From 87e33397918d1148684210c93fe2692feb04e07f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 12:28:05 -0800 Subject: [PATCH 01/63] Fix for normal selection with degenerate triangles. --- interface/src/MetavoxelSystem.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index eeb1c84a4e..ea4941ee33 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1498,6 +1498,17 @@ const NormalIndex& IndexVector::get(int y) const { return (relative >= 0 && relative < size()) ? at(relative) : invalidIndex; } +static inline glm::vec3 getNormal(const QVector& vertices, const NormalIndex& i0, + const NormalIndex& i1, const NormalIndex& i2, const NormalIndex& i3) { + // check both triangles in case one is degenerate + const glm::vec3& v0 = vertices.at(i0.indices[0]).vertex; + glm::vec3 normal = glm::cross(vertices.at(i1.indices[0]).vertex - v0, vertices.at(i2.indices[0]).vertex - v0); + if (glm::length(normal) > EPSILON) { + return normal; + } + return glm::cross(vertices.at(i2.indices[0]).vertex - v0, vertices.at(i3.indices[0]).vertex - v0); +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -2174,10 +2185,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ - 1), indices.size()); quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size()); } - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first, - vertices.at(index3.indices[0]).vertex - first); - + glm::vec3 normal = getNormal(vertices, index, index1, index2, index3); if (alpha0 == 0) { // quad faces negative x indices.append(index3.getClosestIndex(normal = -normal, vertices)); indices.append(index2.getClosestIndex(normal, vertices)); @@ -2206,10 +2214,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (reclampedZ > 0) { quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size()); } - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(vertices.at(index3.indices[0]).vertex - first, - vertices.at(index1.indices[0]).vertex - first); - + glm::vec3 normal = getNormal(vertices, index, index3, index2, index1); if (alpha0 == 0) { // quad faces negative y indices.append(index3.getClosestIndex(normal, vertices)); indices.append(index2.getClosestIndex(normal, vertices)); @@ -2235,10 +2240,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ), indices.size()); - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first, - vertices.at(index3.indices[0]).vertex - first); - + glm::vec3 normal = getNormal(vertices, index, index1, index2, index3); if (alpha0 == 0) { // quad faces negative z indices.append(index1.getClosestIndex(normal, vertices)); indices.append(index2.getClosestIndex(normal, vertices)); From 8636f0c48e80374ea3614789a8a9e3f5c6d951f4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 12:57:24 -0800 Subject: [PATCH 02/63] Simplification. --- interface/src/MetavoxelSystem.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index ea4941ee33..719326f628 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1857,11 +1857,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (!(corners & (1 << i))) { continue; } - int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; - int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; - const quint16* height = heightLineSrc + offsetZ * width + offsetX; - float heightValue = *height * voxelScale; - if (heightValue >= y && heightValue < y + 1) { + const EdgeCrossing& cornerCrossing = cornerCrossings[i]; + if (cornerCrossing.point.y >= y && cornerCrossing.point.y < y + 1) { crossedCorners |= (1 << i); } } @@ -1901,30 +1898,24 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (!(corners & (1 << i))) { continue; } - int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; - int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; - const quint16* height = heightLineSrc + offsetZ * width + offsetX; - float heightValue = *height * voxelScale; int nextIndex = NEXT_CORNERS[i]; if (!(corners & (1 << nextIndex))) { continue; } - int nextOffsetX = (nextIndex & X_MAXIMUM_FLAG) ? 1 : 0; - int nextOffsetZ = (nextIndex & Y_MAXIMUM_FLAG) ? 1 : 0; - const quint16* nextHeight = heightLineSrc + nextOffsetZ * width + nextOffsetX; - float nextHeightValue = *nextHeight * voxelScale; - float divisor = (nextHeightValue - heightValue); + const EdgeCrossing& cornerCrossing = cornerCrossings[i]; + const EdgeCrossing& nextCornerCrossing = cornerCrossings[nextIndex]; + float divisor = (nextCornerCrossing.point.y - cornerCrossing.point.y); if (divisor == 0.0f) { continue; } - float t1 = (y - heightValue) / divisor; - float t2 = (y + 1 - heightValue) / divisor; + float t1 = (y - cornerCrossing.point.y) / divisor; + float t2 = (y + 1 - cornerCrossing.point.y) / divisor; if (t1 >= 0.0f && t1 <= 1.0f) { - crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t1); + crossings[crossingCount++].mix(cornerCrossing, nextCornerCrossing, t1); crossings[crossingCount - 1].point.y -= y; } if (t2 >= 0.0f && t2 <= 1.0f) { - crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t2); + crossings[crossingCount++].mix(cornerCrossing, nextCornerCrossing, t2); crossings[crossingCount - 1].point.y -= y; } } From 8bd944e32e038738a95690e8af63ae630a0680f5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 16:10:00 -0800 Subject: [PATCH 03/63] Incremental improvement to stitching. --- interface/src/MetavoxelSystem.cpp | 49 +++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 719326f628..a0d6a8d72e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1427,6 +1427,8 @@ public: void setColorMaterial(const StackArray::Entry& entry) { color = entry.color; material = entry.material; } void mix(const EdgeCrossing& first, const EdgeCrossing& second, float t); + + VoxelPoint createPoint(int clampedX, int clampedZ, float step) const; }; void EdgeCrossing::mix(const EdgeCrossing& first, const EdgeCrossing& second, float t) { @@ -1437,6 +1439,16 @@ void EdgeCrossing::mix(const EdgeCrossing& first, const EdgeCrossing& second, fl material = (t < 0.5f) ? first.material : second.material; } +VoxelPoint EdgeCrossing::createPoint(int clampedX, int clampedZ, float step) const { + VoxelPoint voxelPoint = { glm::vec3(clampedX + point.x, point.y, clampedZ + point.z) * step, + { (quint8)qRed(color), (quint8)qGreen(color), (quint8)qBlue(color) }, + { (char)(normal.x * numeric_limits::max()), (char)(normal.y * numeric_limits::max()), + (char)(normal.z * numeric_limits::max()) }, + { (quint8)material, 0, 0, 0 }, + { numeric_limits::max(), 0, 0, 0 } }; + return voxelPoint; +} + const int MAX_NORMALS_PER_VERTEX = 4; class NormalIndex { @@ -1509,6 +1521,19 @@ static inline glm::vec3 getNormal(const QVector& vertices, const Nor return glm::cross(vertices.at(i2.indices[0]).vertex - v0, vertices.at(i3.indices[0]).vertex - v0); } +static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1, const EdgeCrossing& e2, + int clampedX, int clampedZ, float step, QVector& vertices, QVector& indices, + QMultiHash& quadIndices) { + int firstIndex = vertices.size(); + vertices.append(e0.createPoint(clampedX, clampedZ, step)); + vertices.append(e1.createPoint(clampedX, clampedZ, step)); + vertices.append(e2.createPoint(clampedX, clampedZ, step)); + indices.append(firstIndex); + indices.append(firstIndex + 1); + indices.append(firstIndex + 2); + indices.append(firstIndex + 2); +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -1865,7 +1890,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g switch (crossedCorners) { case UPPER_LEFT_CORNER: case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: - case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: + case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: case UPPER_LEFT_CORNER | LOWER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[0]; crossings[crossingCount - 1].point.y -= y; @@ -1873,22 +1898,34 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g case UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: - case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[1]; crossings[crossingCount - 1].point.y -= y; break; - + + case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: + crossings[crossingCount++] = cornerCrossings[1]; + crossings[crossingCount - 1].point.y -= y; + appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], + clampedX, clampedZ, step, vertices, indices, quadIndices); + break; + case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: - case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; crossings[crossingCount - 1].point.y -= y; break; - + + case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: + crossings[crossingCount++] = cornerCrossings[2]; + crossings[crossingCount - 1].point.y -= y; + appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], + clampedX, clampedZ, step, vertices, indices, quadIndices); + break; + case LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: - case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: + case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[3]; crossings[crossingCount - 1].point.y -= y; break; From 0d8380a28839d846c5146e9c76f404802d4114c5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 17:47:13 -0800 Subject: [PATCH 04/63] Put the indices for our extra triangles into the spatial hash. --- interface/src/MetavoxelSystem.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a0d6a8d72e..2161887b91 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1532,6 +1532,12 @@ static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1 indices.append(firstIndex + 1); indices.append(firstIndex + 2); indices.append(firstIndex + 2); + + int minimumY = qMin((int)e0.point.y, qMin((int)e1.point.y, (int)e2.point.y)); + int maximumY = qMax((int)e0.point.y, qMax((int)e1.point.y, (int)e2.point.y)); + for (int y = minimumY; y <= maximumY; y++) { + quadIndices.insert(qRgb(clampedX, y, clampedZ), firstIndex); + } } void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, @@ -1895,7 +1901,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g crossings[crossingCount++] = cornerCrossings[0]; crossings[crossingCount - 1].point.y -= y; break; - + case UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: @@ -1909,7 +1915,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], clampedX, clampedZ, step, vertices, indices, quadIndices); break; - + case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; @@ -1922,7 +1928,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], clampedX, clampedZ, step, vertices, indices, quadIndices); break; - + case LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: From 45a84895e10a0ef649ddcdaed5297356a2e93b96 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 22 Jan 2015 12:44:07 -0800 Subject: [PATCH 05/63] Paddle ball game, first version --- examples/controllers/hydra/paddleBall.js | 164 +++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 examples/controllers/hydra/paddleBall.js diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js new file mode 100644 index 0000000000..e5d409bd8a --- /dev/null +++ b/examples/controllers/hydra/paddleBall.js @@ -0,0 +1,164 @@ +// PaddleBall.js +// +// Created by Philip Rosedale on January 21, 2015 +// Copyright 2014 High Fidelity, Inc. +// +// Move your hand with the hydra controller, and hit the ball with the paddle. +// Click 'X' button to turn off this script. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var BALL_SIZE = 0.08; +var PADDLE_SIZE = 0.20; +var PADDLE_THICKNESS = 0.06; +var PADDLE_COLOR = { red: 184, green: 134, blue: 11 }; +var BALL_COLOR = { red: 255, green: 0, blue: 0 }; +var LINE_COLOR = { red: 255, green: 255, blue: 0 }; +var PADDLE_OFFSET = { x: 0.05, y: 0.0, z: 0.0 }; +var GRAVITY = 0.0; +var SPRING_FORCE = 15.0; +var lastSoundTime = 0; +var controllerID = 1; +var gameOn = false; + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav"); + +var screenSize = Controller.getViewportDimensions(); +var offButton = Overlays.addOverlay("image", { + x: screenSize.x - 48, + y: 96, + width: 32, + height: 32, + imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + +var ball, paddle, paddleModel, line; + +function createEntities() { + ball = Entities.addEntity( + { type: "Sphere", + position: Controller.getSpatialControlPosition(controllerID), + dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE }, + color: BALL_COLOR, + gravity: { x: 0, y: GRAVITY, z: 0 }, + ignoreCollisions: false, + damping: 0.50, + collisionsWillMove: true }); + + paddle = Entities.addEntity( + { type: "Box", + position: Controller.getSpatialControlPosition(controllerID), + dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 }, + color: PADDLE_COLOR, + gravity: { x: 0, y: 0, z: 0 }, + ignoreCollisions: false, + damping: 0.10, + visible: false, + rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), + collisionsWillMove: false }); + + modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx"; + paddleModel = Entities.addEntity( + { type: "Model", + position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_OFFSET), + dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 }, + color: PADDLE_COLOR, + gravity: { x: 0, y: 0, z: 0 }, + ignoreCollisions: true, + modelURL: modelURL, + damping: 0.10, + rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), + collisionsWillMove: false }); + + line = Overlays.addOverlay("line3d", { + start: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: LINE_COLOR, + alpha: 1, + visible: true, + lineWidth: 2 }); +} + +function deleteEntities() { + Entities.deleteEntity(ball); + Entities.deleteEntity(paddle); + Entities.deleteEntity(paddleModel); + Overlays.deleteOverlay(line); +} + +function update(deltaTime) { + var palmPosition = Controller.getSpatialControlPosition(controllerID); + var controllerActive = (Vec3.length(palmPosition) > 0); + + if (!gameOn && controllerActive) { + createEntities(); + gameOn = true; + } else if (gameOn && !controllerActive) { + deleteEntities(); + gameOn = false; + } + if (!gameOn || !controllerActive) { + return; + } + + if (!paddle.isKnownID) { + paddle = Entities.identifyEntity(paddle); + } + if (!ball.isKnownID) { + ball = Entities.identifyEntity(ball); + } else { + var props = Entities.getEntityProperties(ball); + var spring = Vec3.subtract(palmPosition, props.position); + var paddleWorldOrientation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)); + var springLength = Vec3.length(spring); + spring = Vec3.normalize(spring); + var ballVelocity = Vec3.sum(props.velocity, Vec3.multiply(springLength * SPRING_FORCE * deltaTime, spring)); + Entities.editEntity(ball, { velocity: ballVelocity }); + Overlays.editOverlay(line, { start: props.position, end: palmPosition }); + Entities.editEntity(paddle, { position: palmPosition, + velocity: Controller.getSpatialControlVelocity(controllerID), + rotation: paddleWorldOrientation }); + Entities.editEntity(paddleModel, { position: Vec3.sum(palmPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_OFFSET)), + velocity: Controller.getSpatialControlVelocity(controllerID), + rotation: paddleWorldOrientation }); + } +} + +function entityCollisionWithEntity(entity1, entity2, collision) { + if ((entity1.id == ball.id) || (entity2.id ==ball.id)) { + var props1 = Entities.getEntityProperties(entity1); + var props2 = Entities.getEntityProperties(entity2); + var dVel = Vec3.length(Vec3.subtract(props1.velocity, props2.velocity)); + var currentTime = new Date().getTime(); + var MIN_MSECS_BETWEEN_BOUNCE_SOUNDS = 100; + var MIN_VELOCITY_FOR_SOUND_IMPACT = 0.25; + if ((dVel > MIN_VELOCITY_FOR_SOUND_IMPACT) && (currentTime - lastSoundTime) > MIN_MSECS_BETWEEN_BOUNCE_SOUNDS) { + Audio.playSound(hitSound, { position: props1.position, volume: Math.min(dVel, 1.0) }); + lastSoundTime = new Date().getTime(); + } + } +} + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + if (clickedOverlay == offButton) { + Script.stop(); + } +} + +function scriptEnding() { + if (gameOn) { + deleteEntities(); + } + Overlays.deleteOverlay(offButton); +} + +Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); +Controller.mousePressEvent.connect(mousePressEvent); +Script.scriptEnding.connect(scriptEnding); +Script.update.connect(update); From 59f79fd4368bba983f120d076d63ab4baadede8a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 22 Jan 2015 13:42:19 -0800 Subject: [PATCH 06/63] Add handedness choice, default to right handed --- examples/controllers/hydra/paddleBall.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js index e5d409bd8a..85b025e4cd 100644 --- a/examples/controllers/hydra/paddleBall.js +++ b/examples/controllers/hydra/paddleBall.js @@ -20,8 +20,16 @@ var PADDLE_OFFSET = { x: 0.05, y: 0.0, z: 0.0 }; var GRAVITY = 0.0; var SPRING_FORCE = 15.0; var lastSoundTime = 0; -var controllerID = 1; var gameOn = false; +var leftHanded = false; +var controllerID; + +if (leftHanded) { + controllerID = 1; +} else { + controllerID = 3; +} + HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav"); From 805d5ace13cf8d5411689776071b734edc8be27a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 14:55:14 -0800 Subject: [PATCH 07/63] Another slight stitching improvement. --- interface/src/MetavoxelSystem.cpp | 87 ++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 2161887b91..e91ff89270 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1540,6 +1540,50 @@ static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1 } } +const int CORNER_COUNT = 4; + +static inline StackArray::Entry getEntry(const StackArray* lineSrc, int stackWidth, int y, float heightfieldHeight, + EdgeCrossing cornerCrossings[CORNER_COUNT], int cornerIndex) { + const EdgeCrossing& cornerCrossing = cornerCrossings[cornerIndex]; + if (cornerCrossing.point.y == 0.0f) { + int offsetX = (cornerIndex & X_MAXIMUM_FLAG) ? 1 : 0; + int offsetZ = (cornerIndex & Y_MAXIMUM_FLAG) ? 1 : 0; + return lineSrc[offsetZ * stackWidth + offsetX].getEntry(y, heightfieldHeight); + } + StackArray::Entry entry; + bool set = false; + if (cornerCrossing.point.y >= y) { + entry.color = cornerCrossing.color; + entry.material = cornerCrossing.material; + set = true; + + if (cornerCrossing.point.y < y + 1) { + entry.setHermiteY(cornerCrossing.normal, cornerCrossing.point.y - y); + } + } else { + entry.material = entry.color = 0; + } + if (!(cornerIndex & X_MAXIMUM_FLAG)) { + const EdgeCrossing& nextCornerCrossingX = cornerCrossings[cornerIndex | X_MAXIMUM_FLAG]; + if (nextCornerCrossingX.point.y != 0.0f && (nextCornerCrossingX.point.y >= y) != set) { + float t = (y - cornerCrossing.point.y) / (nextCornerCrossingX.point.y - cornerCrossing.point.y); + if (t >= 0.0f && t <= 1.0f) { + entry.setHermiteX(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingX.normal, t)), t); + } + } + } + if (!(cornerIndex & Y_MAXIMUM_FLAG)) { + const EdgeCrossing& nextCornerCrossingZ = cornerCrossings[cornerIndex | Y_MAXIMUM_FLAG]; + if (nextCornerCrossingZ.point.y != 0.0f && (nextCornerCrossingZ.point.y >= y) != set) { + float t = (y - cornerCrossing.point.y) / (nextCornerCrossingZ.point.y - cornerCrossing.point.y); + if (t >= 0.0f && t <= 1.0f) { + entry.setHermiteZ(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingZ.normal, t)), t); + } + } + } + return entry; +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -1748,7 +1792,6 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g const int LOWER_RIGHT_CORNER = 8; const int NO_CORNERS = 0; const int ALL_CORNERS = UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER | LOWER_RIGHT_CORNER; - const int CORNER_COUNT = 4; const int NEXT_CORNERS[] = { 1, 3, 0, 2 }; int corners = NO_CORNERS; if (heightfieldHeight != 0.0f) { @@ -1823,7 +1866,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g indicesZ[x].position = position; indicesZ[x].resize(count); for (int y = position, end = position + count; y < end; y++) { - const StackArray::Entry& entry = lineSrc->getEntry(y, heightfieldHeight); + StackArray::Entry entry = getEntry(lineSrc, stackWidth, y, heightfieldHeight, cornerCrossings, 0); if (displayHermite && x != 0 && z != 0 && !lineSrc->isEmpty() && y >= lineSrc->getPosition()) { glm::vec3 normal; if (entry.hermiteX != 0) { @@ -1969,10 +2012,13 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g // the terrifying conditional code that follows checks each cube edge for a crossing, gathering // its properties (color, material, normal) if one is present; as before, boundary edges are excluded if (crossingCount == 0) { - const StackArray::Entry& nextEntryY = lineSrc->getEntry(y + 1, heightfieldHeight); + StackArray::Entry nextEntryY = getEntry(lineSrc, stackWidth, y + 1, + heightfieldHeight, cornerCrossings, 0); if (middleX) { - const StackArray::Entry& nextEntryX = lineSrc[1].getEntry(y, nextHeightfieldHeightX); - const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, nextHeightfieldHeightX); + StackArray::Entry nextEntryX = getEntry(lineSrc, stackWidth, y, nextHeightfieldHeightX, + cornerCrossings, 1); + StackArray::Entry nextEntryXY = getEntry(lineSrc, stackWidth, y + 1, nextHeightfieldHeightX, + cornerCrossings, 1); if (alpha0 != alpha1) { EdgeCrossing& crossing = crossings[crossingCount++]; crossing.point = glm::vec3(entry.getHermiteX(crossing.normal), 0.0f, 0.0f); @@ -1989,12 +2035,12 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g crossing.setColorMaterial(alpha2 == 0 ? nextEntryXY : nextEntryY); } if (middleZ) { - const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, - nextHeightfieldHeightZ); - const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( - y, nextHeightfieldHeightXZ); - const StackArray::Entry& nextEntryXYZ = lineSrc[stackWidth + 1].getEntry( - y + 1, nextHeightfieldHeightXZ); + StackArray::Entry nextEntryZ = getEntry(lineSrc, stackWidth, y, nextHeightfieldHeightZ, + cornerCrossings, 2); + StackArray::Entry nextEntryXZ = getEntry(lineSrc, stackWidth, y, nextHeightfieldHeightXZ, + cornerCrossings, 3); + StackArray::Entry nextEntryXYZ = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightXZ, cornerCrossings, 3); if (alpha1 != alpha5) { EdgeCrossing& crossing = crossings[crossingCount++]; crossing.point = glm::vec3(1.0f, 0.0f, nextEntryX.getHermiteZ(crossing.normal)); @@ -2002,8 +2048,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } if (alpha3 != alpha7) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, - nextHeightfieldHeightX); + StackArray::Entry nextEntryXY = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightX, cornerCrossings, 1); crossing.point = glm::vec3(1.0f, 1.0f, nextEntryXY.getHermiteZ(crossing.normal)); crossing.setColorMaterial(alpha3 == 0 ? nextEntryXYZ : nextEntryXY); } @@ -2014,15 +2060,15 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } if (alpha5 != alpha7) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( - y, nextHeightfieldHeightXZ); + StackArray::Entry nextEntryXZ = getEntry(lineSrc, stackWidth, y, + nextHeightfieldHeightXZ, cornerCrossings, 3); crossing.point = glm::vec3(1.0f, nextEntryXZ.getHermiteY(crossing.normal), 1.0f); crossing.setColorMaterial(alpha5 == 0 ? nextEntryXYZ : nextEntryXZ); } if (alpha6 != alpha7) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry( - y + 1, nextHeightfieldHeightZ); + StackArray::Entry nextEntryYZ = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightZ, cornerCrossings, 2); crossing.point = glm::vec3(nextEntryYZ.getHermiteX(crossing.normal), 1.0f, 1.0f); crossing.setColorMaterial(alpha6 == 0 ? nextEntryXYZ : nextEntryYZ); } @@ -2034,9 +2080,10 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g crossing.setColorMaterial(alpha0 == 0 ? nextEntryY : entry); } if (middleZ) { - const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, nextHeightfieldHeightZ); - const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry(y + 1, - nextHeightfieldHeightZ); + StackArray::Entry nextEntryZ = getEntry(lineSrc, stackWidth, y, + nextHeightfieldHeightZ, cornerCrossings, 2); + StackArray::Entry nextEntryYZ = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightZ, cornerCrossings, 2); if (alpha0 != alpha4) { EdgeCrossing& crossing = crossings[crossingCount++]; crossing.point = glm::vec3(0.0f, 0.0f, entry.getHermiteZ(crossing.normal)); From 0e6f2d7252f8943897ae1032457a9a45b27494a8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 22 Jan 2015 16:22:36 -0800 Subject: [PATCH 08/63] Update runningScriptsWidgets px -> pt --- interface/ui/runningScriptsWidget.ui | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index 3d7db5064a..ec078681e3 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -70,7 +70,7 @@ Helvetica,Arial,sans-serif - -1 + 16 75 false true @@ -78,7 +78,7 @@ color: #0e7077; -font: bold 16px; +font: bold 16pt; @@ -192,7 +192,7 @@ font: bold 16px; - font: 14px; color: #5f5f5f; margin: 2px; + font: 14pt; color: #5f5f5f; margin: 2px; There are no scripts running. @@ -245,8 +245,8 @@ font: bold 16px; 0 0 - 334 - 20 + 328 + 18 @@ -259,7 +259,7 @@ font: bold 16px; Qt::LeftToRight - font-size: 14px; + font-size: 14pt; @@ -301,7 +301,7 @@ font: bold 16px; - font: 14px; color: #5f5f5f; margin: 2px; + font: 14pt; color: #5f5f5f; margin: 2px; Tip @@ -370,7 +370,7 @@ font: bold 16px; color: #0e7077; -font: bold 16px; +font: bold 16pt; Load Scripts From e65090bab917d781637b2fad748914d759288928 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 21:08:48 -0800 Subject: [PATCH 09/63] Another slight stitching improvement. --- interface/src/MetavoxelSystem.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index e91ff89270..7edabb0beb 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1857,6 +1857,15 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } minimumY = qMin(minimumY, cornerMinimumY); maximumY = qMax(maximumY, cornerMaximumY); + + if (corners == (LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER)) { + appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], + clampedX, clampedZ, step, vertices, indices, quadIndices); + + } else if (corners == (UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER)) { + appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], + clampedX, clampedZ, step, vertices, indices, quadIndices); + } } int position = minimumY; int count = maximumY - minimumY + 1; @@ -1948,28 +1957,16 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g case UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: - crossings[crossingCount++] = cornerCrossings[1]; - crossings[crossingCount - 1].point.y -= y; - break; - case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[1]; crossings[crossingCount - 1].point.y -= y; - appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], - clampedX, clampedZ, step, vertices, indices, quadIndices); break; case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: - crossings[crossingCount++] = cornerCrossings[2]; - crossings[crossingCount - 1].point.y -= y; - break; - case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; crossings[crossingCount - 1].point.y -= y; - appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], - clampedX, clampedZ, step, vertices, indices, quadIndices); break; case LOWER_RIGHT_CORNER: From c124dffd6ab1f3f3988decc684c1457ab3974dbb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 21:26:08 -0800 Subject: [PATCH 10/63] Another slight improvement. --- interface/src/MetavoxelSystem.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7edabb0beb..1d2caa6c2c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1556,29 +1556,25 @@ static inline StackArray::Entry getEntry(const StackArray* lineSrc, int stackWid entry.color = cornerCrossing.color; entry.material = cornerCrossing.material; set = true; + entry.setHermiteY(cornerCrossing.normal, glm::clamp(cornerCrossing.point.y - y, 0.0f, 1.0f)); - if (cornerCrossing.point.y < y + 1) { - entry.setHermiteY(cornerCrossing.normal, cornerCrossing.point.y - y); - } } else { entry.material = entry.color = 0; } if (!(cornerIndex & X_MAXIMUM_FLAG)) { const EdgeCrossing& nextCornerCrossingX = cornerCrossings[cornerIndex | X_MAXIMUM_FLAG]; if (nextCornerCrossingX.point.y != 0.0f && (nextCornerCrossingX.point.y >= y) != set) { - float t = (y - cornerCrossing.point.y) / (nextCornerCrossingX.point.y - cornerCrossing.point.y); - if (t >= 0.0f && t <= 1.0f) { - entry.setHermiteX(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingX.normal, t)), t); - } + float t = glm::clamp((y - cornerCrossing.point.y) / + (nextCornerCrossingX.point.y - cornerCrossing.point.y), 0.0f, 1.0f); + entry.setHermiteX(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingX.normal, t)), t); } } if (!(cornerIndex & Y_MAXIMUM_FLAG)) { const EdgeCrossing& nextCornerCrossingZ = cornerCrossings[cornerIndex | Y_MAXIMUM_FLAG]; if (nextCornerCrossingZ.point.y != 0.0f && (nextCornerCrossingZ.point.y >= y) != set) { - float t = (y - cornerCrossing.point.y) / (nextCornerCrossingZ.point.y - cornerCrossing.point.y); - if (t >= 0.0f && t <= 1.0f) { - entry.setHermiteZ(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingZ.normal, t)), t); - } + float t = glm::clamp((y - cornerCrossing.point.y) / + (nextCornerCrossingZ.point.y - cornerCrossing.point.y), 0.0f, 1.0f); + entry.setHermiteZ(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingZ.normal, t)), t); } } return entry; From b8a15f0726c90943f07bbc521ab7c37a1fa0bb24 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 22:04:10 -0800 Subject: [PATCH 11/63] Another tweak. --- interface/src/MetavoxelSystem.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 1d2caa6c2c..80c7c3f41f 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1542,13 +1542,21 @@ static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1 const int CORNER_COUNT = 4; -static inline StackArray::Entry getEntry(const StackArray* lineSrc, int stackWidth, int y, float heightfieldHeight, +static StackArray::Entry getEntry(const StackArray* lineSrc, int stackWidth, int y, float heightfieldHeight, EdgeCrossing cornerCrossings[CORNER_COUNT], int cornerIndex) { + int offsetX = (cornerIndex & X_MAXIMUM_FLAG) ? 1 : 0; + int offsetZ = (cornerIndex & Y_MAXIMUM_FLAG) ? 1 : 0; + const StackArray& src = lineSrc[offsetZ * stackWidth + offsetX]; + int count = src.getEntryCount(); + if (count > 0) { + int relative = y - src.getPosition(); + if (relative < count && (relative >= 0 || heightfieldHeight == 0.0f)) { + return src.getEntry(y, heightfieldHeight); + } + } const EdgeCrossing& cornerCrossing = cornerCrossings[cornerIndex]; if (cornerCrossing.point.y == 0.0f) { - int offsetX = (cornerIndex & X_MAXIMUM_FLAG) ? 1 : 0; - int offsetZ = (cornerIndex & Y_MAXIMUM_FLAG) ? 1 : 0; - return lineSrc[offsetZ * stackWidth + offsetX].getEntry(y, heightfieldHeight); + return src.getEntry(y, heightfieldHeight); } StackArray::Entry entry; bool set = false; From 31f72107daf7000ab2f54bb214e7e0288bdc7633 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 23 Jan 2015 09:26:48 -0800 Subject: [PATCH 12/63] remove support for old pre-entity svo files --- libraries/entities/src/EntityTree.h | 3 +- libraries/entities/src/ModelEntityItem.cpp | 127 --------------------- libraries/entities/src/ModelEntityItem.h | 3 - 3 files changed, 2 insertions(+), 131 deletions(-) diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index e8c8a93165..405cbecd99 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -60,7 +60,8 @@ public: // own definition. Implement these to allow your octree based server to support editing virtual bool getWantSVOfileVersions() const { return true; } virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; } - virtual bool canProcessVersion(PacketVersion thisVersion) const { return true; } // we support all versions + virtual bool canProcessVersion(PacketVersion thisVersion) const + { return thisVersion >= VERSION_ENTITIES_SUPPORT_SPLIT_MTU; } // we support all versions with split mtu virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 4cdec0f29a..2c3dcd0600 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -81,17 +81,6 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { return somethingChanged; } - - -int ModelEntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { - return oldVersionReadEntityDataFromBuffer(data, bytesLeftToRead, args); - } - - // let our base class do most of the work... it will call us back for our porition... - return EntityItem::readEntityDataFromBuffer(data, bytesLeftToRead, args); -} - int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { @@ -131,122 +120,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - - int bytesRead = 0; - if (bytesLeftToRead >= expectedBytes()) { - int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0; - - const unsigned char* dataAt = data; - - // id - // this old bitstream format had 32bit IDs. They are obsolete and need to be replaced with our new UUID - // format. We can simply read and ignore the old ID since they should not be repeated. This code should only - // run on loading from an old file. - quint32 oldID; - memcpy(&oldID, dataAt, sizeof(oldID)); - dataAt += sizeof(oldID); - bytesRead += sizeof(oldID); - _id = QUuid::createUuid(); - - // _lastUpdated - memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated)); - dataAt += sizeof(_lastUpdated); - bytesRead += sizeof(_lastUpdated); - _lastUpdated -= clockSkew; - - // _lastEdited - memcpy(&_lastEdited, dataAt, sizeof(_lastEdited)); - dataAt += sizeof(_lastEdited); - bytesRead += sizeof(_lastEdited); - _lastEdited -= clockSkew; - _created = _lastEdited; // NOTE: old models didn't have age or created time, assume their last edit was a create - - QString ageAsString = formatSecondsElapsed(getAge()); - qDebug() << "Loading old model file, _created = _lastEdited =" << _created - << " age=" << getAge() << "seconds - " << ageAsString - << "old ID=" << oldID << "new ID=" << _id; - - // radius - float radius; - memcpy(&radius, dataAt, sizeof(radius)); - dataAt += sizeof(radius); - bytesRead += sizeof(radius); - setRadius(radius); - - // position - memcpy(&_position, dataAt, sizeof(_position)); - dataAt += sizeof(_position); - bytesRead += sizeof(_position); - - // color - memcpy(&_color, dataAt, sizeof(_color)); - dataAt += sizeof(_color); - bytesRead += sizeof(_color); - - // TODO: how to handle this? Presumable, this would only ever be true if the model file was saved with - // a model being in a shouldBeDeleted state. Which seems unlikely. But if it happens, maybe we should delete the entity after loading? - // shouldBeDeleted - bool shouldBeDeleted = false; - memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted)); - dataAt += sizeof(shouldBeDeleted); - bytesRead += sizeof(shouldBeDeleted); - if (shouldBeDeleted) { - qDebug() << "UNEXPECTED - read shouldBeDeleted=TRUE from an old format file"; - } - - // modelURL - uint16_t modelURLLength; - memcpy(&modelURLLength, dataAt, sizeof(modelURLLength)); - dataAt += sizeof(modelURLLength); - bytesRead += sizeof(modelURLLength); - QString modelURLString((const char*)dataAt); - setModelURL(modelURLString); - dataAt += modelURLLength; - bytesRead += modelURLLength; - - // rotation - int bytes = unpackOrientationQuatFromBytes(dataAt, _rotation); - dataAt += bytes; - bytesRead += bytes; - - if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ANIMATION) { - // animationURL - uint16_t animationURLLength; - memcpy(&animationURLLength, dataAt, sizeof(animationURLLength)); - dataAt += sizeof(animationURLLength); - bytesRead += sizeof(animationURLLength); - QString animationURLString((const char*)dataAt); - setAnimationURL(animationURLString); - dataAt += animationURLLength; - bytesRead += animationURLLength; - - // animationIsPlaying - bool animationIsPlaying; - memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying)); - dataAt += sizeof(animationIsPlaying); - bytesRead += sizeof(animationIsPlaying); - setAnimationIsPlaying(animationIsPlaying); - - // animationFrameIndex - float animationFrameIndex; - memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex)); - dataAt += sizeof(animationFrameIndex); - bytesRead += sizeof(animationFrameIndex); - setAnimationFrameIndex(animationFrameIndex); - - // animationFPS - float animationFPS; - memcpy(&animationFPS, dataAt, sizeof(animationFPS)); - dataAt += sizeof(animationFPS); - bytesRead += sizeof(animationFPS); - setAnimationFPS(animationFPS); - } - } - return bytesRead; -} - - // TODO: eventually only include properties changed since the params.lastViewFrustumSent time EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index dc236644b7..a607745475 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -40,7 +40,6 @@ public: OctreeElement::AppendState& appendState) const; - virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); @@ -116,8 +115,6 @@ public: protected: - /// For reading models from pre V3 bitstreams - int oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); bool isAnimatingSomething() const; rgbColor _color; From d173afaa70dc2bc68cdad9d6b7cfefb4c21afa81 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Jan 2015 11:01:46 -0800 Subject: [PATCH 13/63] add support for non-physical kinematic movement --- libraries/entities/src/EntityItem.cpp | 23 +++- libraries/physics/src/EntityMotionState.cpp | 41 ++++--- libraries/physics/src/EntityMotionState.h | 5 +- libraries/physics/src/ObjectMotionState.cpp | 26 +++-- libraries/physics/src/ObjectMotionState.h | 14 ++- libraries/physics/src/PhysicsEngine.cpp | 119 +++++++++++++++++--- libraries/physics/src/PhysicsEngine.h | 9 +- 7 files changed, 176 insertions(+), 61 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7e3e982fb8..c830236287 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -520,7 +520,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); recalculateCollisionShape(); - if (overwriteLocalData && (getDirtyFlags() & EntityItem::DIRTY_POSITION)) { + if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { _lastSimulated = now; } } @@ -770,6 +770,9 @@ void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) { float angularSpeed = glm::length(_angularVelocity); const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; // if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { + if (angularSpeed > 0.0f) { + _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + } setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); } else { // NOTE: angularSpeed is currently in degrees/sec!!! @@ -799,10 +802,18 @@ void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) { // "ground" plane of the domain, but for now it's what we've got velocity += getGravity() * timeElapsed; } - - // NOTE: the simulation should NOT set any DirtyFlags on this entity - setPosition(position); // this will automatically recalculate our collision shape - setVelocity(velocity); + + float speed = glm::length(velocity); + const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec + if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { + setVelocity(ENTITY_ITEM_ZERO_VEC3); + if (speed > 0.0f) { + _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + } + } else { + setPosition(position); // this will automatically recalculate our collision shape + setVelocity(velocity); + } } } @@ -886,7 +897,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { if (_created != UNKNOWN_CREATED_TIME) { setLastEdited(now); } - if (getDirtyFlags() & EntityItem::DIRTY_POSITION) { + if (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { _lastSimulated = now; } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8b6fb1ea9f..b4aa9d0e7e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -14,7 +14,7 @@ #include "BulletUtil.h" #include "EntityMotionState.h" -#include "SimpleEntityKinematicController.h" +#include "PhysicsEngine.h" QSet* _outgoingEntityList; @@ -41,8 +41,6 @@ EntityMotionState::~EntityMotionState() { assert(_entity); _entity->setPhysicsInfo(NULL); _entity = NULL; - delete _kinematicController; - _kinematicController = NULL; } MotionType EntityMotionState::computeMotionType() const { @@ -52,13 +50,15 @@ MotionType EntityMotionState::computeMotionType() const { return _entity->isMoving() ? MOTION_TYPE_KINEMATIC : MOTION_TYPE_STATIC; } -void EntityMotionState::addKinematicController() { - if (!_kinematicController) { - _kinematicController = new SimpleEntityKinematicController(_entity); - _kinematicController->start(); - } else { - _kinematicController->start(); - } +void EntityMotionState::updateKinematicState(uint32_t substep) { + setKinematic(_entity->isMoving(), substep); +} + +void EntityMotionState::stepKinematicSimulation(uint32_t substep) { + assert(_isKinematic); + float dt = (substep - _lastKinematicSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; + _entity->simulateSimpleKinematicMotion(dt); + _lastKinematicSubstep = substep; } // This callback is invoked by the physics simulation in two cases: @@ -67,8 +67,11 @@ void EntityMotionState::addKinematicController() { // (2) at the beginning of each simulation frame for KINEMATIC RigidBody's -- // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { - if (_kinematicController && _kinematicController->isRunning()) { - _kinematicController->stepForward(); + if (_isKinematic) { + uint32_t substep = PhysicsEngine::getNumSubsteps(); + // remove const-ness so we can actually update this instance + EntityMotionState* thisMotion = const_cast(this); + thisMotion->stepKinematicSimulation(substep); } worldTrans.setOrigin(glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset())); worldTrans.setRotation(glmToBullet(_entity->getRotation())); @@ -229,12 +232,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ uint32_t EntityMotionState::getIncomingDirtyFlags() const { uint32_t dirtyFlags = _entity->getDirtyFlags(); - // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings - int bodyFlags = _body->getCollisionFlags(); - bool isMoving = _entity->isMoving(); - if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) || - (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) { - dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + if (_body) { + // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings + int bodyFlags = _body->getCollisionFlags(); + bool isMoving = _entity->isMoving(); + if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) || + (bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) { + dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + } } return dirtyFlags; } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 8eb639688a..192ac166b4 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -14,7 +14,6 @@ #include -#include "KinematicController.h" #include "ObjectMotionState.h" class EntityItem; @@ -39,8 +38,8 @@ public: /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem MotionType computeMotionType() const; - // virtual override for ObjectMotionState - void addKinematicController(); + void updateKinematicState(uint32_t substep); + void stepKinematicSimulation(uint32_t substep); // this relays incoming position/rotation to the RigidBody void getWorldTransform(btTransform& worldTrans) const; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index cab36b8370..dfa059d47f 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -12,7 +12,6 @@ #include #include "BulletUtil.h" -#include "KinematicController.h" #include "ObjectMotionState.h" #include "PhysicsEngine.h" @@ -56,10 +55,6 @@ ObjectMotionState::ObjectMotionState() : ObjectMotionState::~ObjectMotionState() { // NOTE: you MUST remove this MotionState from the world before you call the dtor. assert(_body == NULL); - if (_kinematicController) { - delete _kinematicController; - _kinematicController = NULL; - } } void ObjectMotionState::setFriction(float friction) { @@ -108,6 +103,15 @@ bool ObjectMotionState::doesNotNeedToSendUpdate() const { bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { assert(_body); + // if we've never checked before, our _sentFrame will be 0, and we need to initialize our state + if (_sentFrame == 0) { + _sentPosition = bulletToGLM(_body->getWorldTransform().getOrigin()); + _sentVelocity = bulletToGLM(_body->getLinearVelocity()); + _sentAngularVelocity = bulletToGLM(_body->getAngularVelocity()); + _sentFrame = simulationFrame; + return false; + } + float dt = (float)(simulationFrame - _sentFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP; _sentFrame = simulationFrame; bool isActive = _body->isActive(); @@ -164,13 +168,6 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT); } -void ObjectMotionState::removeKinematicController() { - if (_kinematicController) { - delete _kinematicController; - _kinematicController = NULL; - } -} - void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { @@ -183,3 +180,8 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } } + +void ObjectMotionState::setKinematic(bool kinematic, uint32_t substep) { + _isKinematic = kinematic; + _lastKinematicSubstep = substep; +} diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 223664ceec..424a7fb680 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -46,7 +46,6 @@ const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_POSITION | Entit class OctreeEditPacketSender; -class KinematicController; class ObjectMotionState : public btMotionState { public: @@ -93,11 +92,15 @@ public: virtual MotionType computeMotionType() const = 0; - virtual void addKinematicController() = 0; - virtual void removeKinematicController(); + virtual void updateKinematicState(uint32_t substep) = 0; btRigidBody* getRigidBody() const { return _body; } + bool isKinematic() const { return _isKinematic; } + + void setKinematic(bool kinematic, uint32_t substep); + virtual void stepKinematicSimulation(uint32_t substep) = 0; + friend class PhysicsEngine; protected: void setRigidBody(btRigidBody* body); @@ -114,6 +117,9 @@ protected: btRigidBody* _body; + bool _isKinematic = false; + uint32_t _lastKinematicSubstep = 0; + bool _sentMoving; // true if last update was moving int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects @@ -124,8 +130,6 @@ protected: glm::vec3 _sentVelocity; glm::vec3 _sentAngularVelocity; // radians per second glm::vec3 _sentAcceleration; - - KinematicController* _kinematicController = NULL; }; #endif // hifi_ObjectMotionState_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 02304b3b8d..dbeea165c4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -62,7 +62,13 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) { entity->setPhysicsInfo(static_cast(motionState)); _entityMotionStates.insert(motionState); addObject(shapeInfo, shape, motionState); - } else { + } else if (entity->isMoving()) { + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast(motionState)); + _entityMotionStates.insert(motionState); + + motionState->setKinematic(true, _numSubsteps); + _nonPhysicalKinematicObjects.insert(motionState); // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; } @@ -74,10 +80,16 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { EntityMotionState* motionState = static_cast(physicsInfo); - removeObject(motionState); + if (motionState->getRigidBody()) { + removeObject(motionState); + } else { + // only need to hunt in this list when there is no RigidBody + _nonPhysicalKinematicObjects.remove(motionState); + } _entityMotionStates.remove(motionState); _incomingChanges.remove(motionState); _outgoingPackets.remove(motionState); + // NOTE: EntityMotionState dtor will remove its backpointer from EntityItem delete motionState; } } @@ -117,6 +129,7 @@ void PhysicsEngine::clearEntitiesInternal() { delete (*stateItr); } _entityMotionStates.clear(); + _nonPhysicalKinematicObjects.clear(); _incomingChanges.clear(); _outgoingPackets.clear(); } @@ -127,19 +140,75 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { QSet::iterator stateItr = _incomingChanges.begin(); while (stateItr != _incomingChanges.end()) { ObjectMotionState* motionState = *stateItr; + ++stateItr; uint32_t flags = motionState->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS; + bool removeMotionState = false; btRigidBody* body = motionState->getRigidBody(); if (body) { if (flags & HARD_DIRTY_PHYSICS_FLAGS) { // a HARD update requires the body be pulled out of physics engine, changed, then reinserted // but it also handles all EASY changes - updateObjectHard(body, motionState, flags); + bool success = updateObjectHard(body, motionState, flags); + if (!success) { + // NOTE: since updateObjectHard() failed we know that motionState has been removed + // from simulation and body has been deleted. Depending on what else has changed + // we might need to remove motionState altogether... + if (flags & EntityItem::DIRTY_VELOCITY) { + motionState->updateKinematicState(_numSubsteps); + if (motionState->isKinematic()) { + // all is NOT lost, we still need to move this object around kinematically + _nonPhysicalKinematicObjects.insert(motionState); + } else { + // no need to keep motionState around + removeMotionState = true; + } + } else { + // no need to keep motionState around + removeMotionState = true; + } + } } else if (flags) { // an EASY update does NOT require that the body be pulled out of physics engine // hence the MotionState has all the knowledge and authority to perform the update. motionState->updateObjectEasy(flags, _numSubsteps); } + } else { + // the only way we should ever get here (motionState exists but no body) is when the object + // is undergoing non-physical kinematic motion. + assert(_nonPhysicalKinematicObjects.contains(motionState)); + + // it is possible that the changes are such that the object can now be added to the physical simulation + if (flags & EntityItem::DIRTY_SHAPE) { + ShapeInfo shapeInfo; + motionState->computeShapeInfo(shapeInfo); + btCollisionShape* shape = _shapeManager.getShape(shapeInfo); + if (shape) { + addObject(shapeInfo, shape, motionState); + _nonPhysicalKinematicObjects.remove(motionState); + } else if (flags & EntityItem::DIRTY_VELOCITY) { + // although we couldn't add the object to the simulation, might need to update kinematic motion... + motionState->updateKinematicState(_numSubsteps); + if (!motionState->isKinematic()) { + _nonPhysicalKinematicObjects.remove(motionState); + removeMotionState = true; + } + } + } else if (flags & EntityItem::DIRTY_VELOCITY) { + // although we still can't add to physics simulation, might need to update kinematic motion... + motionState->updateKinematicState(_numSubsteps); + if (!motionState->isKinematic()) { + _nonPhysicalKinematicObjects.remove(motionState); + removeMotionState = true; + } + } + } + if (removeMotionState) { + // if we get here then there is no need to keep this motionState around (no physics or kinematics) + _outgoingPackets.remove(motionState); + // NOTE: motionState will clean up its own backpointers in the Object + delete motionState; + continue; } // NOTE: the grand order of operations is: @@ -152,7 +221,6 @@ void PhysicsEngine::relayIncomingChangesToSimulation() { // outgoing changes at this point. motionState->clearOutgoingPacketFlags(flags); // clear outgoing flags that were trumped motionState->clearIncomingDirtyFlags(flags); // clear incoming flags that were processed - ++stateItr; } _incomingChanges.clear(); } @@ -229,6 +297,7 @@ void PhysicsEngine::stepSimulation() { // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; + stepNonPhysicalKinematics(); unlock(); // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. @@ -248,6 +317,18 @@ void PhysicsEngine::stepSimulation() { computeCollisionEvents(); } +// TODO: need to update non-physical kinematic objects +void PhysicsEngine::stepNonPhysicalKinematics() { + QSet::iterator stateItr = _nonPhysicalKinematicObjects.begin(); + while (stateItr != _nonPhysicalKinematicObjects.end()) { + ObjectMotionState* motionState = *stateItr; + motionState->stepKinematicSimulation(_numSubsteps); + ++stateItr; + } +} + +// TODO?: need to occasionally scan for stopped non-physical kinematics objects + void PhysicsEngine::computeCollisionEvents() { // update all contacts int numManifolds = _collisionDispatcher->getNumManifolds(); @@ -322,7 +403,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT); body->updateInertiaTensor(); motionState->setRigidBody(body); - motionState->addKinematicController(); + motionState->setKinematic(true, _numSubsteps); const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD); @@ -334,6 +415,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body = new btRigidBody(mass, motionState, shape, inertia); body->updateInertiaTensor(); motionState->setRigidBody(body); + motionState->setKinematic(false, _numSubsteps); motionState->updateObjectVelocities(); // NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds. // (the 2 seconds is determined by: static btRigidBody::gDeactivationTime @@ -348,6 +430,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT); body->updateInertiaTensor(); motionState->setRigidBody(body); + motionState->setKinematic(false, _numSubsteps); break; } } @@ -358,7 +441,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap _dynamicsWorld->addRigidBody(body); } -bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { +void PhysicsEngine::removeObject(ObjectMotionState* motionState) { assert(motionState); btRigidBody* body = motionState->getRigidBody(); if (body) { @@ -369,16 +452,14 @@ bool PhysicsEngine::removeObject(ObjectMotionState* motionState) { _shapeManager.releaseShape(shapeInfo); delete body; motionState->setRigidBody(NULL); - motionState->removeKinematicController(); + motionState->setKinematic(false, _numSubsteps); removeContacts(motionState); - return true; } - return false; } // private -void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { +bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) { MotionType newType = motionState->computeMotionType(); // pull body out of physics engine @@ -393,7 +474,16 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio ShapeInfo shapeInfo; motionState->computeShapeInfo(shapeInfo); btCollisionShape* newShape = _shapeManager.getShape(shapeInfo); - if (newShape != oldShape) { + if (!newShape) { + // FAIL! we are unable to support these changes! + _shapeManager.releaseShape(oldShape); + + delete body; + motionState->setRigidBody(NULL); + motionState->setKinematic(false, _numSubsteps); + removeContacts(motionState); + return false; + } else if (newShape != oldShape) { // BUG: if shape doesn't change but density does then we won't compute new mass properties // TODO: fix this BUG by replacing DIRTY_MASS with DIRTY_DENSITY and then fix logic accordingly. body->setCollisionShape(newShape); @@ -426,7 +516,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio body->setMassProps(0.0f, btVector3(0.0f, 0.0f, 0.0f)); body->updateInertiaTensor(); - motionState->addKinematicController(); + motionState->setKinematic(true, _numSubsteps); break; } case MOTION_TYPE_DYNAMIC: { @@ -443,7 +533,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio body->updateInertiaTensor(); } body->forceActivationState(ACTIVE_TAG); - motionState->removeKinematicController(); + motionState->setKinematic(false, _numSubsteps); break; } default: { @@ -458,7 +548,7 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio body->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f)); body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f)); - motionState->removeKinematicController(); + motionState->setKinematic(false, _numSubsteps); break; } } @@ -467,4 +557,5 @@ void PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio _dynamicsWorld->addRigidBody(body); body->activate(); + return true; } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 73a02607e8..9ae9f88e7e 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -67,6 +67,7 @@ public: virtual void init(EntityEditPacketSender* packetSender); void stepSimulation(); + void stepNonPhysicalKinematics(); void computeCollisionEvents(); @@ -81,15 +82,16 @@ public: void addObject(const ShapeInfo& shapeInfo, btCollisionShape* shape, ObjectMotionState* motionState); /// \param motionState pointer to Object's MotionState - /// \return true if Object removed - bool removeObject(ObjectMotionState* motionState); + void removeObject(ObjectMotionState* motionState); /// process queue of changed from external sources void relayIncomingChangesToSimulation(); private: void removeContacts(ObjectMotionState* motionState); - void updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); + + // return 'true' of update was successful + bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags); btClock _clock; @@ -104,6 +106,7 @@ private: // EntitySimulation stuff QSet _entityMotionStates; // all entities that we track + QSet _nonPhysicalKinematicObjects; // not in physics simulation, but still need kinematic simulation QSet _incomingChanges; // entities with pending physics changes by script or packet QSet _outgoingPackets; // MotionStates with pending changes that need to be sent over wire From eefd32b42b173392150c560b01ece0d57ca6ac6f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Jan 2015 11:04:02 -0800 Subject: [PATCH 14/63] remove KinematicController classes --- libraries/physics/src/KinematicController.cpp | 22 ----------- libraries/physics/src/KinematicController.h | 36 ------------------ .../src/SimpleEntityKinematicController.cpp | 21 ---------- .../src/SimpleEntityKinematicController.h | 38 ------------------- 4 files changed, 117 deletions(-) delete mode 100644 libraries/physics/src/KinematicController.cpp delete mode 100644 libraries/physics/src/KinematicController.h delete mode 100644 libraries/physics/src/SimpleEntityKinematicController.cpp delete mode 100644 libraries/physics/src/SimpleEntityKinematicController.h diff --git a/libraries/physics/src/KinematicController.cpp b/libraries/physics/src/KinematicController.cpp deleted file mode 100644 index 354b285bc1..0000000000 --- a/libraries/physics/src/KinematicController.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// KinematicController.cpp -// libraries/physcis/src -// -// Created by Andrew Meadows 2015.01.13 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "KinematicController.h" -#include "PhysicsEngine.h" - -KinematicController::KinematicController() { - _lastSubstep = PhysicsEngine::getNumSubsteps(); -} - -void KinematicController::start() { - _enabled = true; - _lastSubstep = PhysicsEngine::getNumSubsteps(); -} diff --git a/libraries/physics/src/KinematicController.h b/libraries/physics/src/KinematicController.h deleted file mode 100644 index 60b8548607..0000000000 --- a/libraries/physics/src/KinematicController.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// KinematicController.h -// libraries/physcis/src -// -// Created by Andrew Meadows 2015.01.13 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_KinematicController_h -#define hifi_KinematicController_h - -#include - -/// KinematicController defines an API for derived classes. - -class KinematicController { -public: - KinematicController(); - - virtual ~KinematicController() {} - - virtual void stepForward() = 0; - - void start(); - void stop() { _enabled = false; } - bool isRunning() const { return _enabled; } - -protected: - bool _enabled = false; - uint32_t _lastSubstep; -}; - -#endif // hifi_KinematicController_h diff --git a/libraries/physics/src/SimpleEntityKinematicController.cpp b/libraries/physics/src/SimpleEntityKinematicController.cpp deleted file mode 100644 index e834d4e91b..0000000000 --- a/libraries/physics/src/SimpleEntityKinematicController.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// SimpleEntityKinematicController.cpp -// libraries/physcis/src -// -// Created by Andrew Meadows 2015.01.13 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "PhysicsEngine.h" -#include "SimpleEntityKinematicController.h" - -void SimpleEntityKinematicController:: stepForward() { - uint32_t substep = PhysicsEngine::getNumSubsteps(); - float dt = (substep - _lastSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; - _entity->simulateSimpleKinematicMotion(dt); - _lastSubstep = substep; -} - diff --git a/libraries/physics/src/SimpleEntityKinematicController.h b/libraries/physics/src/SimpleEntityKinematicController.h deleted file mode 100644 index 1edfaf8d2c..0000000000 --- a/libraries/physics/src/SimpleEntityKinematicController.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// SimpleEntityKinematicController.h -// libraries/physcis/src -// -// Created by Andrew Meadows 2015.01.13 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_SimpleEntityKinematicController_h -#define hifi_SimpleEntityKinematicController_h - -/// SimpleKinematicConstroller performs simple exrapolation of velocities. - -#include -#include - -#include - -#include "KinematicController.h" - -class SimpleEntityKinematicController : public KinematicController { -public: - SimpleEntityKinematicController() = delete; // prevent compiler from making a default ctor - - SimpleEntityKinematicController(EntityItem* entity) : KinematicController(), _entity(entity) { assert(entity); } - - ~SimpleEntityKinematicController() { _entity = NULL; } - - void stepForward(); - -private: - EntityItem* _entity; -}; - -#endif // hifi_SimpleEntityKinematicController_h From f2bcdfa2b479cbe917f0afd1d6a127f34694f421 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Jan 2015 13:10:41 -0800 Subject: [PATCH 15/63] update _lastSimulated for kinematic motion --- libraries/entities/src/EntityItem.cpp | 101 ++++---------------- libraries/entities/src/EntityItem.h | 4 +- libraries/physics/src/EntityMotionState.cpp | 20 ++-- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 7 +- libraries/physics/src/PhysicsEngine.h | 2 +- 7 files changed, 39 insertions(+), 99 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c830236287..c1fc24fdc7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -607,11 +607,6 @@ bool EntityItem::isRestingOnSurface() const { } void EntityItem::simulate(const quint64& now) { - if (_physicsInfo) { - // we rely on bullet for simulation, so bail - return; - } - bool wantDebug = false; if (_lastSimulated == 0) { @@ -661,9 +656,13 @@ void EntityItem::simulate(const quint64& now) { qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated; } - if (hasAngularVelocity()) { - glm::quat rotation = getRotation(); + simulateKinematicMotion(timeElapsed); + _lastSimulated = now; +} +void EntityItem::simulateKinematicMotion(float timeElapsed) { + bool wantDebug = false; + if (hasAngularVelocity()) { // angular damping glm::vec3 angularVelocity = getAngularVelocity(); if (_angularDamping > 0.0f) { @@ -679,6 +678,9 @@ void EntityItem::simulate(const quint64& now) { const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; // if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { + if (angularSpeed > 0.0f) { + _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; + } setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); } else { // NOTE: angularSpeed is currently in degrees/sec!!! @@ -686,7 +688,7 @@ void EntityItem::simulate(const quint64& now) { float angle = timeElapsed * glm::radians(angularSpeed); glm::vec3 axis = _angularVelocity / angularSpeed; glm::quat dQ = glm::angleAxis(angle, axis); - rotation = glm::normalize(dQ * rotation); + glm::quat rotation = glm::normalize(dQ * getRotation()); setRotation(rotation); } } @@ -722,80 +724,6 @@ void EntityItem::simulate(const quint64& now) { position = newPosition; - // handle bounces off the ground... We bounce at the distance to the bottom of our entity - if (position.y <= getDistanceToBottomOfEntity()) { - velocity = velocity * glm::vec3(1,-1,1); - position.y = getDistanceToBottomOfEntity(); - } - - // apply gravity - if (hasGravity()) { - // handle resting on surface case, this is definitely a bit of a hack, and it only works on the - // "ground" plane of the domain, but for now it's what we've got - if (isRestingOnSurface()) { - velocity.y = 0.0f; - position.y = getDistanceToBottomOfEntity(); - } else { - velocity += getGravity() * timeElapsed; - } - } - - // NOTE: we don't zero out very small velocities --> we rely on a remote Bullet simulation - // to tell us when the entity has stopped. - - // NOTE: the simulation should NOT set any DirtyFlags on this entity - setPosition(position); // this will automatically recalculate our collision shape - setVelocity(velocity); - - if (wantDebug) { - qDebug() << " new position:" << position; - qDebug() << " new velocity:" << velocity; - qDebug() << " new AACube:" << getMaximumAACube(); - qDebug() << " old getAABox:" << getAABox(); - } - } - - _lastSimulated = now; -} - -void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) { - if (hasAngularVelocity()) { - // angular damping - glm::vec3 angularVelocity = getAngularVelocity(); - if (_angularDamping > 0.0f) { - angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); - setAngularVelocity(angularVelocity); - } - - float angularSpeed = glm::length(_angularVelocity); - const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.1f; // - if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { - if (angularSpeed > 0.0f) { - _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; - } - setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); - } else { - // NOTE: angularSpeed is currently in degrees/sec!!! - // TODO: Andrew to convert to radians/sec - float angle = timeElapsed * glm::radians(angularSpeed); - glm::vec3 axis = _angularVelocity / angularSpeed; - glm::quat dQ = glm::angleAxis(angle, axis); - glm::quat rotation = getRotation(); - rotation = glm::normalize(dQ * rotation); - setRotation(rotation); - } - } - - if (hasVelocity()) { - // linear damping - glm::vec3 velocity = getVelocity(); - if (_damping > 0.0f) { - velocity *= powf(1.0f - _damping, timeElapsed); - } - - // integrate position forward - glm::vec3 position = getPosition() + (velocity * timeElapsed); - // apply gravity if (hasGravity()) { // handle resting on surface case, this is definitely a bit of a hack, and it only works on the @@ -811,9 +739,16 @@ void EntityItem::simulateSimpleKinematicMotion(float timeElapsed) { _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; } } else { - setPosition(position); // this will automatically recalculate our collision shape + setPosition(position); setVelocity(velocity); } + + if (wantDebug) { + qDebug() << " new position:" << position; + qDebug() << " new velocity:" << velocity; + qDebug() << " new AACube:" << getMaximumAACube(); + qDebug() << " old getAABox:" << getAABox(); + } } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a9a82c5209..d266a30f62 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -82,6 +82,7 @@ public: void recordCreationTime(); // set _created to 'now' quint64 getLastSimulated() const { return _lastSimulated; } /// Last simulated time of this entity universal usecs + void setLastSimulated(quint64 now) { _lastSimulated = now; } /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } @@ -128,9 +129,8 @@ public: // perform linear extrapolation for SimpleEntitySimulation void simulate(const quint64& now); + void simulateKinematicMotion(float timeElapsed); - void simulateSimpleKinematicMotion(float timeElapsed); - virtual bool needsToCallUpdate() const { return false; } virtual void debugDump() const; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b4aa9d0e7e..f22487b8ea 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -54,11 +54,12 @@ void EntityMotionState::updateKinematicState(uint32_t substep) { setKinematic(_entity->isMoving(), substep); } -void EntityMotionState::stepKinematicSimulation(uint32_t substep) { +void EntityMotionState::stepKinematicSimulation(quint64 now) { assert(_isKinematic); - float dt = (substep - _lastKinematicSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; - _entity->simulateSimpleKinematicMotion(dt); - _lastKinematicSubstep = substep; + // NOTE: this is non-physical kinematic motion which steps to real run-time (now) + // which is different from physical kinematic motion (inside getWorldTransform()) + // which steps in physics simulation time. + _entity->simulate(now); } // This callback is invoked by the physics simulation in two cases: @@ -68,10 +69,15 @@ void EntityMotionState::stepKinematicSimulation(uint32_t substep) { // it is an opportunity for outside code to update the object's simulation position void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { if (_isKinematic) { + // This is physical kinematic motion which steps strictly by the subframe count + // of the physics simulation. uint32_t substep = PhysicsEngine::getNumSubsteps(); - // remove const-ness so we can actually update this instance - EntityMotionState* thisMotion = const_cast(this); - thisMotion->stepKinematicSimulation(substep); + float dt = (substep - _lastKinematicSubstep) * PHYSICS_ENGINE_FIXED_SUBSTEP; + _entity->simulateKinematicMotion(dt); + _entity->setLastSimulated(usecTimestampNow()); + + // bypass const-ness so we can remember the substep + const_cast(this)->_lastKinematicSubstep = substep; } worldTrans.setOrigin(glmToBullet(_entity->getPositionInMeters() - ObjectMotionState::getWorldOffset())); worldTrans.setRotation(glmToBullet(_entity->getRotation())); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 192ac166b4..5d98e545d9 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -39,7 +39,7 @@ public: MotionType computeMotionType() const; void updateKinematicState(uint32_t substep); - void stepKinematicSimulation(uint32_t substep); + void stepKinematicSimulation(quint64 now); // this relays incoming position/rotation to the RigidBody void getWorldTransform(btTransform& worldTrans) const; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 424a7fb680..ceeea219cf 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -99,7 +99,7 @@ public: bool isKinematic() const { return _isKinematic; } void setKinematic(bool kinematic, uint32_t substep); - virtual void stepKinematicSimulation(uint32_t substep) = 0; + virtual void stepKinematicSimulation(quint64 now) = 0; friend class PhysicsEngine; protected: diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index dbeea165c4..62693e3c9a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -297,7 +297,7 @@ void PhysicsEngine::stepSimulation() { // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; - stepNonPhysicalKinematics(); + stepNonPhysicalKinematics(usecTimestampNow()); unlock(); // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. @@ -317,12 +317,11 @@ void PhysicsEngine::stepSimulation() { computeCollisionEvents(); } -// TODO: need to update non-physical kinematic objects -void PhysicsEngine::stepNonPhysicalKinematics() { +void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) { QSet::iterator stateItr = _nonPhysicalKinematicObjects.begin(); while (stateItr != _nonPhysicalKinematicObjects.end()) { ObjectMotionState* motionState = *stateItr; - motionState->stepKinematicSimulation(_numSubsteps); + motionState->stepKinematicSimulation(now); ++stateItr; } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9ae9f88e7e..1dbfe2646e 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -67,7 +67,7 @@ public: virtual void init(EntityEditPacketSender* packetSender); void stepSimulation(); - void stepNonPhysicalKinematics(); + void stepNonPhysicalKinematics(const quint64& now); void computeCollisionEvents(); From 36c20c24fe7f3d90c3bb7d5fd25bfa77edcd6b5d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 23 Jan 2015 13:20:12 -0800 Subject: [PATCH 16/63] fix for velocity in units of domain size --- libraries/entities/src/EntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c1fc24fdc7..1ebde85d65 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -732,7 +732,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { } float speed = glm::length(velocity); - const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec + const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f / (float)TREE_SCALE; // 1mm/sec if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { setVelocity(ENTITY_ITEM_ZERO_VEC3); if (speed > 0.0f) { From 3c38a9eb53316e867eadea0ddbec5d766cdbd005 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 23 Jan 2015 13:32:38 -0800 Subject: [PATCH 17/63] add last simulated to the protocal --- libraries/entities/src/EntityItem.cpp | 41 ++++++++++++++++++++-- libraries/entities/src/EntityItem.h | 8 +++-- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7e3e982fb8..cb90875c43 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -140,9 +140,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet ByteCountCoded typeCoder = getType(); QByteArray encodedType = typeCoder; - quint64 updateDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited(); + // last updated (animations, non-physics changes) + quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited(); ByteCountCoded updateDeltaCoder = updateDelta; QByteArray encodedUpdateDelta = updateDeltaCoder; + + // last simulated (velocity, angular velocity, physics changes) + quint64 simulatedDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited(); + ByteCountCoded simulatedDeltaCoder = simulatedDelta; + QByteArray encodedSimulatedDelta = simulatedDeltaCoder; + + EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); EntityPropertyFlags requestedProperties = getEntityProperties(params); EntityPropertyFlags propertiesDidntFit = requestedProperties; @@ -170,6 +178,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet bool successCreatedFits = false; bool successLastEditedFits = false; bool successLastUpdatedFits = false; + bool successLastSimulatedFits = false; bool successPropertyFlagsFits = false; int propertyFlagsOffset = 0; int oldPropertyFlagsLength = 0; @@ -189,8 +198,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet if (successLastEditedFits) { successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta); } - if (successLastUpdatedFits) { + successLastSimulatedFits = packetData->appendValue(encodedSimulatedDelta); + } + + if (successLastSimulatedFits) { propertyFlagsOffset = packetData->getUncompressedByteOffset(); encodedPropertyFlags = propertyFlags; oldPropertyFlagsLength = encodedPropertyFlags.length(); @@ -458,6 +470,25 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef encodedUpdateDelta = updateDeltaCoder; // determine true length dataAt += encodedUpdateDelta.size(); bytesRead += encodedUpdateDelta.size(); + + // Newer bitstreams will have a last simulated and a last updated value + if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) { + // last simulated is stored as ByteCountCoded delta from lastEdited + QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size + ByteCountCoded simulatedDeltaCoder = encodedSimulatedDelta; + quint64 simulatedDelta = simulatedDeltaCoder; + if (overwriteLocalData) { + _lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that + if (wantDebug) { + qDebug() << "_lastSimulated =" << _lastSimulated; + qDebug() << "_lastEdited=" << _lastEdited; + qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted; + } + } + encodedSimulatedDelta = simulatedDeltaCoder; // determine true length + dataAt += encodedSimulatedDelta.size(); + bytesRead += encodedSimulatedDelta.size(); + } // Property Flags QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size @@ -521,6 +552,12 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef recalculateCollisionShape(); if (overwriteLocalData && (getDirtyFlags() & EntityItem::DIRTY_POSITION)) { + // TODO: Andrew & Brad to discuss -- this probably should not be "now" but instead should be the last + // simulated time from server. The logic should maybe be: the position changed from the server, so the + // position we just set can be thought of as the position at the time it was last simulated by the + // server (clock skew adjusted). By setting it to "now" we are saying that the last position is to be + // considered to be the correct position for "now" which is likely in the future from when it actually + // was at that last known positition. _lastSimulated = now; } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a9a82c5209..c68b638553 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -86,7 +86,7 @@ public: /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } void setLastEdited(quint64 lastEdited) - { _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } + { _lastEdited = _lastUpdated = _lastSimulated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } @@ -125,6 +125,7 @@ public: // perform update virtual void update(const quint64& now) { _lastUpdated = now; } + quint64 getLastUpdated() const { return _lastUpdated; } // perform linear extrapolation for SimpleEntitySimulation void simulate(const quint64& now); @@ -296,9 +297,10 @@ protected: QUuid _id; uint32_t _creatorTokenID; bool _newlyCreated; - quint64 _lastSimulated; // last time this entity called simulate() - quint64 _lastUpdated; // last time this entity called update() + quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes + quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes quint64 _lastEdited; // last official local or remote edit time + quint64 _lastEditedFromRemote; // last time we received and edit from the server quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame) quint64 _created; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 110892a106..07228c8351 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAVE_USER_DATA; + return VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 87d93b931f..f0d21ca9f8 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -126,6 +126,7 @@ const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_ const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6; +const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From fa485d21b7edc7fe08ce4d4e4c0f1fd81d168a4a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 23 Jan 2015 13:52:28 -0800 Subject: [PATCH 18/63] added comment --- libraries/entities/src/EntityItem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index cb90875c43..fd6502d045 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -924,6 +924,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { setLastEdited(now); } if (getDirtyFlags() & EntityItem::DIRTY_POSITION) { + // TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases. _lastSimulated = now; } } From c01d2d657c242e2e8cc1c7d6c8a493717fbc620f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 23 Jan 2015 13:55:12 -0800 Subject: [PATCH 19/63] added comment --- libraries/physics/src/EntityMotionState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8b6fb1ea9f..a799a3d7d2 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -208,6 +208,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (_numNonMovingUpdates <= 1) { // we only update lastEdited when we're sending new physics data // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) + // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); From bc0fa0ed246bf490f456721be004f38394f6c092 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 Jan 2015 13:58:51 -0800 Subject: [PATCH 20/63] Push granularity option down the line in preparation for selectively increasing resolution. --- interface/src/ui/MetavoxelEditor.cpp | 41 ++++++++++++++----- interface/src/ui/MetavoxelEditor.h | 3 ++ .../metavoxels/src/MetavoxelMessages.cpp | 23 +++++++---- libraries/metavoxels/src/MetavoxelMessages.h | 9 ++-- libraries/metavoxels/src/Spanner.cpp | 31 +++++++------- libraries/metavoxels/src/Spanner.h | 20 +++++---- libraries/networking/src/PacketHeaders.cpp | 2 +- 7 files changed, 82 insertions(+), 47 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 1df82a42a0..4cb6414966 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -822,6 +822,12 @@ HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QStrin _radius->setSingleStep(0.01); _radius->setMaximum(FLT_MAX); _radius->setValue(5.0); + + _form->addRow("Granularity:", _granularity = new QDoubleSpinBox()); + _granularity->setMinimum(-FLT_MAX); + _granularity->setMaximum(FLT_MAX); + _granularity->setPrefix("2^"); + _granularity->setValue(8.0); } bool HeightfieldBrushTool::appliesTo(const AttributePointer& attribute) const { @@ -851,7 +857,7 @@ bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Wheel) { float angle = static_cast(event)->angleDelta().y(); const float ANGLE_SCALE = 1.0f / 1000.0f; - _radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE)); + _radius->setValue(_radius->value() * pow(2.0f, angle * ANGLE_SCALE)); return true; } else if (event->type() == QEvent::MouseButtonPress && _positionValid) { @@ -881,7 +887,7 @@ QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) { const int ERASE_MODE_INDEX = 2; return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), alternate ? -_height->value() : _height->value(), _mode->currentIndex() == SET_MODE_INDEX, - _mode->currentIndex() == ERASE_MODE_INDEX)); + _mode->currentIndex() == ERASE_MODE_INDEX, pow(2.0f, _granularity->value()))); } MaterialControl::MaterialControl(QWidget* widget, QFormLayout* form, bool clearable) : @@ -956,10 +962,11 @@ QVariant HeightfieldMaterialBrushTool::createEdit(bool alternate) { sphere->setScale(_radius->value()); if (alternate) { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - SharedObjectPointer(), QColor(0, 0, 0, 0), true)); + SharedObjectPointer(), QColor(0, 0, 0, 0), true, false, pow(2.0f, _granularity->value()))); } else { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - _materialControl->getMaterial(), _materialControl->getColor(), true)); + _materialControl->getMaterial(), _materialControl->getColor(), + true, false, pow(2.0f, _granularity->value()))); } } @@ -974,10 +981,11 @@ QVariant HeightfieldSculptBrushTool::createEdit(bool alternate) { sphere->setScale(_radius->value()); if (alternate) { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - SharedObjectPointer(), QColor(0, 0, 0, 0))); + SharedObjectPointer(), QColor(0, 0, 0, 0), false, false, pow(2.0f, _granularity->value()))); } else { return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - _materialControl->getMaterial(), _materialControl->getColor())); + _materialControl->getMaterial(), _materialControl->getColor(), + false, false, pow(2.0f, _granularity->value()))); } } @@ -992,13 +1000,14 @@ HeightfieldFillBrushTool::HeightfieldFillBrushTool(MetavoxelEditor* editor) : QVariant HeightfieldFillBrushTool::createEdit(bool alternate) { const int FILL_MODE_INDEX = 0; if (_mode->currentIndex() == FILL_MODE_INDEX) { - return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value())); + return QVariant::fromValue(FillHeightfieldHeightEdit(_position, _radius->value(), + pow(2.0f, _granularity->value()))); } Sphere* sphere = new Sphere(); sphere->setTranslation(_position); sphere->setScale(_radius->value()); return QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(sphere), - SharedObjectPointer(), QColor(), false, true)); + SharedObjectPointer(), QColor(), false, true, pow(2.0f, _granularity->value()))); } HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor) : @@ -1017,6 +1026,12 @@ HeightfieldMaterialBoxTool::HeightfieldMaterialBoxTool(MetavoxelEditor* editor) _snapToGrid->setChecked(true); _materialControl = new MaterialControl(this, form, true); + + form->addRow("Granularity:", _granularity = new QDoubleSpinBox()); + _granularity->setMinimum(-FLT_MAX); + _granularity->setMaximum(FLT_MAX); + _granularity->setPrefix("2^"); + _granularity->setValue(8.0); } bool HeightfieldMaterialBoxTool::appliesTo(const AttributePointer& attribute) const { @@ -1039,7 +1054,7 @@ void HeightfieldMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm: cuboid->setAspectY(vector.y / vector.x); cuboid->setAspectZ(vector.z / vector.x); MetavoxelEditMessage message = { QVariant::fromValue(HeightfieldMaterialSpannerEdit(SharedObjectPointer(cuboid), - _materialControl->getMaterial(), _materialControl->getColor())) }; + _materialControl->getMaterial(), _materialControl->getColor(), false, false, pow(2.0f, _granularity->value()))) }; Application::getInstance()->getMetavoxels()->applyEdit(message, true); } @@ -1056,6 +1071,12 @@ HeightfieldMaterialSpannerTool::HeightfieldMaterialSpannerTool(MetavoxelEditor* _materialControl = new MaterialControl(this, form, true); + form->addRow("Granularity:", _granularity = new QDoubleSpinBox()); + _granularity->setMinimum(-FLT_MAX); + _granularity->setMaximum(FLT_MAX); + _granularity->setPrefix("2^"); + _granularity->setValue(8.0); + QPushButton* place = new QPushButton("Set"); layout()->addWidget(place); connect(place, &QPushButton::clicked, this, &HeightfieldMaterialSpannerTool::place); @@ -1076,7 +1097,7 @@ QColor HeightfieldMaterialSpannerTool::getColor() { void HeightfieldMaterialSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { static_cast(spanner.data())->setWillBeVoxelized(true); MetavoxelEditMessage message = { QVariant::fromValue(HeightfieldMaterialSpannerEdit(spanner, - _materialControl->getMaterial(), _materialControl->getColor())) }; + _materialControl->getMaterial(), _materialControl->getColor(), false, false, pow(2.0f, _granularity->value()))) }; Application::getInstance()->getMetavoxels()->applyEdit(message, true); } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 23feb940c9..a816b9ebe7 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -326,6 +326,7 @@ protected: QFormLayout* _form; QDoubleSpinBox* _radius; + QDoubleSpinBox* _granularity; glm::vec3 _position; bool _positionValid; @@ -448,6 +449,7 @@ private: QCheckBox* _snapToGrid; MaterialControl* _materialControl; + QDoubleSpinBox* _granularity; }; /// Allows setting heightfield materials by placing a spanner. @@ -470,6 +472,7 @@ private: SharedObjectEditor* _spannerEditor; MaterialControl* _materialControl; + QDoubleSpinBox* _granularity; }; #endif // hifi_MetavoxelEditor_h diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index bae5768068..98da28cafa 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -149,12 +149,13 @@ void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects } PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, - float height, bool set, bool erase) : + float height, bool set, bool erase, float granularity) : position(position), radius(radius), height(height), set(set), - erase(erase) { + erase(erase), + granularity(granularity) { } void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { @@ -166,7 +167,8 @@ void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObje Box(position - extents, position + extents), results); foreach (const SharedObjectPointer& spanner, results) { - Spanner* newSpanner = static_cast(spanner.data())->paintHeight(position, radius, height, set, erase); + Spanner* newSpanner = static_cast(spanner.data())->paintHeight(position, radius, + height, set, erase, granularity); if (newSpanner != spanner) { data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner); } @@ -179,11 +181,12 @@ MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& av } HeightfieldMaterialSpannerEdit::HeightfieldMaterialSpannerEdit(const SharedObjectPointer& spanner, - const SharedObjectPointer& material, const QColor& averageColor, bool paint, bool voxelize) : + const SharedObjectPointer& material, const QColor& averageColor, bool paint, bool voxelize, float granularity) : MaterialEdit(material, averageColor), spanner(spanner), paint(paint), - voxelize(voxelize) { + voxelize(voxelize), + granularity(granularity) { } class SpannerProjectionFetchVisitor : public SpannerVisitor { @@ -250,16 +253,18 @@ void HeightfieldMaterialSpannerEdit::apply(MetavoxelData& data, const WeakShared } foreach (const SharedObjectPointer& result, results) { - Spanner* newResult = static_cast(result.data())->setMaterial(spanner, material, color, paint, voxelize); + Spanner* newResult = static_cast(result.data())->setMaterial(spanner, material, + color, paint, voxelize, granularity); if (newResult != result) { data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), result, newResult); } } } -FillHeightfieldHeightEdit::FillHeightfieldHeightEdit(const glm::vec3& position, float radius) : +FillHeightfieldHeightEdit::FillHeightfieldHeightEdit(const glm::vec3& position, float radius, float granularity) : position(position), - radius(radius) { + radius(radius), + granularity(granularity) { } void FillHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { @@ -269,7 +274,7 @@ void FillHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjec Box(position - extents, position + extents), results); foreach (const SharedObjectPointer& spanner, results) { - Spanner* newSpanner = static_cast(spanner.data())->fillHeight(position, radius); + Spanner* newSpanner = static_cast(spanner.data())->fillHeight(position, radius, granularity); if (newSpanner != spanner) { data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner); } diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 71013996c2..7fbe2b4243 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -205,9 +205,10 @@ public: STREAM float height; STREAM bool set; STREAM bool erase; + STREAM float granularity; PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, - float height = 0.0f, bool set = false, bool erase = false); + float height = 0.0f, bool set = false, bool erase = false, float granularity = 0.0f); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; @@ -237,10 +238,11 @@ public: STREAM SharedObjectPointer spanner; STREAM bool paint; STREAM bool voxelize; + STREAM float granularity; HeightfieldMaterialSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer(), const SharedObjectPointer& material = SharedObjectPointer(), - const QColor& averageColor = QColor(), bool paint = false, bool voxelize = false); + const QColor& averageColor = QColor(), bool paint = false, bool voxelize = false, float granularity = 0.0f); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; @@ -255,8 +257,9 @@ public: STREAM glm::vec3 position; STREAM float radius; + STREAM float granularity; - FillHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f); + FillHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float granularity = 0.0f); virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index c771b8fb4a..05d765f9d4 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -111,16 +111,16 @@ bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& dire return _bounds.findRayIntersection(origin, direction, distance); } -Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase) { +Spanner* Spanner::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase, float granularity) { return this; } -Spanner* Spanner::fillHeight(const glm::vec3& position, float radius) { +Spanner* Spanner::fillHeight(const glm::vec3& position, float radius, float granularity) { return this; } Spanner* Spanner::setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize) { + const QColor& color, bool paint, bool voxelize, float granularity) { return this; } @@ -1786,7 +1786,7 @@ void HeightfieldNode::getRangeAfterHeightPaint(const glm::vec3& translation, con HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const glm::vec3& position, float radius, float height, bool set, bool erase, - float normalizeScale, float normalizeOffset) { + float normalizeScale, float normalizeOffset, float granularity) { if (!_height) { return this; } @@ -1813,7 +1813,7 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons HeightfieldNode* newChild = _children[i]->paintHeight(translation + rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation, - nextScale, position, radius, height, set, erase, normalizeScale, normalizeOffset); + nextScale, position, radius, height, set, erase, normalizeScale, normalizeOffset, granularity); if (_children[i] != newChild) { if (newNode == this) { newNode = new HeightfieldNode(*this); @@ -1885,7 +1885,7 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons } HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, - const glm::vec3& position, float radius) { + const glm::vec3& position, float radius, float granularity) { if (!_height) { return this; } @@ -1911,7 +1911,7 @@ HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const HeightfieldNode* newChild = _children[i]->fillHeight(translation + rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation, - nextScale, position, radius); + nextScale, position, radius, granularity); if (_children[i] != newChild) { if (newNode == this) { newNode = new HeightfieldNode(*this); @@ -2088,7 +2088,7 @@ void HeightfieldNode::getRangeAfterEdit(const glm::vec3& translation, const glm: HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, Spanner* spanner, const SharedObjectPointer& material, const QColor& color, bool paint, bool voxelize, - float normalizeScale, float normalizeOffset) { + float normalizeScale, float normalizeOffset, float granularity) { if (!_height) { return this; } @@ -2109,7 +2109,7 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons HeightfieldNode* newChild = _children[i]->setMaterial(translation + rotation * glm::vec3(i & X_MAXIMUM_FLAG ? nextScale.x : 0.0f, 0.0f, i & Y_MAXIMUM_FLAG ? nextScale.z : 0.0f), rotation, nextScale, spanner, - material, color, paint, voxelize, normalizeScale, normalizeOffset); + material, color, paint, voxelize, normalizeScale, normalizeOffset, granularity); if (_children[i] != newChild) { if (newNode == this) { newNode = new HeightfieldNode(*this); @@ -3310,7 +3310,8 @@ bool Heightfield::findRayIntersection(const glm::vec3& origin, const glm::vec3& getScale() * _aspectZ), origin, direction, distance); } -Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase) { +Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float height, + bool set, bool erase, float granularity) { // first see if we're going to exceed the range limits float minimumValue = 1.0f, maximumValue = numeric_limits::max(); if (set) { @@ -3328,19 +3329,19 @@ Spanner* Heightfield::paintHeight(const glm::vec3& position, float radius, float Heightfield* newHeightfield = prepareEdit(minimumValue, maximumValue, normalizeScale, normalizeOffset); newHeightfield->setRoot(HeightfieldNodePointer(_root->paintHeight(newHeightfield->getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * newHeightfield->getAspectY(), getScale() * _aspectZ), position, radius, height, - set, erase, normalizeScale, normalizeOffset))); + set, erase, normalizeScale, normalizeOffset, granularity))); return newHeightfield; } -Spanner* Heightfield::fillHeight(const glm::vec3& position, float radius) { +Spanner* Heightfield::fillHeight(const glm::vec3& position, float radius, float granularity) { Heightfield* newHeightfield = static_cast(clone(true)); newHeightfield->setRoot(HeightfieldNodePointer(_root->fillHeight(getTranslation(), getRotation(), - glm::vec3(getScale(), getScale() * _aspectY, getScale() * _aspectZ), position, radius))); + glm::vec3(getScale(), getScale() * _aspectY, getScale() * _aspectZ), position, radius, granularity))); return newHeightfield; } Spanner* Heightfield::setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize) { + const QColor& color, bool paint, bool voxelize, float granularity) { // first see if we're going to exceed the range limits, normalizing if necessary Spanner* spannerData = static_cast(spanner.data()); float normalizeScale = 1.0f, normalizeOffset = 0.0f; @@ -3355,7 +3356,7 @@ Spanner* Heightfield::setMaterial(const SharedObjectPointer& spanner, const Shar } newHeightfield->setRoot(HeightfieldNodePointer(_root->setMaterial(newHeightfield->getTranslation(), getRotation(), glm::vec3(getScale(), getScale() * newHeightfield->getAspectY(), getScale() * _aspectZ), spannerData, - material, color, paint, voxelize, normalizeScale, normalizeOffset))); + material, color, paint, voxelize, normalizeScale, normalizeOffset, granularity))); return newHeightfield; } diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index 653893c84d..42aad203c6 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -77,16 +77,17 @@ public: /// \param set whether to set the height as opposed to raising/lowering it /// \param erase whether to erase height values /// \return the modified spanner, or this if no modification was performed - virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase); + virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, + bool set, bool erase, float granularity); /// Attempts to fill the spanner's height (adding removing volumetric information). /// \return the modified spanner, or this if no modification was performed - virtual Spanner* fillHeight(const glm::vec3& position, float radius); + virtual Spanner* fillHeight(const glm::vec3& position, float radius, float granularity); /// Attempts to "sculpt" or "paint," etc., with the supplied spanner. /// \return the modified spanner, or this if no modification was performed virtual Spanner* setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize); + const QColor& color, bool paint, bool voxelize, float granularity); /// Checks whether this spanner has its own colors. virtual bool hasOwnColors() const; @@ -696,17 +697,17 @@ public: HeightfieldNode* paintHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const glm::vec3& position, float radius, float height, bool set, bool erase, - float normalizeScale, float normalizeOffset); + float normalizeScale, float normalizeOffset, float granularity); HeightfieldNode* fillHeight(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, - const glm::vec3& position, float radius); + const glm::vec3& position, float radius, float granularity); void getRangeAfterEdit(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, const Box& editBounds, float& minimum, float& maximum) const; HeightfieldNode* setMaterial(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, Spanner* spanner, const SharedObjectPointer& material, const QColor& color, bool paint, bool voxelize, - float normalizeScale, float normalizeOffset); + float normalizeScale, float normalizeOffset, float granularity); void read(HeightfieldStreamState& state); void write(HeightfieldStreamState& state) const; @@ -803,12 +804,13 @@ public: virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; - virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, bool set, bool erase); + virtual Spanner* paintHeight(const glm::vec3& position, float radius, float height, + bool set, bool erase, float granularity); - virtual Spanner* fillHeight(const glm::vec3& position, float radius); + virtual Spanner* fillHeight(const glm::vec3& position, float radius, float granularity); virtual Spanner* setMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material, - const QColor& color, bool paint, bool voxelize); + const QColor& color, bool paint, bool voxelize, float granularity); virtual bool hasOwnColors() const; virtual bool hasOwnMaterials() const; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 110892a106..7968c36e42 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -78,7 +78,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeAudioStreamStats: return 1; case PacketTypeMetavoxelData: - return 12; + return 13; default: return 0; } From 9a0576adfb3381e9c7bb5e680018ade4e8e34969 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 23 Jan 2015 15:54:26 -0800 Subject: [PATCH 21/63] remove setting last simulated in setLastEdited() because it may cause problems --- libraries/entities/src/EntityItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 020f7ee0d4..df619e2f69 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -87,7 +87,7 @@ public: /// Last edited time of this entity universal usecs quint64 getLastEdited() const { return _lastEdited; } void setLastEdited(quint64 lastEdited) - { _lastEdited = _lastUpdated = _lastSimulated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } + { _lastEdited = _lastUpdated = lastEdited; _changedOnServer = glm::max(lastEdited, _changedOnServer); } float getEditedAgo() const /// Elapsed seconds since this entity was last edited { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } From 7a1300d66cf0ba54e056ba0fa720bb8e1bf61d27 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Jan 2015 16:04:06 -0800 Subject: [PATCH 22/63] Request blocking calls --- examples/controllers/hydra/hydraGrab.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/controllers/hydra/hydraGrab.js b/examples/controllers/hydra/hydraGrab.js index 4d0b873fd2..0c6e135739 100644 --- a/examples/controllers/hydra/hydraGrab.js +++ b/examples/controllers/hydra/hydraGrab.js @@ -274,7 +274,7 @@ function controller(wichSide) { this.glowedIntersectingModel.isKnownID = false; } if (!this.grabbing) { - var intersection = Entities.findRayIntersection({ + var intersection = Entities.findRayIntersectionBlocking({ origin: this.palmPosition, direction: this.front }); @@ -304,7 +304,7 @@ function controller(wichSide) { if (this.grabbing) { if (!this.entityID.isKnownID) { print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); - this.entityID = Entities.findRayIntersection({ + this.entityID = Entities.findRayIntersectionBlocking({ origin: this.palmPosition, direction: this.front }).entityID; @@ -475,7 +475,7 @@ function controller(wichSide) { Vec3.print("Looking at: ", this.palmPosition); var pickRay = { origin: this.palmPosition, direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; - var foundIntersection = Entities.findRayIntersection(pickRay); + var foundIntersection = Entities.findRayIntersectionBlocking(pickRay); if(!foundIntersection.accurate) { print("No accurate intersection"); From 34110b6745c8378653c21d1d09d6e72fb1c3807d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 23 Jan 2015 18:19:45 -0800 Subject: [PATCH 23/63] Partial subdivision implementation. --- libraries/metavoxels/src/Spanner.cpp | 227 ++++++++++++++++++++++++++- libraries/metavoxels/src/Spanner.h | 2 + 2 files changed, 228 insertions(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/Spanner.cpp b/libraries/metavoxels/src/Spanner.cpp index 05d765f9d4..5d9cc24b92 100644 --- a/libraries/metavoxels/src/Spanner.cpp +++ b/libraries/metavoxels/src/Spanner.cpp @@ -1846,6 +1846,13 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons new HeightfieldStack(stackWidth, newStackContents, newStackMaterials))); } + // if the granularity is insufficient, we must subdivide + if (scale.x / innerHeightWidth > granularity || scale.z / innerHeightHeight > granularity) { + HeightfieldNodePointer newNode(subdivide(newHeightContents, newStackContents)); + return newNode->paintHeight(translation, rotation, scale, position, radius, height, set, + erase, 1.0f, 0.0f, granularity); + } + // now apply the actual change glm::vec3 start = glm::clamp(glm::floor(center - extents), glm::vec3(), glm::vec3((float)highestHeightX, 0.0f, (float)highestHeightZ)); @@ -1927,9 +1934,15 @@ HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const if (!_stack) { return this; } - QVector newHeightContents = _height->getContents(); + // if the granularity is insufficient, we must subdivide + QVector newHeightContents = _height->getContents(); QVector newStackContents = _stack->getContents(); + if (scale.x / innerHeightWidth > granularity || scale.z / innerHeightHeight > granularity) { + HeightfieldNodePointer newNode(subdivide(newHeightContents, newStackContents)); + return newNode->fillHeight(translation, rotation, scale, position, radius, granularity); + } + int stackWidth = _stack->getWidth(); int stackHeight = newStackContents.size() / stackWidth; QVector newStackMaterials = _stack->getMaterials(); @@ -2149,6 +2162,14 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons return new HeightfieldNode(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, newHeightContents)), _color, _material, HeightfieldStackPointer(new HeightfieldStack(stackWidth, newStackContents, newStackMaterials))); } + + // if the granularity is insufficient, we must subdivide + if (scale.x / innerHeightWidth > granularity || scale.z / innerHeightHeight > granularity) { + HeightfieldNodePointer newNode(subdivide(newHeightContents, newStackContents)); + return newNode->setMaterial(translation, rotation, scale, spanner, material, color, + paint, voxelize, 1.0f, 0.0f, granularity); + } + QVector oldHeightContents = newHeightContents; QVector oldStackContents = newStackContents; @@ -3210,6 +3231,210 @@ bool HeightfieldNode::findHeightfieldRayIntersection(const glm::vec3& origin, co return false; } +static inline float mixHeights(float firstHeight, float secondHeight, float t) { + return (firstHeight == 0.0f) ? secondHeight : (secondHeight == 0.0f ? firstHeight : + glm::mix(firstHeight, secondHeight, t)); +} + +HeightfieldNode* HeightfieldNode::subdivide(const QVector& heightContents, + const QVector& stackContents) const { + HeightfieldNode* newNode = new HeightfieldNode(*this); + int heightWidth = _height->getWidth(); + int heightHeight = heightContents.size() / heightWidth; + newNode->setHeight(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, heightContents))); + int stackWidth = 0, stackHeight = 0; + QVector stackMaterials; + if (_stack) { + stackWidth = _stack->getWidth(); + stackHeight = stackContents.size() / stackWidth; + stackMaterials = _stack->getMaterials(); + newNode->setStack(HeightfieldStackPointer(new HeightfieldStack(stackWidth, stackContents, stackMaterials))); + } + int colorWidth = 0, colorHeight = 0; + if (_color) { + colorWidth = _color->getWidth(); + colorHeight = _color->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES); + } + int materialWidth = 0, materialHeight = 0; + QVector materialMaterials; + if (_material) { + materialWidth = _material->getWidth(); + materialHeight = _material->getContents().size() / materialWidth; + materialMaterials = _material->getMaterials(); + } + for (int i = 0; i < CHILD_COUNT; i++) { + QVector childHeightContents(heightWidth * heightHeight); + QByteArray childColorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF); + QByteArray childMaterialContents(materialWidth * materialHeight, 0); + QVector childStackContents(stackWidth * stackHeight); + + quint16* heightDest = childHeightContents.data(); + const quint16* heightSrc = heightContents.constData() + (i & Y_MAXIMUM_FLAG ? (heightHeight / 2) * heightWidth : 0) + + (i & X_MAXIMUM_FLAG ? heightWidth / 2 : 0); + for (int z = 0; z < heightHeight; z++) { + float srcZ = z * 0.5f + 0.5f; + float fractZ = glm::fract(srcZ); + const quint16* heightSrcZ = heightSrc + (int)srcZ * heightWidth; + for (int x = 0; x < heightWidth; x++) { + float srcX = x * 0.5f + 0.5f; + float fractX = glm::fract(srcX); + const quint16* heightSrcX = heightSrcZ + (int)srcX; + if (fractZ == 0.0f) { + if (fractX == 0.0f) { + *heightDest++ = heightSrcX[0]; + } else { + *heightDest++ = mixHeights(heightSrcX[0], heightSrcX[1], fractX); + } + } else { + if (fractX == 0.0f) { + *heightDest++ = mixHeights(heightSrcX[0], heightSrcX[heightWidth], fractZ); + } else { + *heightDest++ = mixHeights(mixHeights(heightSrcX[0], heightSrcX[1], fractX), + mixHeights(heightSrcX[heightWidth], heightSrcX[heightWidth + 1], fractX), fractZ); + } + } + } + } + + if (colorWidth != 0) { + char* colorDest = childColorContents.data(); + const uchar* colorSrc = (const uchar*)_color->getContents().constData() + + ((i & Y_MAXIMUM_FLAG ? (colorHeight / 2) * colorWidth : 0) + + (i & X_MAXIMUM_FLAG ? colorWidth / 2 : 0)) * DataBlock::COLOR_BYTES; + for (int z = 0; z < colorHeight; z++) { + float srcZ = z * 0.5f; + float fractZ = glm::fract(srcZ); + const uchar* colorSrcZ = colorSrc + (int)srcZ * colorWidth * DataBlock::COLOR_BYTES; + for (int x = 0; x < colorWidth; x++) { + float srcX = x * 0.5f; + float fractX = glm::fract(srcX); + const uchar* colorSrcX = colorSrcZ + (int)srcX * DataBlock::COLOR_BYTES; + const uchar* nextColorSrcX = colorSrcX + colorWidth * DataBlock::COLOR_BYTES; + if (fractZ == 0.0f) { + if (fractX == 0.0f) { + *colorDest++ = colorSrcX[0]; + *colorDest++ = colorSrcX[1]; + *colorDest++ = colorSrcX[2]; + } else { + *colorDest++ = glm::mix(colorSrcX[0], colorSrcX[3], fractX); + *colorDest++ = glm::mix(colorSrcX[1], colorSrcX[4], fractX); + *colorDest++ = glm::mix(colorSrcX[2], colorSrcX[5], fractX); + } + } else { + if (fractX == 0.0f) { + *colorDest++ = glm::mix(colorSrcX[0], nextColorSrcX[0], fractZ); + *colorDest++ = glm::mix(colorSrcX[1], nextColorSrcX[1], fractZ); + *colorDest++ = glm::mix(colorSrcX[2], nextColorSrcX[2], fractZ); + } else { + *colorDest++ = glm::mix(glm::mix(colorSrcX[0], colorSrcX[3], fractX), + glm::mix(nextColorSrcX[0], nextColorSrcX[3], fractX), fractZ); + *colorDest++ = glm::mix(glm::mix(colorSrcX[1], colorSrcX[4], fractX), + glm::mix(nextColorSrcX[1], nextColorSrcX[4], fractX), fractZ); + *colorDest++ = glm::mix(glm::mix(colorSrcX[2], colorSrcX[5], fractX), + glm::mix(nextColorSrcX[2], nextColorSrcX[5], fractX), fractZ); + } + } + } + } + } + + if (materialWidth != 0) { + char* materialDest = childMaterialContents.data(); + const char* materialSrc = _material->getContents().constData() + + (i & Y_MAXIMUM_FLAG ? (materialHeight / 2) * materialWidth : 0) + + (i & X_MAXIMUM_FLAG ? materialWidth / 2 : 0); + for (int z = 0; z < materialHeight; z++) { + float srcZ = z * 0.5f; + const char* materialSrcZ = materialSrc + (int)srcZ * materialWidth; + for (int x = 0; x < materialWidth; x++) { + float srcX = x * 0.5f; + const char* materialSrcX = materialSrcZ + (int)srcX; + *materialDest++ = *materialSrcX; + } + } + } + + if (stackWidth != 0) { + StackArray* stackDest = childStackContents.data(); + const StackArray* stackSrc = _stack->getContents().constData() + + (i & Y_MAXIMUM_FLAG ? (stackHeight / 2) * stackWidth : 0) + + (i & X_MAXIMUM_FLAG ? stackWidth / 2 : 0); + for (int z = 0; z < stackHeight; z++) { + float srcZ = z * 0.5f; + float fractZ = glm::fract(srcZ); + const StackArray* stackSrcZ = stackSrc + (int)srcZ * stackWidth; + for (int x = 0; x < stackWidth; x++) { + float srcX = x * 0.5f; + float fractX = glm::fract(srcX); + const StackArray* stackSrcX = stackSrcZ + (int)srcX; + if (stackSrcX->isEmpty()) { + stackDest++; + continue; + } + int minimumY = stackSrcX->getPosition() * 2; + int maximumY = (stackSrcX->getPosition() + stackSrcX->getEntryCount() - 1) * 2; + *stackDest = StackArray(maximumY - minimumY + 1); + stackDest->setPosition(minimumY); + for (int y = minimumY; y <= maximumY; y++) { + float srcY = y * 0.5f; + float fractY = glm::fract(srcY); + const StackArray::Entry& srcEntry = stackSrcX->getEntry((int)srcY); + StackArray::Entry& destEntry = stackDest->getEntry(y); + destEntry.color = srcEntry.color; + destEntry.material = srcEntry.material; + if (srcEntry.hermiteX != 0) { + glm::vec3 normal; + float distance = srcEntry.getHermiteX(normal); + if (distance < fractX) { + const StackArray::Entry& nextSrcEntryX = stackSrcX[1].getEntry((int)srcY); + destEntry.color = nextSrcEntryX.color; + destEntry.material = nextSrcEntryX.material; + + } else { + destEntry.setHermiteX(normal, (distance - fractX) / 0.5f); + } + } + if (srcEntry.hermiteY != 0) { + glm::vec3 normal; + float distance = srcEntry.getHermiteY(normal); + if (distance < fractY) { + const StackArray::Entry& nextSrcEntryY = stackSrcX->getEntry((int)srcY + 1); + destEntry.color = nextSrcEntryY.color; + destEntry.material = nextSrcEntryY.material; + + } else { + destEntry.setHermiteY(normal, (distance - fractY) / 0.5f); + } + } + if (srcEntry.hermiteZ != 0) { + glm::vec3 normal; + float distance = srcEntry.getHermiteZ(normal); + if (distance < fractZ) { + const StackArray::Entry& nextSrcEntryZ = stackSrcX[stackWidth].getEntry((int)srcY); + destEntry.color = nextSrcEntryZ.color; + destEntry.material = nextSrcEntryZ.material; + + } else { + destEntry.setHermiteZ(normal, (distance - fractZ) / 0.5f); + } + } + } + stackDest++; + } + } + } + + newNode->setChild(i, HeightfieldNodePointer(new HeightfieldNode( + HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, childHeightContents)), + HeightfieldColorPointer(colorWidth == 0 ? NULL : new HeightfieldColor(colorWidth, childColorContents)), + HeightfieldMaterialPointer(materialWidth == 0 ? NULL : + new HeightfieldMaterial(materialWidth, childMaterialContents, materialMaterials)), + HeightfieldStackPointer(stackWidth == 0 ? NULL : + new HeightfieldStack(stackWidth, childStackContents, stackMaterials))))); + } + return newNode; +} + AbstractHeightfieldNodeRenderer::~AbstractHeightfieldNodeRenderer() { } diff --git a/libraries/metavoxels/src/Spanner.h b/libraries/metavoxels/src/Spanner.h index 42aad203c6..b60a104d68 100644 --- a/libraries/metavoxels/src/Spanner.h +++ b/libraries/metavoxels/src/Spanner.h @@ -737,6 +737,8 @@ private: bool findHeightfieldRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float boundsDistance, float& distance) const; + HeightfieldNode* subdivide(const QVector& heightContents, const QVector& stackContents) const; + HeightfieldHeightPointer _height; HeightfieldColorPointer _color; HeightfieldMaterialPointer _material; From f85774c687cf870675996bb764d9471c892d9b0d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 09:45:33 -0800 Subject: [PATCH 24/63] adding some debugging --- .../entities/src/EntityEditPacketSender.cpp | 5 +++ libraries/physics/src/EntityMotionState.cpp | 3 ++ libraries/physics/src/ObjectMotionState.cpp | 35 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index f2588d0493..a04e07ebb3 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -36,6 +36,11 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI int sizeOut = 0; if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, &bufferOut[0], _maxPacketSize, sizeOut)) { + #ifdef WANT_DEBUG + qDebug() << "calling queueOctreeEditMessage()..."; + qDebug() << " id:" << modelID; + qDebug() << " properties:" << properties; + #endif queueOctreeEditMessage(type, bufferOut, sizeOut); } } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 96897ff527..a6a358faa0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -227,6 +227,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); + #ifdef WANT_DEBUG + qDebug() << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; + #endif entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); // The outgoing flags only itemized WHAT to send, not WHETHER to send, hence we always set them diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index dfa059d47f..7e9c6b76b6 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -111,6 +111,12 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { _sentFrame = simulationFrame; return false; } + + #ifdef WANT_DEBUG + glm::vec3 wasPosition = _sentPosition; + glm::quat wasRotation = _sentRotation; + glm::vec3 wasAngularVelocity = _sentAngularVelocity; + #endif float dt = (float)(simulationFrame - _sentFrame) * PHYSICS_ENGINE_FIXED_SUBSTEP; _sentFrame = simulationFrame; @@ -147,11 +153,21 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { glm::vec3 position = bulletToGLM(worldTrans.getOrigin()); float dx2 = glm::distance2(position, _sentPosition); + const float MAX_POSITION_ERROR_SQUARED = 0.001f; // 0.001 m^2 ~~> 0.03 m if (dx2 > MAX_POSITION_ERROR_SQUARED) { + + #ifdef WANT_DEBUG + qDebug() << ".... (dx2 > MAX_POSITION_ERROR_SQUARED) ...."; + qDebug() << "wasPosition:" << wasPosition; + qDebug() << "bullet position:" << position; + qDebug() << "_sentPosition:" << _sentPosition; + qDebug() << "dx2:" << dx2; + #endif + return true; } - + if (glm::length2(_sentAngularVelocity) > 0.0f) { // compute rotation error _sentAngularVelocity *= powf(1.0f - _angularDamping, dt); @@ -165,6 +181,23 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationFrame) { } const float MIN_ROTATION_DOT = 0.98f; glm::quat actualRotation = bulletToGLM(worldTrans.getRotation()); + + #ifdef WANT_DEBUG + if ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) { + qDebug() << ".... ((fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT)) ...."; + + qDebug() << "wasAngularVelocity:" << wasAngularVelocity; + qDebug() << "_sentAngularVelocity:" << _sentAngularVelocity; + + qDebug() << "length wasAngularVelocity:" << glm::length(wasAngularVelocity); + qDebug() << "length _sentAngularVelocity:" << glm::length(_sentAngularVelocity); + + qDebug() << "wasRotation:" << wasRotation; + qDebug() << "bullet actualRotation:" << actualRotation; + qDebug() << "_sentRotation:" << _sentRotation; + } + #endif + return (fabsf(glm::dot(actualRotation, _sentRotation)) < MIN_ROTATION_DOT); } From 73b9c06ec08e2bc0a275ee62b0327addce7b2e41 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 11:13:30 -0800 Subject: [PATCH 25/63] added some debugging --- libraries/entities/src/EntityItem.cpp | 3 +++ libraries/entities/src/EntityItem.h | 3 ++- libraries/physics/src/EntityMotionState.cpp | 7 +++++++ libraries/physics/src/PhysicsEngine.cpp | 8 ++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 91aef39eea..3315cdd2e7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -21,6 +21,9 @@ #include "EntityItem.h" #include "EntityTree.h" +quint64 EntityItem::lastCollisionTime = 0; + + void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; _creatorTokenID = entityItemID.creatorTokenID; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index df619e2f69..ad540d1df9 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -42,7 +42,6 @@ class EntityTreeElementExtraEncodeData; /// one directly, instead you must only construct one of it's derived classes with additional features. class EntityItem { friend class EntityTreeElement; - public: enum EntityDirtyFlags { DIRTY_POSITION = 0x0001, @@ -55,6 +54,8 @@ public: DIRTY_UPDATEABLE = 0x0080, }; + static quint64 lastCollisionTime; + DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly EntityItem(const EntityItemID& entityItemID); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index a6a358faa0..02d7b77606 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -99,6 +99,13 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; EntityMotionState::enqueueOutgoingEntity(_entity); + + quint64 now = usecTimestampNow(); + qDebug() << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID(); + qDebug() << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago"; + qDebug() << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; + qDebug() << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; + qDebug() << " last collision:" << EntityItem::lastCollisionTime << formatUsecTime(now - EntityItem::lastCollisionTime) << "ago"; } void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index dfd28dd8a4..fce8faf301 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -371,10 +371,18 @@ void PhysicsEngine::computeCollisionEvents() { if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { idB = static_cast(B)->getEntity()->getEntityItemID(); } + +qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; +EntityItem::lastCollisionTime = usecTimestampNow(); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { EntityItemID idA; EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); + +qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; +EntityItem::lastCollisionTime = usecTimestampNow(); + emit entityCollisionWithEntity(idA, idB, contactItr->second); } From d26804e68cbe04904b6226499a941fce97a3d5f6 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Mon, 26 Jan 2015 13:45:14 -0600 Subject: [PATCH 26/63] Check just for http availability --- ice-server/src/IceServer.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 4648656e87..77deb6125b 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -173,23 +173,12 @@ void IceServer::clearInactivePeers() { bool IceServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) { // // We need an HTTP handler in order to monitor the health of the ice server - // The correct functioning of the ICE server will first be determined by its HTTP availability, - // and then by the existence of a minimum number of peers in the list, matching the minimum number of - // domains in production by High Fidelity. + // The correct functioning of the ICE server will be determined by its HTTP availability, // - int MINIMUM_PEERS = 3; - bool IS_HEALTHY = false; - - IS_HEALTHY = _activePeers.size() >= MINIMUM_PEERS ? true : false; - if (connection->requestOperation() == QNetworkAccessManager::GetOperation) { if (url.path() == "/status") { - if (IS_HEALTHY) { - connection->respond(HTTPConnection::StatusCode200, QByteArray::number(_activePeers.size())); - } else { - connection->respond(HTTPConnection::StatusCode404, QByteArray::number(_activePeers.size())); - } + connection->respond(HTTPConnection::StatusCode200, QByteArray::number(_activePeers.size())); } } return true; From 9aaa3a6fe46a97b7f9bb9a16310cfaf447521935 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 26 Jan 2015 11:48:44 -0800 Subject: [PATCH 27/63] Temporarily re-enable audio selection on Windows This is to test current behavior on different users' PCs before re-enabling permanently. --- interface/src/Audio.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index ce50e093e4..c7ba02700f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -118,7 +118,9 @@ void Audio::audioMixerKilled() { QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) { QAudioDeviceInfo result; -#ifdef WIN32 +// Temporarily enable audio device selection in Windows again to test how it behaves now +//#ifdef WIN32 +#if FALSE // NOTE // this is a workaround for a windows only QtBug https://bugreports.qt-project.org/browse/QTBUG-16117 // static QAudioDeviceInfo objects get deallocated when QList objects go out of scope From a1ec44b8e0aa5640e1e660775b18bf168417dcd6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 12:05:57 -0800 Subject: [PATCH 28/63] add developer menu item to disable sending physics updates --- .../utilities/tools/developerMenuItems.js | 20 +++++++++++++++++++ libraries/entities/src/EntityItem.cpp | 2 ++ libraries/entities/src/EntityItem.h | 7 +++++++ .../entities/src/EntityScriptingInterface.cpp | 9 +++++++++ .../entities/src/EntityScriptingInterface.h | 3 +++ libraries/physics/src/EntityMotionState.cpp | 16 +++++++++------ libraries/physics/src/EntityMotionState.h | 1 + 7 files changed, 52 insertions(+), 6 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 3a274c7083..765e85579e 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -18,6 +18,7 @@ function setupMenus() { } if (!Menu.menuExists("Developer > Entities")) { Menu.addMenu("Developer > Entities"); + /* Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Bounds", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Triangles", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Element Bounds", isCheckable: true, isChecked: false }); @@ -26,9 +27,28 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Attempt Render Entities as Scene", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); + */ + Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't send collision updates to server", isCheckable: true, isChecked: false }); } } +Menu.menuItemEvent.connect(function (menuItem) { + print("menuItemEvent() in JS... menuItem=" + menuItem); + + if (menuItem == "Don't send collision updates to server") { + var dontSendUpdates = Menu.isOptionChecked("Don't send collision updates to server"); + print(" dontSendUpdates... checked=" + dontSendUpdates); + Entities.setSendPhysicsUpdates(!dontSendUpdates); + } +}); + +setupMenus(); + +// register our scriptEnding callback +Script.scriptEnding.connect(scriptEnding); + + + function scriptEnding() { Menu.removeMenu("Developer > Entities"); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 3315cdd2e7..ab859c7282 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -22,6 +22,8 @@ #include "EntityTree.h" quint64 EntityItem::lastCollisionTime = 0; +bool EntityItem::_sendPhysicsUpdates = true; + void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ad540d1df9..1c35a0aa3d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -289,8 +289,15 @@ public: void setPhysicsInfo(void* data) { _physicsInfo = data; } EntityTreeElement* getElement() const { return _element; } + + static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } + static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } + + protected: + static bool _sendPhysicsUpdates; + virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init virtual void recalculateCollisionShape(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6226012052..599649aad0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -14,6 +14,7 @@ #include "LightEntityItem.h" #include "ModelEntityItem.h" + EntityScriptingInterface::EntityScriptingInterface() : _nextCreatorTokenID(0), _entityTree(NULL) @@ -234,6 +235,14 @@ bool EntityScriptingInterface::getLightsArePickable() const { return LightEntityItem::getLightsArePickable(); } +void EntityScriptingInterface::setSendPhysicsUpdates(bool value) { + EntityItem::setSendPhysicsUpdates(value); +} + +bool EntityScriptingInterface::getSendPhysicsUpdates() const { + return EntityItem::getSendPhysicsUpdates(); +} + RayToEntityIntersectionResult::RayToEntityIntersectionResult() : intersects(false), diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index e0fc721516..3585cce946 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -99,6 +99,9 @@ public slots: Q_INVOKABLE void setLightsArePickable(bool value); Q_INVOKABLE bool getLightsArePickable() const; + Q_INVOKABLE void setSendPhysicsUpdates(bool value); + Q_INVOKABLE bool getSendPhysicsUpdates() const; + Q_INVOKABLE void dumpTree() const; signals: diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 02d7b77606..c8b0133b86 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -232,12 +232,16 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ properties.setLastEdited(_entity->getLastEdited()); } - EntityItemID id(_entity->getID()); - EntityEditPacketSender* entityPacketSender = static_cast(packetSender); - #ifdef WANT_DEBUG - qDebug() << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; - #endif - entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + if (EntityItem::getSendPhysicsUpdates()) { + EntityItemID id(_entity->getID()); + EntityEditPacketSender* entityPacketSender = static_cast(packetSender); + #ifdef WANT_DEBUG + qDebug() << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; + #endif + entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + } else { + qDebug() << "EntityMotionState::sendUpdate()... NOT sending update as requested."; + } // The outgoing flags only itemized WHAT to send, not WHETHER to send, hence we always set them // to the full set. These flags may be momentarily cleared by incoming external changes. diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 5d98e545d9..5370f9ebb4 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -63,6 +63,7 @@ public: protected: EntityItem* _entity; + }; #endif // hifi_EntityMotionState_h From 08fbcbaf40e34a5b1227195eaff6a07e2e853462 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 12:38:02 -0800 Subject: [PATCH 29/63] tweaks for debugging --- examples/controllers/hydra/gun.js | 3 ++- libraries/physics/src/EntityMotionState.cpp | 20 ++++++++++++-------- libraries/physics/src/PhysicsEngine.cpp | 8 ++++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/controllers/hydra/gun.js b/examples/controllers/hydra/gun.js index 0c0740e12b..f3c1e14001 100644 --- a/examples/controllers/hydra/gun.js +++ b/examples/controllers/hydra/gun.js @@ -486,7 +486,8 @@ function mousePressEvent(event) { if (clickedOverlay == offButton) { Script.stop(); } else if (clickedOverlay == platformButton) { - makePlatform(-9.8, 1.0, 5); + var platformSize = 3; + makePlatform(-9.8, 1.0, platformSize); } else if (clickedOverlay == gridButton) { makeGrid("Box", 1.0, 3); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c8b0133b86..02a0dfbf92 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -99,13 +99,15 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; EntityMotionState::enqueueOutgoingEntity(_entity); - - quint64 now = usecTimestampNow(); - qDebug() << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID(); - qDebug() << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago"; - qDebug() << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; - qDebug() << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; - qDebug() << " last collision:" << EntityItem::lastCollisionTime << formatUsecTime(now - EntityItem::lastCollisionTime) << "ago"; + + #ifdef WANT_DEBUG + quint64 now = usecTimestampNow(); + qDebug() << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID(); + qDebug() << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago"; + qDebug() << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; + qDebug() << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; + qDebug() << " last collision:" << EntityItem::lastCollisionTime << formatUsecTime(now - EntityItem::lastCollisionTime) << "ago"; + #endif } void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t frame) { @@ -240,7 +242,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ #endif entityPacketSender->queueEditEntityMessage(PacketTypeEntityAddOrEdit, id, properties); } else { - qDebug() << "EntityMotionState::sendUpdate()... NOT sending update as requested."; + #ifdef WANT_DEBUG + qDebug() << "EntityMotionState::sendUpdate()... NOT sending update as requested."; + #endif } // The outgoing flags only itemized WHAT to send, not WHETHER to send, hence we always set them diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index fce8faf301..b427d78a69 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -372,16 +372,16 @@ void PhysicsEngine::computeCollisionEvents() { idB = static_cast(B)->getEntity()->getEntityItemID(); } -qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; -EntityItem::lastCollisionTime = usecTimestampNow(); +//qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; +//EntityItem::lastCollisionTime = usecTimestampNow(); emit entityCollisionWithEntity(idA, idB, contactItr->second); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { EntityItemID idA; EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); -qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; -EntityItem::lastCollisionTime = usecTimestampNow(); +//qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; +//EntityItem::lastCollisionTime = usecTimestampNow(); emit entityCollisionWithEntity(idA, idB, contactItr->second); } From 81185cfe5615ceecbc67eb0a89c8a203cdd1d692 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 12:46:22 -0800 Subject: [PATCH 30/63] removed some debugging --- libraries/entities/src/EntityItem.cpp | 3 --- libraries/entities/src/EntityItem.h | 2 -- libraries/physics/src/EntityMotionState.cpp | 1 - libraries/physics/src/PhysicsEngine.cpp | 8 -------- 4 files changed, 14 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ab859c7282..b987e37f3b 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -21,11 +21,8 @@ #include "EntityItem.h" #include "EntityTree.h" -quint64 EntityItem::lastCollisionTime = 0; bool EntityItem::_sendPhysicsUpdates = true; - - void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; _creatorTokenID = entityItemID.creatorTokenID; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 1c35a0aa3d..2cba4692d0 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -54,8 +54,6 @@ public: DIRTY_UPDATEABLE = 0x0080, }; - static quint64 lastCollisionTime; - DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly EntityItem(const EntityItemID& entityItemID); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 02a0dfbf92..01063a43d6 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -106,7 +106,6 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { qDebug() << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago"; qDebug() << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago"; qDebug() << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago"; - qDebug() << " last collision:" << EntityItem::lastCollisionTime << formatUsecTime(now - EntityItem::lastCollisionTime) << "ago"; #endif } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index b427d78a69..dfd28dd8a4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -371,18 +371,10 @@ void PhysicsEngine::computeCollisionEvents() { if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { idB = static_cast(B)->getEntity()->getEntityItemID(); } - -//qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; -//EntityItem::lastCollisionTime = usecTimestampNow(); - emit entityCollisionWithEntity(idA, idB, contactItr->second); } else if (B && B->getType() == MOTION_STATE_TYPE_ENTITY) { EntityItemID idA; EntityItemID idB = static_cast(B)->getEntity()->getEntityItemID(); - -//qDebug() << "entityCollisionWithEntity()... idA:" << idA << "idB:" << idB << "*******************************"; -//EntityItem::lastCollisionTime = usecTimestampNow(); - emit entityCollisionWithEntity(idA, idB, contactItr->second); } From d9835701b004467a6278ee10a79cc9fb8222a184 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 12:48:57 -0800 Subject: [PATCH 31/63] added comment --- examples/utilities/tools/developerMenuItems.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index 765e85579e..419285eeb9 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -18,6 +18,9 @@ function setupMenus() { } if (!Menu.menuExists("Developer > Entities")) { Menu.addMenu("Developer > Entities"); + + // NOTE: these menu items aren't currently working. I've temporarily removed them. Will add them back once we + // rewire these to work /* Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Bounds", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Display Model Triangles", isCheckable: true, isChecked: false }); @@ -47,8 +50,6 @@ setupMenus(); // register our scriptEnding callback Script.scriptEnding.connect(scriptEnding); - - function scriptEnding() { Menu.removeMenu("Developer > Entities"); } From 427840713732101eae349364e031d3bd3fa89ef2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Jan 2015 16:48:33 -0800 Subject: [PATCH 32/63] Account for avatar scale in Hand(Data) get/set When using localToWorld/WorldToLocal type functions --- interface/src/avatar/Hand.cpp | 4 ---- libraries/avatars/src/HandData.cpp | 10 +++++++--- libraries/avatars/src/HandData.h | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 0ea0d1b725..b477f606d7 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -171,10 +171,6 @@ void Hand::renderHandTargets(bool isMine) { glm::vec3 tip = palm.getTipPosition(); glm::vec3 root = palm.getPosition(); - //Scale the positions based on avatar scale - myAvatar->scaleVectorRelativeToPosition(tip); - myAvatar->scaleVectorRelativeToPosition(root); - Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS); // Render sphere at palm/finger root glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS; diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index b691bcc8ef..5d850d06d0 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -27,7 +27,7 @@ HandData::HandData(AvatarData* owningAvatar) : } glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const { - return glm::inverse(getBaseOrientation()) * worldVector; + return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale(); } PalmData& HandData::addNewPalm() { @@ -108,15 +108,19 @@ glm::quat HandData::getBaseOrientation() const { glm::vec3 HandData::getBasePosition() const { return _owningAvatarData->getPosition(); } + +float HandData::getBaseScale() const { + return _owningAvatarData->getTargetScale(); +} glm::vec3 PalmData::getFingerDirection() const { const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 0.0f, 1.0f); - return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION); + return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION)); } glm::vec3 PalmData::getNormal() const { const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, -1.0f, 0.0f); - return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION); + return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION)); } diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 8e44658faf..534ea67726 100644 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -36,11 +36,11 @@ public: // position conversion glm::vec3 localToWorldPosition(const glm::vec3& localPosition) { - return getBasePosition() + getBaseOrientation() * localPosition; + return getBasePosition() + getBaseOrientation() * localPosition * getBaseScale(); } glm::vec3 localToWorldDirection(const glm::vec3& localVector) { - return getBaseOrientation() * localVector; + return getBaseOrientation() * localVector * getBaseScale(); } glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const; @@ -71,6 +71,7 @@ protected: glm::quat getBaseOrientation() const; glm::vec3 getBasePosition() const; + float getBaseScale() const; private: // privatize copy ctor and assignment operator so copies of this object cannot be made From 4b3291d9468aac4dac6e0885b678fda87f8466fa Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Jan 2015 17:11:49 -0800 Subject: [PATCH 33/63] Some cleanup in hydraGrab.js --- examples/controllers/hydra/hydraGrab.js | 168 +++++++++++++++--------- 1 file changed, 106 insertions(+), 62 deletions(-) diff --git a/examples/controllers/hydra/hydraGrab.js b/examples/controllers/hydra/hydraGrab.js index 0c6e135739..5da296f117 100644 --- a/examples/controllers/hydra/hydraGrab.js +++ b/examples/controllers/hydra/hydraGrab.js @@ -14,13 +14,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("libraries/entityPropertyDialogBox.js"); +Script.include("../../libraries/entityPropertyDialogBox.js"); var entityPropertyDialogBox = EntityPropertyDialogBox; -var LASER_WIDTH = 4; -var LASER_COLOR = { red: 255, green: 0, blue: 0 }; -var LASER_LENGTH_FACTOR = 500; - var MIN_ANGULAR_SIZE = 2; var MAX_ANGULAR_SIZE = 45; var allowLargeModels = false; @@ -32,7 +28,44 @@ var RIGHT = 1; var jointList = MyAvatar.getJointNames(); -var mode = 0; +var STICKS = 0; +var MAPPED = 1; +var mode = STICKS; + +var LASER_WIDTH = 4; +var LASER_COLOR = [{ red: 200, green: 150, blue: 50 }, // STICKS + { red: 50, green: 150, blue: 200 }]; // MAPPED +var LASER_LENGTH_FACTOR = 500; + +var lastAccurateIntersection = null; +var accurateIntersections = 0; +var totalIntersections = 0; +var inaccurateInARow = 0; +var maxInaccurateInARow = 0; +function getRayIntersection(pickRay) { // pickRay : { origin : {xyz}, direction : {xyz} } + if (lastAccurateIntersection === null) { + lastAccurateIntersection = Entities.findRayIntersectionBlocking(pickRay); + } else { + var intersection = Entities.findRayIntersection(pickRay); + if (intersection.accurate) { + lastAccurateIntersection = intersection; + accurateIntersections++; + maxInaccurateInARow = (maxInaccurateInARow > inaccurateInARow) ? maxInaccurateInARow : inaccurateInARow; + inaccurateInARow = 0; + } else { + inaccurateInARow++; + } + totalIntersections++; + } + return lastAccurateIntersection; +} + +function printIntersectionsStats() { + var ratio = accurateIntersections / totalIntersections; + print("Out of " + totalIntersections + " intersections, " + accurateIntersections + " where accurate. (" + ratio * 100 +"%)"); + print("Worst case was " + maxInaccurateInARow + " inaccurate intersections in a row."); +} + function controller(wichSide) { this.side = wichSide; @@ -42,10 +75,10 @@ function controller(wichSide) { this.bumper = 6 * wichSide + 5; this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm); - this.palmPosition = Controller.getSpatialControlPosition(this.palm); + this.palmPosition = this.oldPalmPosition; this.oldTipPosition = Controller.getSpatialControlPosition(this.tip); - this.tipPosition = Controller.getSpatialControlPosition(this.tip); + this.tipPosition = this.oldTipPosition; this.oldUp = Controller.getSpatialControlNormal(this.palm); this.up = this.oldUp; @@ -81,7 +114,7 @@ function controller(wichSide) { this.laser = Overlays.addOverlay("line3d", { start: { x: 0, y: 0, z: 0 }, end: { x: 0, y: 0, z: 0 }, - color: LASER_COLOR, + color: LASER_COLOR[mode], alpha: 1, visible: false, lineWidth: LASER_WIDTH, @@ -245,9 +278,9 @@ function controller(wichSide) { var inverseRotation = Quat.inverse(MyAvatar.orientation); var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position)); + startPosition = Vec3.multiply(startPosition, 1 / MyAvatar.scale); var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition)); - var distance = Vec3.length(direction); - direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance); + direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / (Vec3.length(direction) * MyAvatar.scale)); var endPosition = Vec3.sum(startPosition, direction); Overlays.editOverlay(this.laser, { @@ -267,17 +300,16 @@ function controller(wichSide) { start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) }); - this.showLaser(!this.grabbing || mode == 0); + this.showLaser(!this.grabbing || mode == STICKS); if (this.glowedIntersectingModel.isKnownID) { Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 }); this.glowedIntersectingModel.isKnownID = false; } if (!this.grabbing) { - var intersection = Entities.findRayIntersectionBlocking({ - origin: this.palmPosition, - direction: this.front - }); + var intersection = getRayIntersection({ origin: this.palmPosition, + direction: this.front + }); var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0; @@ -304,17 +336,16 @@ function controller(wichSide) { if (this.grabbing) { if (!this.entityID.isKnownID) { print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); - this.entityID = Entities.findRayIntersectionBlocking({ - origin: this.palmPosition, - direction: this.front - }).entityID; + this.entityID = getRayIntersection({ origin: this.palmPosition, + direction: this.front + }).entityID; print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); } var newPosition; var newRotation; switch (mode) { - case 0: + case STICKS: newPosition = Vec3.sum(this.palmPosition, Vec3.multiply(this.front, this.x)); newPosition = Vec3.sum(newPosition, @@ -328,7 +359,7 @@ function controller(wichSide) { newRotation = Quat.multiply(newRotation, this.oldModelRotation); break; - case 1: + case MAPPED: var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); var d = Vec3.dot(forward, MyAvatar.position); @@ -397,15 +428,13 @@ function controller(wichSide) { var bumperValue = Controller.isButtonPressed(this.bumper); if (bumperValue && !this.bumperValue) { - if (mode == 0) { - mode = 1; - Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } }); - Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } }); - } else { - mode = 0; - Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } }); - Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } }); + if (mode === STICKS) { + mode = MAPPED; + } else if (mode === MAPPED) { + mode = STICKS; } + Overlays.editOverlay(leftController.laser, { color: LASER_COLOR[mode] }); + Overlays.editOverlay(rightController.laser, { color: LASER_COLOR[mode] }); } this.bumperValue = bumperValue; @@ -475,10 +504,10 @@ function controller(wichSide) { Vec3.print("Looking at: ", this.palmPosition); var pickRay = { origin: this.palmPosition, direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; - var foundIntersection = Entities.findRayIntersectionBlocking(pickRay); + var foundIntersection = getRayIntersection(pickRay); - if(!foundIntersection.accurate) { - print("No accurate intersection"); + if(!foundIntersection.intersects) { + print("No intersection"); return; } newModel = foundIntersection.entityID; @@ -526,7 +555,7 @@ function moveEntities() { switch (mode) { - case 0: + case STICKS: var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); @@ -545,7 +574,7 @@ function moveEntities() { newPosition = Vec3.sum(middle, Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); break; - case 1: + case MAPPED: var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); @@ -628,43 +657,56 @@ var glowedEntityID = { id: -1, isKnownID: false }; // In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already // exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that // added it. +var ROOT_MENU = "Edit"; +var ITEM_BEFORE = "Physics"; +var MENU_SEPARATOR = "Models"; +var EDIT_PROPERTIES = "Edit Properties..."; +var INTERSECTION_STATS = "Print Intersection Stats"; +var DELETE = "Delete"; +var LARGE_MODELS = "Allow Selecting of Large Models"; +var SMALL_MODELS = "Allow Selecting of Small Models"; + var LIGHTS = "Allow Selecting of Lights"; + var modelMenuAddedDelete = false; var originalLightsArePickable = Entities.getLightsArePickable(); function setupModelMenus() { print("setupModelMenus()"); // adj our menuitems - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", - shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); - if (!Menu.menuItemExists("Edit", "Delete")) { + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: MENU_SEPARATOR, isSeparator: true, beforeItem: ITEM_BEFORE }); + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: EDIT_PROPERTIES, + shortcutKeyEvent: { text: "`" }, afterItem: MENU_SEPARATOR }); + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: INTERSECTION_STATS, afterItem: MENU_SEPARATOR }); + if (!Menu.menuItemExists(ROOT_MENU, DELETE)) { print("no delete... adding ours"); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", - shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: DELETE, + shortcutKeyEvent: { text: "backspace" }, afterItem: MENU_SEPARATOR }); modelMenuAddedDelete = true; } else { print("delete exists... don't add ours"); } - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", - afterItem: "Paste Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", - afterItem: "Allow Selecting of Large Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", - afterItem: "Allow Selecting of Small Models", isCheckable: true }); + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LARGE_MODELS, shortcutKey: "CTRL+META+L", + afterItem: DELETE, isCheckable: true }); + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: SMALL_MODELS, shortcutKey: "CTRL+META+S", + afterItem: LARGE_MODELS, isCheckable: true }); + Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LIGHTS, shortcutKey: "CTRL+SHIFT+META+L", + afterItem: SMALL_MODELS, isCheckable: true }); Entities.setLightsArePickable(false); } function cleanupModelMenus() { - Menu.removeMenuItem("Edit", "Edit Properties..."); + Menu.removeSeparator(ROOT_MENU, MENU_SEPARATOR); + Menu.removeMenuItem(ROOT_MENU, EDIT_PROPERTIES); + Menu.removeMenuItem(ROOT_MENU, INTERSECTION_STATS); if (modelMenuAddedDelete) { // delete our menuitems - Menu.removeMenuItem("Edit", "Delete"); + Menu.removeMenuItem(ROOT_MENU, DELETE); } - Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); - Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); + Menu.removeMenuItem(ROOT_MENU, LARGE_MODELS); + Menu.removeMenuItem(ROOT_MENU, SMALL_MODELS); + Menu.removeMenuItem(ROOT_MENU, LIGHTS); } @@ -688,13 +730,13 @@ function showPropertiesForm(editModelID) { Menu.menuItemEvent.connect(function (menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == "Allow Selecting of Small Models") { - allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); - } else if (menuItem == "Allow Selecting of Large Models") { - allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); - } else if (menuItem == "Allow Selecting of Lights") { - Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); - } else if (menuItem == "Delete") { + if (menuItem == SMALL_MODELS) { + allowSmallModels = Menu.isOptionChecked(SMALL_MODELS); + } else if (menuItem == LARGE_MODELS) { + allowLargeModels = Menu.isOptionChecked(LARGE_MODELS); + } else if (menuItem == LIGHTS) { + Entities.setLightsArePickable(Menu.isOptionChecked(LIGHTS)); + } else if (menuItem == DELETE) { if (leftController.grabbing) { print(" Delete Entity.... leftController.entityID="+ leftController.entityID); Entities.deleteEntity(leftController.entityID); @@ -712,7 +754,7 @@ Menu.menuItemEvent.connect(function (menuItem) { } else { print(" Delete Entity.... not holding..."); } - } else if (menuItem == "Edit Properties...") { + } else if (menuItem == EDIT_PROPERTIES) { editModelID = -1; if (leftController.grabbing) { print(" Edit Properties.... leftController.entityID="+ leftController.entityID); @@ -727,16 +769,18 @@ Menu.menuItemEvent.connect(function (menuItem) { print(" Edit Properties.... about to edit properties..."); showPropertiesForm(editModelID); } + } else if (menuItem == INTERSECTION_STATS) { + printIntersectionsStats(); } }); Controller.keyReleaseEvent.connect(function (event) { // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items if (event.text == "`") { - handeMenuEvent("Edit Properties..."); + handeMenuEvent(EDIT_PROPERTIES); } if (event.text == "BACKSPACE") { - handeMenuEvent("Delete"); + handeMenuEvent(DELETE); } }); From 02c0700db326b6847bcab65cd75a56ccfda7847b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 17:25:06 -0800 Subject: [PATCH 34/63] support for skipping forward on new edit packets from server --- libraries/entities/src/EntityItem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index b987e37f3b..673f23e328 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -560,6 +560,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // server (clock skew adjusted). By setting it to "now" we are saying that the last position is to be // considered to be the correct position for "now" which is likely in the future from when it actually // was at that last known positition. + + float skipTimeForward = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); + qDebug() << "skipTimeForward:" << skipTimeForward; + simulateKinematicMotion(skipTimeForward); + //simulate(now); _lastSimulated = now; } } From 64f849568168faaa6c82b8f2782c8b2465b6f982 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Jan 2015 18:20:08 -0800 Subject: [PATCH 35/63] Fixed mapped rotation + doubled it --- examples/controllers/hydra/hydraGrab.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/controllers/hydra/hydraGrab.js b/examples/controllers/hydra/hydraGrab.js index 5da296f117..202a226f1e 100644 --- a/examples/controllers/hydra/hydraGrab.js +++ b/examples/controllers/hydra/hydraGrab.js @@ -108,7 +108,7 @@ function controller(wichSide) { this.positionAtGrab; this.rotationAtGrab; this.modelPositionAtGrab; - this.rotationAtGrab; + this.modelRotationAtGrab; this.jointsIntersectingFromStart = []; this.laser = Overlays.addOverlay("line3d", { @@ -165,7 +165,7 @@ function controller(wichSide) { this.positionAtGrab = this.palmPosition; this.rotationAtGrab = this.rotation; this.modelPositionAtGrab = properties.position; - this.rotationAtGrab = properties.rotation; + this.modelRotationAtGrab = properties.rotation; this.jointsIntersectingFromStart = []; for (var i = 0; i < jointList.length; i++) { var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); @@ -381,8 +381,9 @@ function controller(wichSide) { newRotation = Quat.multiply(this.rotation, Quat.inverse(this.rotationAtGrab)); + newRotation = Quat.multiply(newRotation, newRotation); newRotation = Quat.multiply(newRotation, - this.rotationAtGrab); + this.modelRotationAtGrab); break; } Entities.editEntity(this.entityID, { @@ -595,11 +596,11 @@ function moveEntities() { leftController.positionAtGrab = leftController.palmPosition; leftController.rotationAtGrab = leftController.rotation; leftController.modelPositionAtGrab = leftController.oldModelPosition; - leftController.rotationAtGrab = rotation; + leftController.modelRotationAtGrab = rotation; rightController.positionAtGrab = rightController.palmPosition; rightController.rotationAtGrab = rightController.rotation; rightController.modelPositionAtGrab = rightController.oldModelPosition; - rightController.rotationAtGrab = rotation; + rightController.modelRotationAtGrab = rotation; break; } Entities.editEntity(leftController.entityID, { From f84f6e9b667a942237fa16f13ea6c1ba4c8ad961 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Jan 2015 19:12:18 -0800 Subject: [PATCH 36/63] Restore joints state on stopAnimation --- libraries/render-utils/src/AnimationHandle.cpp | 11 +++++++++++ libraries/render-utils/src/AnimationHandle.h | 1 + 2 files changed, 12 insertions(+) diff --git a/libraries/render-utils/src/AnimationHandle.cpp b/libraries/render-utils/src/AnimationHandle.cpp index 30edf97a33..64e2bf28b9 100644 --- a/libraries/render-utils/src/AnimationHandle.cpp +++ b/libraries/render-utils/src/AnimationHandle.cpp @@ -74,6 +74,7 @@ void AnimationHandle::setRunning(bool running) { } } else { _model->_runningAnimations.removeOne(_self); + restoreJoints(); replaceMatchingPriorities(0.0f); } emit runningChanged(isRunning()); @@ -173,3 +174,13 @@ void AnimationHandle::replaceMatchingPriorities(float newPriority) { } } +void AnimationHandle::restoreJoints() { + for (int i = 0; i < _jointMappings.size(); i++) { + int mapping = _jointMappings.at(i); + if (mapping != -1) { + JointState& state = _model->_jointStates[mapping]; + state.restoreRotation(1.0f, state._animationPriority); + } + } +} + diff --git a/libraries/render-utils/src/AnimationHandle.h b/libraries/render-utils/src/AnimationHandle.h index 3956b01ebf..13a1b97dc1 100644 --- a/libraries/render-utils/src/AnimationHandle.h +++ b/libraries/render-utils/src/AnimationHandle.h @@ -92,6 +92,7 @@ private: void simulate(float deltaTime); void applyFrame(float frameIndex); void replaceMatchingPriorities(float newPriority); + void restoreJoints(); Model* _model; WeakAnimationHandlePointer _self; From cf631bf3fc106b6b330153494cbbb06b7332d1ac Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Jan 2015 19:20:47 -0800 Subject: [PATCH 37/63] Remove unnecessary stopAnimation in script to get rid of sacades --- examples/controllers/hydra/squeezeHands.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/controllers/hydra/squeezeHands.js b/examples/controllers/hydra/squeezeHands.js index 2a4756f017..b1e9274905 100644 --- a/examples/controllers/hydra/squeezeHands.js +++ b/examples/controllers/hydra/squeezeHands.js @@ -60,11 +60,9 @@ Script.update.connect(function(deltaTime) { } if ((leftFrame != lastLeftFrame) && leftHandAnimation.length){ - MyAvatar.stopAnimation(leftHandAnimation); MyAvatar.startAnimation(leftHandAnimation, 30.0, 1.0, false, true, leftFrame, leftFrame); } if ((rightFrame != lastRightFrame) && rightHandAnimation.length) { - MyAvatar.stopAnimation(rightHandAnimation); MyAvatar.startAnimation(rightHandAnimation, 30.0, 1.0, false, true, rightFrame, rightFrame); } From 83d1cc911a23f0d9f0addf705cf5de3cf8864c2b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 26 Jan 2015 19:38:24 -0800 Subject: [PATCH 38/63] hacking --- libraries/entities/src/EntityItem.cpp | 6 ++++-- libraries/physics/src/EntityMotionState.cpp | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 673f23e328..338009c280 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -562,8 +562,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // was at that last known positition. float skipTimeForward = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); - qDebug() << "skipTimeForward:" << skipTimeForward; - simulateKinematicMotion(skipTimeForward); + if (skipTimeForward > 0.0f) { + qDebug() << "skipTimeForward:" << skipTimeForward; + simulateKinematicMotion(skipTimeForward); + } //simulate(now); _lastSimulated = now; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 01063a43d6..3355f12b47 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -97,6 +97,8 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { // DANGER! EntityItem stores angularVelocity in degrees/sec!!! _entity->setAngularVelocity(glm::degrees(v)); + _entity->setLastSimulated(usecTimestampNow()); + _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; EntityMotionState::enqueueOutgoingEntity(_entity); From 1f6932bdcbec165cb5a89fa72ef5a1770b61eeed Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 08:09:20 -0800 Subject: [PATCH 39/63] Update TextureCache to store original image dimensions (pre-scale) --- libraries/render-utils/src/TextureCache.cpp | 10 ++++++++-- libraries/render-utils/src/TextureCache.h | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 4c9abc74a1..58032a0916 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -459,6 +459,9 @@ void ImageReader::run() { _reply->deleteLater(); } QImage image = QImage::fromData(_content); + + int originalWidth = image.width(); + int originalHeight = image.height(); // enforce a fixed maximum const int MAXIMUM_SIZE = 1024; @@ -519,7 +522,8 @@ void ImageReader::run() { } QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), Q_ARG(bool, translucentPixels >= imageArea / 2), Q_ARG(const QColor&, QColor(redTotal / imageArea, - greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea))); + greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea)), + Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); } void NetworkTexture::downloadFinished(QNetworkReply* reply) { @@ -531,9 +535,11 @@ void NetworkTexture::loadContent(const QByteArray& content) { QThreadPool::globalInstance()->start(new ImageReader(_self, NULL, _url, content)); } -void NetworkTexture::setImage(const QImage& image, bool translucent, const QColor& averageColor) { +void NetworkTexture::setImage(const QImage& image, bool translucent, const QColor& averageColor, int originalWidth, int originalHeight) { _translucent = translucent; _averageColor = averageColor; + _originalWidth = originalWidth; + _originalHeight = originalHeight; _width = image.width(); _height = image.height(); diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index efcccc4b8c..6d115223a2 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -150,6 +150,8 @@ public: /// Returns the lazily-computed average texture color. const QColor& getAverageColor() const { return _averageColor; } + int getOriginalWidth() const { return _originalWidth; } + int getOriginalHeight() const { return _originalHeight; } int getWidth() const { return _width; } int getHeight() const { return _height; } @@ -158,7 +160,7 @@ protected: virtual void downloadFinished(QNetworkReply* reply); Q_INVOKABLE void loadContent(const QByteArray& content); - Q_INVOKABLE void setImage(const QImage& image, bool translucent, const QColor& averageColor); + Q_INVOKABLE void setImage(const QImage& image, bool translucent, const QColor& averageColor, int originalWidth, int originalHeight); virtual void imageLoaded(const QImage& image); @@ -166,6 +168,8 @@ private: TextureType _type; bool _translucent; QColor _averageColor; + int _originalWidth; + int _originalHeight; int _width; int _height; }; From d27a26967fd53c00e405a3a9b20a4785c0d4c206 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 08:09:47 -0800 Subject: [PATCH 40/63] Update ImageOverlay to take texture rescaling into account --- interface/src/ui/overlays/ImageOverlay.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index e18f99072f..519e0c603d 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -93,6 +93,14 @@ void ImageOverlay::render(RenderArgs* args) { QRect fromImage; if (_wantClipFromImage) { fromImage = _fromImage; + float originalWidth = _texture->getOriginalWidth(); + float originalHeight = _texture->getOriginalHeight(); + float scaleX = imageWidth / originalWidth; + float scaleY = imageHeight / originalHeight; + fromImage.setX(scaleX * _fromImage.x()); + fromImage.setY(scaleY * _fromImage.y()); + fromImage.setWidth(scaleX * _fromImage.width()); + fromImage.setHeight(scaleY * _fromImage.height()); } else { fromImage.setX(0); fromImage.setY(0); From 6a9f135e1c5b743285aca48e5ffe69aba1428f7d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 08:11:37 -0800 Subject: [PATCH 41/63] Cleanup image clipping in ImageOverlay --- interface/src/ui/overlays/ImageOverlay.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 519e0c603d..0c5d9a7737 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -92,11 +92,9 @@ void ImageOverlay::render(RenderArgs* args) { QRect fromImage; if (_wantClipFromImage) { - fromImage = _fromImage; - float originalWidth = _texture->getOriginalWidth(); - float originalHeight = _texture->getOriginalHeight(); - float scaleX = imageWidth / originalWidth; - float scaleY = imageHeight / originalHeight; + float scaleX = imageWidth / _texture->getOriginalWidth(); + float scaleY = imageHeight / _texture->getOriginalHeight(); + fromImage.setX(scaleX * _fromImage.x()); fromImage.setY(scaleY * _fromImage.y()); fromImage.setWidth(scaleX * _fromImage.width()); From f085b81cdef2ed7cd08762a064ff57dec9cb5d54 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 10:10:10 -0800 Subject: [PATCH 42/63] Add specifics on env variable setting location --- BUILD_WIN.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 3ccc4881c1..cf1c60ee23 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -38,6 +38,7 @@ NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit Once Qt is installed, you need to manually configure the following: * Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.3.2\msvc2013_opengl\bin\`. +* Go to Control Panel > System > Advanced System Settings > Environment Variables > New ... * Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl` directory. ###External Libraries From 5f2cfc3cdeee56a8f6a090a6bf6c4c6e8277b241 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 27 Jan 2015 19:16:20 +0100 Subject: [PATCH 43/63] Update README.md default number of assignment-clients to start --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90f1ca0dc7..a4d193324d 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Any target can be terminated with Ctrl-C (SIGINT) in the associated Terminal win This assignment-client will grab one assignment from the domain-server. You can tell the assignment-client what type you want it to be with the `-t` option. You can also run an assignment-client that forks off *n* assignment-clients with the `-n` option. - ./assignment-client -n 6 + ./assignment-client -n 4 To test things out you'll want to run the Interface client. From 86f7c28ee93151d4f713a3540a913c040d00e3b9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 10:24:28 -0800 Subject: [PATCH 44/63] Update EntityScriptingInterface::deleteEntity to not delete when known entity is locked --- .../entities/src/EntityScriptingInterface.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6226012052..166e6d2819 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -144,15 +144,26 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) { } } + bool shouldDelete = true; + // If we have a local entity tree set, then also update it. if (_entityTree) { _entityTree->lockForWrite(); - _entityTree->deleteEntity(entityID); + + EntityItem* entity = const_cast(_entityTree->findEntityByEntityItemID(actualID)); + if (entity) { + if (entity->getLocked()) { + shouldDelete = false; + } else { + _entityTree->deleteEntity(entityID); + } + } + _entityTree->unlock(); } - // if at this point, we know the id, send the update to the entity server - if (entityID.isKnownID) { + // if at this point, we know the id, and we should still delete the entity, send the update to the entity server + if (shouldDelete && entityID.isKnownID) { getEntityPacketSender()->queueEraseEntityMessage(entityID); } } From f65640a5934401551b9ebc629a5e1348b3ee0c50 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 10:24:54 -0800 Subject: [PATCH 45/63] Update EntityTree.cpp to not delete entity when locked --- libraries/entities/src/EntityTree.cpp | 42 +++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 580fed8790..a0a8a33ca8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -229,6 +229,23 @@ void EntityTree::setSimulation(EntitySimulation* simulation) { } void EntityTree::deleteEntity(const EntityItemID& entityID) { + EntityTreeElement* containingElement = getContainingElement(entityID); + if (!containingElement) { + qDebug() << "UNEXPECTED!!!! EntityTree::deleteEntity() entityID doesn't exist!!! entityID=" << entityID; + return; + } + + EntityItem* existingEntity = containingElement->getEntityWithEntityItemID(entityID); + if (!existingEntity) { + qDebug() << "UNEXPECTED!!!! don't call EntityTree::deleteEntity() on entity items that don't exist. entityID=" << entityID; + return; + } + + if (existingEntity->getLocked()) { + qDebug() << "ERROR! EntityTree::deleteEntity() trying to delete locked entity. entityID=" << entityID; + return; + } + emit deletingEntity(entityID); // NOTE: callers must lock the tree before using this method @@ -242,14 +259,33 @@ void EntityTree::deleteEntities(QSet entityIDs) { // NOTE: callers must lock the tree before using this method DeleteEntityOperator theOperator(this); foreach(const EntityItemID& entityID, entityIDs) { + EntityTreeElement* containingElement = getContainingElement(entityID); + if (!containingElement) { + qDebug() << "UNEXPECTED!!!! EntityTree::deleteEntities() entityID doesn't exist!!! entityID=" << entityID; + continue; + } + + EntityItem* existingEntity = containingElement->getEntityWithEntityItemID(entityID); + if (!existingEntity) { + qDebug() << "UNEXPECTED!!!! don't call EntityTree::deleteEntities() on entity items that don't exist. entityID=" << entityID; + continue; + } + + if (existingEntity->getLocked()) { + qDebug() << "ERROR! EntityTree::deleteEntities() trying to delete locked entity. entityID=" << entityID; + continue; + } + // tell our delete operator about this entityID theOperator.addEntityIDToDeleteList(entityID); emit deletingEntity(entityID); } - recurseTreeWithOperator(&theOperator); - processRemovedEntities(theOperator); - _isDirty = true; + if (theOperator.getEntities().size() > 0) { + recurseTreeWithOperator(&theOperator); + processRemovedEntities(theOperator); + _isDirty = true; + } } void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) { From 9fd352e1dcf2cdc9137e99aafd42918e6c0f5e49 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 10:27:05 -0800 Subject: [PATCH 46/63] Break long lines in TextureCache.h/cpp --- libraries/render-utils/src/TextureCache.cpp | 3 ++- libraries/render-utils/src/TextureCache.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 58032a0916..372b4732f5 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -535,7 +535,8 @@ void NetworkTexture::loadContent(const QByteArray& content) { QThreadPool::globalInstance()->start(new ImageReader(_self, NULL, _url, content)); } -void NetworkTexture::setImage(const QImage& image, bool translucent, const QColor& averageColor, int originalWidth, int originalHeight) { +void NetworkTexture::setImage(const QImage& image, bool translucent, const QColor& averageColor, int originalWidth, + int originalHeight) { _translucent = translucent; _averageColor = averageColor; _originalWidth = originalWidth; diff --git a/libraries/render-utils/src/TextureCache.h b/libraries/render-utils/src/TextureCache.h index 6d115223a2..c4264b95f6 100644 --- a/libraries/render-utils/src/TextureCache.h +++ b/libraries/render-utils/src/TextureCache.h @@ -160,7 +160,8 @@ protected: virtual void downloadFinished(QNetworkReply* reply); Q_INVOKABLE void loadContent(const QByteArray& content); - Q_INVOKABLE void setImage(const QImage& image, bool translucent, const QColor& averageColor, int originalWidth, int originalHeight); + Q_INVOKABLE void setImage(const QImage& image, bool translucent, const QColor& averageColor, int originalWidth, + int originalHeight); virtual void imageLoaded(const QImage& image); From a012562323e95150eda54efcea47b806552b478b Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 10:52:15 -0800 Subject: [PATCH 47/63] Correct bullet link, change order of build guides --- BUILD.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index c86e34823c..9bd5da7c14 100644 --- a/BUILD.md +++ b/BUILD.md @@ -6,12 +6,12 @@ * [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g * IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability. * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3 -* [Bullet Physics Engine](http://bulletphysics.org) ~> 2.82 +* [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82 ### OS Specific Build Guides +* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows. * [BUILD_OSX.md](BUILD_OSX.md) - additional instructions for OS X. * [BUILD_LINUX.md](BUILD_LINUX.md) - additional instructions for Linux. -* [BUILD_WIN.md](BUILD_WIN.md) - additional instructions for Windows. ###CMake Hifi uses CMake to generate build files and project files for your platform. From 411541b8847053de355bdce7c7b905121e10f079 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Tue, 27 Jan 2015 11:04:50 -0800 Subject: [PATCH 48/63] Tidy up some scripts. Tidy up scripts. Make some changes to some script references and reorganize. --- .../RealSense}/realsenseHands.js | 0 examples/controllers/oculus/vrUI.js | 187 ++++++++++++++++++ examples/{ => example/games}/billiards.js | 0 examples/utilities/record/recorder.js | 2 +- 4 files changed, 188 insertions(+), 1 deletion(-) rename examples/{ => controllers/RealSense}/realsenseHands.js (100%) create mode 100644 examples/controllers/oculus/vrUI.js rename examples/{ => example/games}/billiards.js (100%) diff --git a/examples/realsenseHands.js b/examples/controllers/RealSense/realsenseHands.js similarity index 100% rename from examples/realsenseHands.js rename to examples/controllers/RealSense/realsenseHands.js diff --git a/examples/controllers/oculus/vrUI.js b/examples/controllers/oculus/vrUI.js new file mode 100644 index 0000000000..9586445980 --- /dev/null +++ b/examples/controllers/oculus/vrUI.js @@ -0,0 +1,187 @@ +// VR menu prototype +// David Rowe + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var vrChat = (function () { + + var background, + CHAT_YAW = -40.0, // Degrees + CHAT_DISTANCE = 0.6, + CHAT_HEIGHT = 0.35; + + function setUp() { + background = Overlays.addOverlay("rectangle3d", { + color: { red: 200, green: 200, blue: 200 }, + alpha: 0.5, + solid: true, + visible: false, + dimensions: { width: 0.3, height: 0.5 }, + ignoreRayIntersection: true, + isFacingAvatar: false + }); + } + + function show(on) { + Overlays.editOverlay(background, { visible: on }); + } + + function update() { + var CHAT_OFFSET = { x: 0.0, y: CHAT_HEIGHT, z: -CHAT_DISTANCE }, + chatRotation, + chatOffset; + + chatRotation = Quat.multiply(Quat.fromPitchYawRollDegrees(0.0, CHAT_YAW, 0.0), MyAvatar.orientation); + chatOffset = Vec3.multiplyQbyV(chatRotation, CHAT_OFFSET); + chatRotation = Quat.multiply(chatRotation, Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); + + Overlays.editOverlay(background, { + position: Vec3.sum(MyAvatar.position, chatOffset), + rotation: chatRotation + }); + } + + function tearDown() { + Overlays.deleteOverlay(background); + } + + return { + setUp: setUp, + show: show, + update: update, + tearDown: tearDown + }; + +}()); + + +var vrMenu = (function () { + + var menuItems = [], + menuVisible = false, + MENU_HEIGHT = 0.7, + MENU_RADIUS = 0.6, + ITEM_SPACING = 12.0, // Degrees + IMAGE_WIDTH = 160, + IMAGE_HEIGHT = 100, + IMAGE_SCALE = 0.1, + NUMBER_OF_BUTTONS = 10; + + function setVisible(visible) { + var i; + + menuVisible = visible; + + for (i = 0; i < menuItems.length; i += 1) { + Overlays.editOverlay(menuItems[i].overlay, { visible: menuVisible }); + } + } + + function keyPressEvent(event) { + if (event.text.toLowerCase() === "o") { + setVisible(!menuVisible); + } + } + + function mousePressEvent(event) { + var pickRay, + intersection, + subImage = { x: 0, y: IMAGE_HEIGHT, width: IMAGE_WIDTH, height: IMAGE_HEIGHT }, + i; + + pickRay = Camera.computePickRay(event.x, event.y); + intersection = Overlays.findRayIntersection(pickRay); + + if (intersection.intersects) { + for (i = 0; i < menuItems.length; i += 1) { + if (intersection.overlayID === menuItems[i].overlay) { + menuItems[i].on = !menuItems[i].on; + subImage.y = (menuItems[i].on ? 0 : 1) * IMAGE_HEIGHT; + Overlays.editOverlay(menuItems[i].overlay, { subImage: subImage }); + if (menuItems[i].callback) { + menuItems[i].callback(menuItems[i].on); + } + } + } + } + } + + function setUp() { + var overlay, + menuItem, + i; + + for (i = 0; i < NUMBER_OF_BUTTONS; i += 1) { + overlay = Overlays.addOverlay("billboard", { + url: "http://ctrlaltstudio.com/hifi/menu-blank.svg", + subImage: { x: 0, y: IMAGE_HEIGHT, width: IMAGE_WIDTH, height: IMAGE_HEIGHT }, + alpha: 1.0, + visible: false, + scale: IMAGE_SCALE, + isFacingAvatar: false + }); + + menuItem = { + overlay: overlay, + on: false, + callback: null + }; + + menuItems.push(menuItem); + } + + Overlays.editOverlay(menuItems[NUMBER_OF_BUTTONS - 2].overlay, { + url: "http://ctrlaltstudio.com/hifi/menu-chat.svg" + }); + menuItems[NUMBER_OF_BUTTONS - 2].callback = vrChat.show; + + Controller.keyPressEvent.connect(keyPressEvent); + Controller.mousePressEvent.connect(mousePressEvent); + } + + function update() { + var MENU_OFFSET = { x: 0.0, y: MENU_HEIGHT, z: -MENU_RADIUS }, // Offset from avatar position. + itemAngle, + itemRotation, + itemOffset, + i; + + itemAngle = menuItems.length * ITEM_SPACING / 2.0; + + for (i = 0; i < menuItems.length; i += 1) { + + itemRotation = Quat.multiply(Quat.fromPitchYawRollDegrees(0.0, itemAngle, 0.0), MyAvatar.orientation); + itemOffset = Vec3.multiplyQbyV(itemRotation, MENU_OFFSET); + + Overlays.editOverlay(menuItems[i].overlay, { + position: Vec3.sum(MyAvatar.position, itemOffset), + rotation: itemRotation + }); + + itemAngle -= ITEM_SPACING; + } + } + + function tearDown() { + var i; + + for (i = 0; i < menuItems.length; i += 1) { + Overlays.deleteOverlay(menuItems[i].overlay); + } + } + + return { + setUp: setUp, + update: update, + tearDown: tearDown + }; + +}()); + +vrChat.setUp(); +Script.update.connect(vrChat.update); +Script.scriptEnding.connect(vrChat.tearDown); + +vrMenu.setUp(); +Script.update.connect(vrMenu.update); +Script.scriptEnding.connect(vrMenu.tearDown); \ No newline at end of file diff --git a/examples/billiards.js b/examples/example/games/billiards.js similarity index 100% rename from examples/billiards.js rename to examples/example/games/billiards.js diff --git a/examples/utilities/record/recorder.js b/examples/utilities/record/recorder.js index f3f46adf1a..495a862db1 100644 --- a/examples/utilities/record/recorder.js +++ b/examples/utilities/record/recorder.js @@ -10,7 +10,7 @@ // HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; -Script.include("libraries/toolBars.js"); +Script.include("../../libraries/toolBars.js"); var recordingFile = "recording.rec"; From 45dbff67f8099a832f508a80e29bb0dc667edb61 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 27 Jan 2015 11:15:33 -0800 Subject: [PATCH 49/63] more hacking --- libraries/entities/src/BoxEntityItem.cpp | 9 ++++ libraries/entities/src/BoxEntityItem.h | 2 + libraries/entities/src/EntityItem.cpp | 58 +++++++++++++-------- libraries/entities/src/EntityItem.h | 4 ++ libraries/entities/src/SphereEntityItem.cpp | 11 ++++ libraries/entities/src/SphereEntityItem.h | 2 + libraries/physics/src/EntityMotionState.cpp | 8 ++- 7 files changed, 71 insertions(+), 23 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 88e1a4b6b1..25ef2e6aaf 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -101,3 +101,12 @@ void BoxEntityItem::computeShapeInfo(ShapeInfo& info) const { info.setBox(halfExtents); } +void BoxEntityItem::debugDump() const { + quint64 now = usecTimestampNow(); + qDebug() << " BOX EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qDebug() << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; + qDebug() << " position:" << debugTreeVector(_position); + qDebug() << " dimensions:" << debugTreeVector(_dimensions); + qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now); +} + diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index 3ce67369ee..8d68a13158 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -53,6 +53,8 @@ public: void computeShapeInfo(ShapeInfo& info) const; + virtual void debugDump() const; + protected: rgbColor _color; }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 338009c280..0ebab1f19c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -380,7 +380,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef float editedAgo = getEditedAgo(); QString agoAsString = formatSecondsElapsed(editedAgo); QString ageAsString = formatSecondsElapsed(getAge()); + qDebug() << "------------------------------------------"; qDebug() << "Loading entity " << getEntityItemID() << " from buffer..."; + qDebug() << "------------------------------------------"; + debugDump(); + qDebug() << "------------------------------------------"; qDebug() << " _created =" << _created; qDebug() << " age=" << getAge() << "seconds - " << ageAsString; qDebug() << " lastEdited =" << lastEdited; @@ -402,19 +406,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime); - if (wantDebug) { + if (true || wantDebug) { qDebug() << "data from server **************** "; - qDebug() << " entityItemID=" << getEntityItemID(); - qDebug() << " now=" << now; - qDebug() << " getLastEdited()=" << getLastEdited(); - qDebug() << " lastEditedFromBuffer=" << lastEditedFromBuffer << " (BEFORE clockskew adjust)"; - qDebug() << " clockSkew=" << clockSkew; - qDebug() << " lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted << " (AFTER clockskew adjust)"; - qDebug() << " _lastEditedFromRemote=" << _lastEditedFromRemote - << " (our local time the last server edit we accepted)"; - qDebug() << " _lastEditedFromRemoteInRemoteTime=" << _lastEditedFromRemoteInRemoteTime - << " (remote time the last server edit we accepted)"; - qDebug() << " fromSameServerEdit=" << fromSameServerEdit; + qDebug() << " entityItemID:" << getEntityItemID(); + qDebug() << " now:" << now; + qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now); + qDebug() << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now); + qDebug() << " clockSkew:" << debugTimeOnly(clockSkew); + qDebug() << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); + qDebug() << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now); + qDebug() << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now); + qDebug() << " fromSameServerEdit:" << fromSameServerEdit; } bool ignoreServerPacket = false; // assume we'll use this server packet @@ -438,13 +440,15 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (ignoreServerPacket) { overwriteLocalData = false; - if (wantDebug) { + if (true || wantDebug) { qDebug() << "IGNORING old data from server!!! ****************"; + debugDump(); } } else { - if (wantDebug) { + if (true || wantDebug) { qDebug() << "USING NEW data from server!!! ****************"; + debugDump(); } // don't allow _lastEdited to be in the future @@ -464,9 +468,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (overwriteLocalData) { _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that if (wantDebug) { - qDebug() << "_lastUpdated =" << _lastUpdated; - qDebug() << "_lastEdited=" << _lastEdited; - qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted; + qDebug() << " _lastUpdated:" << debugTime(_lastUpdated, now); + qDebug() << " _lastEdited:" << debugTime(_lastEdited, now); + qDebug() << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); } } encodedUpdateDelta = updateDeltaCoder; // determine true length @@ -482,15 +486,25 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (overwriteLocalData) { _lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that if (wantDebug) { - qDebug() << "_lastSimulated =" << _lastSimulated; - qDebug() << "_lastEdited=" << _lastEdited; - qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted; + qDebug() << " _lastSimulated:" << debugTime(_lastSimulated, now); + qDebug() << " _lastEdited:" << debugTime(_lastEdited, now); + qDebug() << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); } } encodedSimulatedDelta = simulatedDeltaCoder; // determine true length dataAt += encodedSimulatedDelta.size(); bytesRead += encodedSimulatedDelta.size(); - } + } + + #if 1 //def WANT_DEBUG + if (overwriteLocalData) { + qDebug() << "EntityItem::readEntityDataFromBuffer()... changed entity:" << getEntityItemID(); + qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now); + qDebug() << " getLastSimulated:" << debugTime(getLastSimulated(), now); + qDebug() << " getLastUpdated:" << debugTime(getLastUpdated(), now); + } + #endif + // Property Flags QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size @@ -592,7 +606,7 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime)); quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew; memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime)); - const bool wantDebug = false; + const bool wantDebug = true; if (wantDebug) { qDebug("EntityItem::adjustEditPacketForClockSkew()..."); qDebug() << " lastEditedInLocalTime: " << lastEditedInLocalTime; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 2cba4692d0..58dc391458 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -36,6 +36,10 @@ class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; +#define debugTime(T, N) qPrintable(QString("%1 [ %2 ago]").arg(T, 16, 10).arg(formatUsecTime(N - T), 15)) +#define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) +#define debugTreeVector(V) V << "[" << (V * (float)TREE_SCALE) << " in meters ]" + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 7f3d619e03..181e5851f6 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -132,3 +132,14 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons } return false; } + + +void SphereEntityItem::debugDump() const { + quint64 now = usecTimestampNow(); + qDebug() << "SHPERE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qDebug() << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; + qDebug() << " position:" << debugTreeVector(_position); + qDebug() << " dimensions:" << debugTreeVector(_dimensions); + qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now); +} + diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index c81f80d9ab..f76c9f5600 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -63,6 +63,8 @@ public: bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; + virtual void debugDump() const; + protected: virtual void recalculateCollisionShape(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 3355f12b47..01d9162314 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -228,9 +228,15 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // we only update lastEdited when we're sending new physics data // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly - quint64 lastSimulated = _entity->getLastSimulated(); + quint64 now = usecTimestampNow(); + quint64 lastSimulated = _entity->getLastSimulated(); // or now??? _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); + + qDebug() << "EntityMotionState::sendUpdate()"; + qDebug() << " EntityItemId:" << _entity->getEntityItemID() << "---------------------------------------------"; + qDebug() << " lastSimulated:" << debugTime(lastSimulated, now); + } else { properties.setLastEdited(_entity->getLastEdited()); } From 2556b4790b8d37c93355337e3b020348a9020773 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 11:28:20 -0800 Subject: [PATCH 50/63] Update inspect.js to not activate if camera is in independent mode --- examples/inspect.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/inspect.js b/examples/inspect.js index ff0925db97..d730a7e53f 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -158,6 +158,11 @@ function handleModes() { avatarOrientation.w != MyAvatar.orientation.w)) { newMode = noMode; } + + if (mode == noMode && newMode != noMode && Camera.mode == "independent") { + newMode = noMode; + } + // if leaving noMode if (mode == noMode && newMode != noMode) { saveCameraState(); From 80002551f92332bcf7c99b214da4c6c1c56f165b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 11:28:39 -0800 Subject: [PATCH 51/63] Update editEntities camera to not enable if camera is in independent mode --- examples/libraries/entityCameraTool.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index b9170dc25d..f5095bb149 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -80,7 +80,8 @@ CameraManager = function() { that.lastMousePosition = { x: 0, y: 0 }; that.enable = function() { - if (that.enabled) return; + if (Camera.mode == "independent" || that.enabled) return; + that.enabled = true; that.mode = MODE_INACTIVE; From b1586d4f904420470a77cc900dd9c5dcb9f2b4b5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 27 Jan 2015 11:29:17 -0800 Subject: [PATCH 52/63] move debug into ifdef --- libraries/entities/src/EntityItem.cpp | 106 ++++++-------------- libraries/physics/src/EntityMotionState.cpp | 10 +- 2 files changed, 38 insertions(+), 78 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0ebab1f19c..86e116bf9f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -167,13 +167,12 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet quint64 lastEdited = getLastEdited(); - const bool wantDebug = false; - if (wantDebug) { + #ifdef WANT_DEBUG float editedAgo = getEditedAgo(); QString agoAsString = formatSecondsElapsed(editedAgo); qDebug() << "Writing entity " << getEntityItemID() << " to buffer, lastEdited =" << lastEdited << " ago=" << editedAgo << "seconds - " << agoAsString; - } + #endif bool successIDFits = false; bool successTypeFits = false; @@ -227,11 +226,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, getDimensions()); // NOTE: PROP_RADIUS obsolete - - if (wantDebug) { - qDebug() << " APPEND_ENTITY_PROPERTY() PROP_DIMENSIONS:" << getDimensions(); - } - APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation()); APPEND_ENTITY_PROPERTY(PROP_DENSITY, appendValue, getDensity()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity()); @@ -310,7 +304,6 @@ int EntityItem::expectedBytes() { int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { - bool wantDebug = false; if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) { @@ -375,7 +368,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef _created = createdFromBuffer; } - if (wantDebug) { + #ifdef WANT_DEBUG quint64 lastEdited = getLastEdited(); float editedAgo = getEditedAgo(); QString agoAsString = formatSecondsElapsed(editedAgo); @@ -389,7 +382,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qDebug() << " age=" << getAge() << "seconds - " << ageAsString; qDebug() << " lastEdited =" << lastEdited; qDebug() << " ago=" << editedAgo << "seconds - " << agoAsString; - } + #endif quint64 lastEditedFromBuffer = 0; quint64 lastEditedFromBufferAdjusted = 0; @@ -406,7 +399,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime); - if (true || wantDebug) { + #ifdef WANT_DEBUG qDebug() << "data from server **************** "; qDebug() << " entityItemID:" << getEntityItemID(); qDebug() << " now:" << now; @@ -417,7 +410,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef qDebug() << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now); qDebug() << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now); qDebug() << " fromSameServerEdit:" << fromSameServerEdit; - } + #endif bool ignoreServerPacket = false; // assume we'll use this server packet @@ -440,16 +433,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (ignoreServerPacket) { overwriteLocalData = false; - if (true || wantDebug) { + #ifdef WANT_DEBUG qDebug() << "IGNORING old data from server!!! ****************"; debugDump(); - } + #endif } else { - if (true || wantDebug) { + #ifdef WANT_DEBUG qDebug() << "USING NEW data from server!!! ****************"; debugDump(); - } + #endif // don't allow _lastEdited to be in the future _lastEdited = lastEditedFromBufferAdjusted; @@ -467,11 +460,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 updateDelta = updateDeltaCoder; if (overwriteLocalData) { _lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << " _lastUpdated:" << debugTime(_lastUpdated, now); qDebug() << " _lastEdited:" << debugTime(_lastEdited, now); qDebug() << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); - } + #endif } encodedUpdateDelta = updateDeltaCoder; // determine true length dataAt += encodedUpdateDelta.size(); @@ -485,18 +478,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef quint64 simulatedDelta = simulatedDeltaCoder; if (overwriteLocalData) { _lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << " _lastSimulated:" << debugTime(_lastSimulated, now); qDebug() << " _lastEdited:" << debugTime(_lastEdited, now); qDebug() << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now); - } + #endif } encodedSimulatedDelta = simulatedDeltaCoder; // determine true length dataAt += encodedSimulatedDelta.size(); bytesRead += encodedSimulatedDelta.size(); } - #if 1 //def WANT_DEBUG + #ifdef WANT_DEBUG if (overwriteLocalData) { qDebug() << "EntityItem::readEntityDataFromBuffer()... changed entity:" << getEntityItemID(); qDebug() << " getLastEdited:" << debugTime(getLastEdited(), now); @@ -524,23 +517,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef if (overwriteLocalData) { setRadius(fromBuffer); } - - if (wantDebug) { - qDebug() << " readEntityDataFromBuffer() OLD FORMAT... found PROP_RADIUS"; - } - } } else { READ_ENTITY_PROPERTY_SETTER(PROP_DIMENSIONS, glm::vec3, setDimensions); - if (wantDebug) { - qDebug() << " readEntityDataFromBuffer() NEW FORMAT... look for PROP_DIMENSIONS"; - } } - if (wantDebug) { - qDebug() << " readEntityDataFromBuffer() _dimensions:" << getDimensionsInMeters() << " in meters"; - } - READ_ENTITY_PROPERTY_QUAT_SETTER(PROP_ROTATION, updateRotation); READ_ENTITY_PROPERTY_SETTER(PROP_DENSITY, float, updateDensity); READ_ENTITY_PROPERTY_SETTER(PROP_VELOCITY, glm::vec3, updateVelocity); @@ -557,13 +538,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA,setUserData); - if (wantDebug) { - qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint; - qDebug() << " readEntityDataFromBuffer() _visible:" << _visible; - qDebug() << " readEntityDataFromBuffer() _ignoreForCollisions:" << _ignoreForCollisions; - qDebug() << " readEntityDataFromBuffer() _collisionsWillMove:" << _collisionsWillMove; - } - bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); recalculateCollisionShape(); @@ -577,10 +551,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef float skipTimeForward = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); if (skipTimeForward > 0.0f) { - qDebug() << "skipTimeForward:" << skipTimeForward; + #ifdef WANT_DEBUG + qDebug() << "skipTimeForward:" << skipTimeForward; + #endif simulateKinematicMotion(skipTimeForward); } - //simulate(now); _lastSimulated = now; } } @@ -606,13 +581,12 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime)); quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew; memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime)); - const bool wantDebug = true; - if (wantDebug) { + #ifdef WANT_DEBUG qDebug("EntityItem::adjustEditPacketForClockSkew()..."); qDebug() << " lastEditedInLocalTime: " << lastEditedInLocalTime; qDebug() << " clockSkew: " << clockSkew; qDebug() << " lastEditedInServerTime: " << lastEditedInServerTime; - } + #endif } float EntityItem::computeMass() const { @@ -667,15 +641,13 @@ bool EntityItem::isRestingOnSurface() const { } void EntityItem::simulate(const quint64& now) { - bool wantDebug = false; - if (_lastSimulated == 0) { _lastSimulated = now; } float timeElapsed = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << "********** EntityItem::simulate()"; qDebug() << " entity ID=" << getEntityItemID(); qDebug() << " now=" << now; @@ -710,27 +682,23 @@ void EntityItem::simulate(const quint64& now) { qDebug() << " getAge()=" << getAge(); qDebug() << " getLifetime()=" << getLifetime(); } - } - - if (wantDebug) { qDebug() << " ********** EntityItem::simulate() .... SETTING _lastSimulated=" << _lastSimulated; - } + #endif simulateKinematicMotion(timeElapsed); _lastSimulated = now; } void EntityItem::simulateKinematicMotion(float timeElapsed) { - bool wantDebug = false; if (hasAngularVelocity()) { // angular damping glm::vec3 angularVelocity = getAngularVelocity(); if (_angularDamping > 0.0f) { angularVelocity *= powf(1.0f - _angularDamping, timeElapsed); - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << " angularDamping :" << _angularDamping; qDebug() << " newAngularVelocity:" << angularVelocity; - } + #endif setAngularVelocity(angularVelocity); } @@ -758,19 +726,19 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { glm::vec3 velocity = getVelocity(); if (_damping > 0.0f) { velocity *= powf(1.0f - _damping, timeElapsed); - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << " damping:" << _damping; qDebug() << " velocity AFTER dampingResistance:" << velocity; qDebug() << " glm::length(velocity):" << glm::length(velocity); qDebug() << " velocityEspilon :" << ENTITY_ITEM_EPSILON_VELOCITY_LENGTH; - } + #endif } // integrate position forward glm::vec3 position = getPosition(); glm::vec3 newPosition = position + (velocity * timeElapsed); - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << " EntityItem::simulate()...."; qDebug() << " timeElapsed:" << timeElapsed; qDebug() << " old AACube:" << getMaximumAACube(); @@ -780,7 +748,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; qDebug() << " newPosition:" << newPosition; qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); - } + #endif position = newPosition; @@ -803,12 +771,12 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) { setVelocity(velocity); } - if (wantDebug) { + #ifdef WANT_DEBUG qDebug() << " new position:" << position; qDebug() << " new velocity:" << velocity; qDebug() << " new AACube:" << getMaximumAACube(); qDebug() << " old getAABox:" << getAABox(); - } + #endif } } @@ -882,13 +850,12 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed - bool wantDebug = false; uint64_t now = usecTimestampNow(); - if (wantDebug) { + #ifdef WANT_DEBUG int elapsed = now - getLastEdited(); qDebug() << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed << "now=" << now << " getLastEdited()=" << getLastEdited(); - } + #endif if (_created != UNKNOWN_CREATED_TIME) { setLastEdited(now); } @@ -1030,15 +997,6 @@ void EntityItem::setRadius(float value) { float diameter = value * 2.0f; float maxDimension = sqrt((diameter * diameter) / 3.0f); _dimensions = glm::vec3(maxDimension, maxDimension, maxDimension); - - bool wantDebug = false; - if (wantDebug) { - qDebug() << "EntityItem::setRadius()..."; - qDebug() << " radius:" << value; - qDebug() << " diameter:" << diameter; - qDebug() << " maxDimension:" << maxDimension; - qDebug() << " _dimensions:" << _dimensions; - } } // TODO: get rid of all users of this function... diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 01d9162314..6283229dea 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -228,14 +228,16 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // we only update lastEdited when we're sending new physics data // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly - quint64 now = usecTimestampNow(); quint64 lastSimulated = _entity->getLastSimulated(); // or now??? _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); - qDebug() << "EntityMotionState::sendUpdate()"; - qDebug() << " EntityItemId:" << _entity->getEntityItemID() << "---------------------------------------------"; - qDebug() << " lastSimulated:" << debugTime(lastSimulated, now); + #ifdef WANT_DEBUG + quint64 now = usecTimestampNow(); + qDebug() << "EntityMotionState::sendUpdate()"; + qDebug() << " EntityItemId:" << _entity->getEntityItemID() << "---------------------------------------------"; + qDebug() << " lastSimulated:" << debugTime(lastSimulated, now); + #endif //def WANT_DEBUG } else { properties.setLastEdited(_entity->getLastEdited()); From 94e04e2d7d1a5299d91a321e75354826714e1987 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 27 Jan 2015 11:34:46 -0800 Subject: [PATCH 53/63] removed extra whitespace --- libraries/physics/src/EntityMotionState.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 5370f9ebb4..5d98e545d9 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -63,7 +63,6 @@ public: protected: EntityItem* _entity; - }; #endif // hifi_EntityMotionState_h From 283a056a43963b2fd484c18a68c83be841b2f024 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Tue, 27 Jan 2015 11:37:31 -0800 Subject: [PATCH 54/63] remove VRui remove VRui --- examples/controllers/oculus/vrUI.js | 187 ---------------------------- 1 file changed, 187 deletions(-) delete mode 100644 examples/controllers/oculus/vrUI.js diff --git a/examples/controllers/oculus/vrUI.js b/examples/controllers/oculus/vrUI.js deleted file mode 100644 index 9586445980..0000000000 --- a/examples/controllers/oculus/vrUI.js +++ /dev/null @@ -1,187 +0,0 @@ -// VR menu prototype -// David Rowe - -HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; - -var vrChat = (function () { - - var background, - CHAT_YAW = -40.0, // Degrees - CHAT_DISTANCE = 0.6, - CHAT_HEIGHT = 0.35; - - function setUp() { - background = Overlays.addOverlay("rectangle3d", { - color: { red: 200, green: 200, blue: 200 }, - alpha: 0.5, - solid: true, - visible: false, - dimensions: { width: 0.3, height: 0.5 }, - ignoreRayIntersection: true, - isFacingAvatar: false - }); - } - - function show(on) { - Overlays.editOverlay(background, { visible: on }); - } - - function update() { - var CHAT_OFFSET = { x: 0.0, y: CHAT_HEIGHT, z: -CHAT_DISTANCE }, - chatRotation, - chatOffset; - - chatRotation = Quat.multiply(Quat.fromPitchYawRollDegrees(0.0, CHAT_YAW, 0.0), MyAvatar.orientation); - chatOffset = Vec3.multiplyQbyV(chatRotation, CHAT_OFFSET); - chatRotation = Quat.multiply(chatRotation, Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); - - Overlays.editOverlay(background, { - position: Vec3.sum(MyAvatar.position, chatOffset), - rotation: chatRotation - }); - } - - function tearDown() { - Overlays.deleteOverlay(background); - } - - return { - setUp: setUp, - show: show, - update: update, - tearDown: tearDown - }; - -}()); - - -var vrMenu = (function () { - - var menuItems = [], - menuVisible = false, - MENU_HEIGHT = 0.7, - MENU_RADIUS = 0.6, - ITEM_SPACING = 12.0, // Degrees - IMAGE_WIDTH = 160, - IMAGE_HEIGHT = 100, - IMAGE_SCALE = 0.1, - NUMBER_OF_BUTTONS = 10; - - function setVisible(visible) { - var i; - - menuVisible = visible; - - for (i = 0; i < menuItems.length; i += 1) { - Overlays.editOverlay(menuItems[i].overlay, { visible: menuVisible }); - } - } - - function keyPressEvent(event) { - if (event.text.toLowerCase() === "o") { - setVisible(!menuVisible); - } - } - - function mousePressEvent(event) { - var pickRay, - intersection, - subImage = { x: 0, y: IMAGE_HEIGHT, width: IMAGE_WIDTH, height: IMAGE_HEIGHT }, - i; - - pickRay = Camera.computePickRay(event.x, event.y); - intersection = Overlays.findRayIntersection(pickRay); - - if (intersection.intersects) { - for (i = 0; i < menuItems.length; i += 1) { - if (intersection.overlayID === menuItems[i].overlay) { - menuItems[i].on = !menuItems[i].on; - subImage.y = (menuItems[i].on ? 0 : 1) * IMAGE_HEIGHT; - Overlays.editOverlay(menuItems[i].overlay, { subImage: subImage }); - if (menuItems[i].callback) { - menuItems[i].callback(menuItems[i].on); - } - } - } - } - } - - function setUp() { - var overlay, - menuItem, - i; - - for (i = 0; i < NUMBER_OF_BUTTONS; i += 1) { - overlay = Overlays.addOverlay("billboard", { - url: "http://ctrlaltstudio.com/hifi/menu-blank.svg", - subImage: { x: 0, y: IMAGE_HEIGHT, width: IMAGE_WIDTH, height: IMAGE_HEIGHT }, - alpha: 1.0, - visible: false, - scale: IMAGE_SCALE, - isFacingAvatar: false - }); - - menuItem = { - overlay: overlay, - on: false, - callback: null - }; - - menuItems.push(menuItem); - } - - Overlays.editOverlay(menuItems[NUMBER_OF_BUTTONS - 2].overlay, { - url: "http://ctrlaltstudio.com/hifi/menu-chat.svg" - }); - menuItems[NUMBER_OF_BUTTONS - 2].callback = vrChat.show; - - Controller.keyPressEvent.connect(keyPressEvent); - Controller.mousePressEvent.connect(mousePressEvent); - } - - function update() { - var MENU_OFFSET = { x: 0.0, y: MENU_HEIGHT, z: -MENU_RADIUS }, // Offset from avatar position. - itemAngle, - itemRotation, - itemOffset, - i; - - itemAngle = menuItems.length * ITEM_SPACING / 2.0; - - for (i = 0; i < menuItems.length; i += 1) { - - itemRotation = Quat.multiply(Quat.fromPitchYawRollDegrees(0.0, itemAngle, 0.0), MyAvatar.orientation); - itemOffset = Vec3.multiplyQbyV(itemRotation, MENU_OFFSET); - - Overlays.editOverlay(menuItems[i].overlay, { - position: Vec3.sum(MyAvatar.position, itemOffset), - rotation: itemRotation - }); - - itemAngle -= ITEM_SPACING; - } - } - - function tearDown() { - var i; - - for (i = 0; i < menuItems.length; i += 1) { - Overlays.deleteOverlay(menuItems[i].overlay); - } - } - - return { - setUp: setUp, - update: update, - tearDown: tearDown - }; - -}()); - -vrChat.setUp(); -Script.update.connect(vrChat.update); -Script.scriptEnding.connect(vrChat.tearDown); - -vrMenu.setUp(); -Script.update.connect(vrMenu.update); -Script.scriptEnding.connect(vrMenu.tearDown); \ No newline at end of file From 23892ab1e70a4e9abe7f07c164370fe2d90d2944 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 27 Jan 2015 11:38:14 -0800 Subject: [PATCH 55/63] fixed comments --- libraries/entities/src/EntityItem.cpp | 12 +++++------- libraries/physics/src/EntityMotionState.cpp | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 86e116bf9f..64cbf8ab04 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -542,13 +542,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef recalculateCollisionShape(); if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { - // TODO: Andrew & Brad to discuss -- this probably should not be "now" but instead should be the last - // simulated time from server. The logic should maybe be: the position changed from the server, so the - // position we just set can be thought of as the position at the time it was last simulated by the - // server (clock skew adjusted). By setting it to "now" we are saying that the last position is to be - // considered to be the correct position for "now" which is likely in the future from when it actually - // was at that last known positition. - + // NOTE: This code is attempting to "repair" the old data we just got from the server to make it more + // closely match where the entities should be if they'd stepped forward in time to "now". The server + // is sending us data with a known "last simulated" time. That time is likely in the past, and therefore + // this "new" data is actually slightly out of date. We calculate the time we need to skip forward and + // use our simulation helper routine to get a best estimate of where the entity should be. float skipTimeForward = (float)(now - _lastSimulated) / (float)(USECS_PER_SECOND); if (skipTimeForward > 0.0f) { #ifdef WANT_DEBUG diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6283229dea..acff3ed64a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -228,7 +228,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // we only update lastEdited when we're sending new physics data // (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data) // NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly - quint64 lastSimulated = _entity->getLastSimulated(); // or now??? + quint64 lastSimulated = _entity->getLastSimulated(); _entity->setLastEdited(lastSimulated); properties.setLastEdited(lastSimulated); From 1ce92c19394da39a281acf3608ed5084d5247ec5 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 11:45:26 -0800 Subject: [PATCH 56/63] added bullet to externals list --- BUILD_WIN.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index cf1c60ee23..1f60e43840 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -48,6 +48,9 @@ CMake will need to know where the headers and libraries for required external de The recommended route for CMake to find the external dependencies is to place all of the dependencies in one folder and set one ENV variable - HIFI_LIB_DIR. That ENV variable should point to a directory with the following structure: root_lib_dir + -> bullet + -> include + -> lib -> freeglut -> bin -> include From 36e9f6b9e03fe13f058b68cd475020fdfc3f8874 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 13:33:29 -0800 Subject: [PATCH 57/63] Reminder about all dependencies --- BUILD_WIN.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 1f60e43840..12248d4727 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -1,9 +1,10 @@ Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Windows specific instructions are found in this file. -###Windows Dependencies +###Windows Specific Dependencies * [GLEW](http://glew.sourceforge.net/) ~> 1.10.0 * [freeglut MSVC](http://www.transmissionzero.co.uk/software/freeglut-devel/) ~> 2.8.1 * [zLib](http://www.zlib.net/) ~> 1.2.8 +* (remember that you need all other dependencies listed in BUILD.md) ###Visual Studio From acb1494e3ebf49b6e353403441d99db5a0bdfa57 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 13:38:58 -0800 Subject: [PATCH 58/63] Small edits to links --- BUILD_WIN.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 12248d4727..905bd360fb 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -31,11 +31,11 @@ You can use the online installer or the offline installer. If you use the offlin NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit version of libraries for interface.exe to run. The 32-bit version of the static library is the one linked by our CMake find modules. -* Download the online installer [here](http://qt-project.org/downloads) +* [Do load the online installer](http://qt-project.org/downloads) * When it asks you to select components, ONLY select the following: * Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL** -* Download the offline installer [here](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe) +* [Download the offline installer](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe) Once Qt is installed, you need to manually configure the following: * Make sure the Qt runtime DLLs are loadable. You must do this before you attempt to build because some tools for the build depend on Qt. E.g., add to the PATH: `Qt\5.3.2\msvc2013_opengl\bin\`. From e290fa2e7f925576fe4bf798382e9d3c04f296f5 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 13:42:24 -0800 Subject: [PATCH 59/63] Small changes, removed VS section Removed the Visual Studio section -- now that we have a better Visual Studio 2013 section it was unnecessary. --- BUILD_WIN.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 905bd360fb..eff4aad194 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -4,13 +4,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies * [GLEW](http://glew.sourceforge.net/) ~> 1.10.0 * [freeglut MSVC](http://www.transmissionzero.co.uk/software/freeglut-devel/) ~> 2.8.1 * [zLib](http://www.zlib.net/) ~> 1.2.8 -* (remember that you need all other dependencies listed in BUILD.md) - -###Visual Studio - -Currently building on Windows has been tested using the following compilers: -* Visual Studio 2013 -* Visual Studio 2013 Express +* (remember that you need all other dependencies listed in [BUILD.md](BUILD.md)) ####Visual Studio 2013 @@ -31,7 +25,7 @@ You can use the online installer or the offline installer. If you use the offlin NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit version of libraries for interface.exe to run. The 32-bit version of the static library is the one linked by our CMake find modules. -* [Do load the online installer](http://qt-project.org/downloads) +* [Download the online installer](http://qt-project.org/downloads) * When it asks you to select components, ONLY select the following: * Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL** From 7ececd793a876037bd1c048d41037b29e0ee30c4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Jan 2015 13:59:46 -0800 Subject: [PATCH 60/63] Fix failing QMetaObject::invokeMethod call --- libraries/render-utils/src/TextureCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 372b4732f5..bbbe927c0f 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -490,7 +490,7 @@ void ImageReader::run() { averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea); } QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image), Q_ARG(bool, false), - Q_ARG(const QColor&, averageColor)); + Q_ARG(const QColor&, averageColor), Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); return; } if (image.format() != QImage::Format_ARGB32) { From e6673327a2c134a4c4e96a6c0fd7543c421eff87 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 14:37:22 -0800 Subject: [PATCH 61/63] Minor edits, addition of note about PATH --- BUILD_WIN.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index eff4aad194..d9aae98df4 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -91,7 +91,7 @@ To prevent these problems, install OpenSSL yourself. Download the following bina * Visual C++ 2008 Redistributables * Win32 OpenSSL v1.0.1h -Install OpenSSL into the Windows system directory, to make sure that QT uses the version that you've just installed, and not some other version. +Install OpenSSL into the Windows system directory, to make sure that Qt uses the version that you've just installed, and not some other version. ###Intel Threading Building Blocks (TBB) @@ -110,8 +110,10 @@ Add the following environment variables (remember to substitute your own directo Add to the PATH: `%HIFI_LIB_DIR%\zlib` -Important! This should be added at the beginning of the path, not the end. That's because your -system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version. If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022". +(The PATH environment variable is where Windows looks for its DLL's and executables. There's a great tool for editing these variables with ease, [Rapid Environment Editor](http://www.rapidee.com/en/download)) + +Important! This should be added at the beginning of the path, not the end (your +system likely has many copies of zlib1.dll, and you want High Fidelity to use the correct version). If High Fidelity picks up the wrong zlib1.dll then it might be unable to use it, and that would cause it to fail to start, showing only the cryptic error "The application was unable to start correctly: 0xc0000022". ###freeglut @@ -133,10 +135,10 @@ Be careful with glm. For the folder other libraries would normally call 'include ###Bullet -Bullet 2.82 source can be downloaded [here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself. +Bullet 2.82 source can be [downloaded here](https://code.google.com/p/bullet/downloads/detail?name=bullet-2.82-r2704.zip). Bullet does not come with prebuilt libraries, you need to make those yourself. * Download the zip file and extract into a temporary folder -* Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, I prefer to run the cmake build on its own directory. +* Create a directory named cmakebuild. Bullet comes with a build\ directory by default, however, that directory is intended for use with premake, and considering premake doesn't support VS2013, we prefer to run the cmake build on its own directory. * Make the following modifications to Bullet's source: 1. In file: Extras\HACD\hacdICHull.cpp --- in line: 17 --- insert: #include <algorithm> 2. In file: src\MiniCL\cl_MiniCL_Defs.h --- comment lines 364 to 372 From a28195a3344a69e9d988245240b3b9ba47f91b13 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 27 Jan 2015 15:28:06 -0800 Subject: [PATCH 62/63] Move setApplication/Organisation to setupEssentials --- interface/src/Application.cpp | 40 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 86af8b0e91..4537b3eb91 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -153,6 +153,16 @@ bool setupEssentials(int& argc, char** argv) { listenPort = atoi(portStr); } + // read the ApplicationInfo.ini file for Name/Version/Domain information + QSettings::setDefaultFormat(QSettings::IniFormat); + QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); + // set the associated application properties + applicationInfo.beginGroup("INFO"); + QApplication::setApplicationName(applicationInfo.value("name").toString()); + QApplication::setApplicationVersion(BUILD_VERSION); + QApplication::setOrganizationName(applicationInfo.value("organizationName").toString()); + QApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); + DependencyManager::registerInheritance(); // Set dependencies @@ -223,35 +233,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _isVSyncOn(true), _aboutToQuit(false) { - auto glCanvas = DependencyManager::get(); - auto nodeList = DependencyManager::get(); + _logger = new FileLogger(this); // After setting organization name in order to get correct directory + qInstallMessageHandler(messageHandler); + + QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); + _window->setWindowTitle("Interface"); + Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us - - // read the ApplicationInfo.ini file for Name/Version/Domain information - QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); - - // set the associated application properties - applicationInfo.beginGroup("INFO"); - - setApplicationName(applicationInfo.value("name").toString()); - setApplicationVersion(BUILD_VERSION); - setOrganizationName(applicationInfo.value("organizationName").toString()); - setOrganizationDomain(applicationInfo.value("organizationDomain").toString()); - - _logger = new FileLogger(this); // After setting organization name in order to get correct directory - - QSettings::setDefaultFormat(QSettings::IniFormat); + auto glCanvas = DependencyManager::get(); + auto nodeList = DependencyManager::get(); _myAvatar = _avatarManager.getMyAvatar(); _applicationStartupTime = startup_time; - QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf"); - _window->setWindowTitle("Interface"); - - qInstallMessageHandler(messageHandler); - qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion()); _bookmarks = new Bookmarks(); // Before setting up the menu From baba56a79362395e6fc394f68c6d05841a023d77 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 27 Jan 2015 15:34:54 -0800 Subject: [PATCH 63/63] Add another link back to BUILD.md --- BUILD_WIN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD_WIN.md b/BUILD_WIN.md index d9aae98df4..5045201f62 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -163,7 +163,7 @@ You now have Bullet libraries compiled, now you need to put them in the right pl _Note that the INSTALL target should handle the copying of files into an install directory automatically, however, without modifications to Cmake, the install target didn't work right for me, please update this instructions if you get that working right - Leo <leo@highfidelity.io>_ ###Build High Fidelity using Visual Studio -Follow the same build steps from the CMake section, but pass a different generator to CMake. +Follow the same build steps from the CMake section of [BUILD.md](BUILD.md), but pass a different generator to CMake. cmake .. -DZLIB_LIBRARY=%ZLIB_LIBRARY% -DZLIB_INCLUDE_DIR=%ZLIB_INCLUDE_DIR% -G "Visual Studio 12"