From 6c062102e92c73e9f1b711924d0acac7091f1667 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 7 Sep 2014 21:21:29 -0700 Subject: [PATCH 01/38] fix typo in comment --- assignment-client/src/octree/OctreeServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 52a027852c..23e8c0d965 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -878,10 +878,10 @@ void OctreeServer::setupDatagramProcessingThread() { // we do not want this event loop to be the handler for UDP datagrams, so disconnect disconnect(&nodeList->getNodeSocket(), 0, this, 0); - // setup a QThread with us as parent that will house the AudioMixerDatagramProcessor + // setup a QThread with us as parent that will house the OctreeServerDatagramProcessor _datagramProcessingThread = new QThread(this); - // create an AudioMixerDatagramProcessor and move it to that thread + // create an OctreeServerDatagramProcessor and move it to that thread OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread()); datagramProcessor->moveToThread(_datagramProcessingThread); From 31fc5bb4f7db318c4aab133e6aacc8c935a86b81 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 13:19:06 -0700 Subject: [PATCH 02/38] silence some over active debug messages --- libraries/octree/src/Octree.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 9569296502..5d83d4034e 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -238,19 +238,25 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch int bytesLeftToRead = bytesAvailable; int bytesRead = 0; + bool wantDebug = false; // give this destination element the child mask from the packet const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; if ((size_t)bytesLeftToRead < sizeof(unsigned char)) { - qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. Not enough for meaningful data."; + if (wantDebug) { + qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. " + "Not enough for meaningful data."; + } return bytesAvailable; // assume we read the entire buffer... } if (destinationElement->getScale() < SCALE_AT_DANGEROUSLY_DEEP_RECURSION) { - qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small [" - << destinationElement->getScale() * (float)TREE_SCALE << " meters] " - << " Discarding " << bytesAvailable << " remaining bytes."; + if (wantDebug) { + qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small [" + << destinationElement->getScale() * (float)TREE_SCALE << " meters] " + << " Discarding " << bytesAvailable << " remaining bytes."; + } return bytesAvailable; // assume we read the entire buffer... } @@ -299,8 +305,10 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch : sizeof(childInBufferMask); if (bytesLeftToRead < bytesForMasks) { - qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. " - "Not enough for meaningful data."; + if (wantDebug) { + qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. " + "Not enough for meaningful data."; + } return bytesAvailable; // assume we read the entire buffer... } @@ -360,6 +368,7 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long ReadBitstreamToTreeParams& args) { int bytesRead = 0; const unsigned char* bitstreamAt = bitstream; + bool wantDebug = false; // If destination element is not included, set it to root if (!args.destinationElement) { @@ -376,7 +385,10 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes); if (numberOfThreeBitSectionsInStream == OVERFLOWED_OCTCODE_BUFFER) { - qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. This buffer is corrupt. Returning."; + if (wantDebug) { + qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. " + "This buffer is corrupt. Returning."; + } return; } From b78b8ccbb095170ceabba4f3d252034615551ea0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 13:33:05 -0700 Subject: [PATCH 03/38] first cut at replacing radius with dimensions --- examples/editModels.js | 91 ++++++--- interface/src/avatar/ModelReferential.cpp | 16 +- interface/src/entities/EntityTreeRenderer.cpp | 1 + .../src/entities/RenderableBoxEntityItem.cpp | 12 +- .../entities/RenderableModelEntityItem.cpp | 4 +- .../entities/RenderableSphereEntityItem.cpp | 8 +- interface/src/renderer/Model.cpp | 19 +- interface/src/renderer/Model.h | 5 +- libraries/entities/src/BoxEntityItem.cpp | 19 +- libraries/entities/src/EntityItem.cpp | 177 +++++++++++------- libraries/entities/src/EntityItem.h | 43 ++++- .../entities/src/EntityItemProperties.cpp | 68 ++++--- libraries/entities/src/EntityItemProperties.h | 69 ++++--- libraries/entities/src/EntityTreeElement.cpp | 3 + libraries/entities/src/ModelEntityItem.cpp | 56 ++---- libraries/entities/src/ModelEntityItem.h | 9 + libraries/entities/src/SphereEntityItem.cpp | 10 +- .../entities/src/UpdateEntityOperator.cpp | 11 +- libraries/networking/src/PacketHeaders.cpp | 5 +- libraries/networking/src/PacketHeaders.h | 1 + tests/octree/src/ModelTests.cpp | 11 +- 21 files changed, 392 insertions(+), 246 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index cec1bff783..2888141bf1 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -40,7 +40,7 @@ var LEFT = 0; var RIGHT = 1; var SPAWN_DISTANCE = 1; -var DEFAULT_RADIUS = 0.10; +var DEFAULT_DIMENSION = 0.20; var modelURLs = [ "http://highfidelity-public.s3-us-west-1.amazonaws.com/meshes/Feisar_Ship.FBX", @@ -1220,7 +1220,7 @@ var toolBar = (function () { Entities.addEntity({ type: "Model", position: position, - radius: DEFAULT_RADIUS, + dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, modelURL: url }); print("Model added: " + url); @@ -1311,7 +1311,7 @@ var toolBar = (function () { Entities.addEntity({ type: "Box", position: position, - radius: DEFAULT_RADIUS, + dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, color: { red: 255, green: 0, blue: 0 } }); } else { @@ -1327,7 +1327,7 @@ var toolBar = (function () { Entities.addEntity({ type: "Sphere", position: position, - radius: DEFAULT_RADIUS, + dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, color: { red: 255, green: 0, blue: 0 } }); } else { @@ -1804,7 +1804,7 @@ function controller(wichSide) { this.modelURL = ""; this.oldModelRotation; this.oldModelPosition; - this.oldModelRadius; + this.oldModelHalfDiagonal; this.positionAtGrab; this.rotationAtGrab; @@ -1864,7 +1864,7 @@ function controller(wichSide) { this.oldModelPosition = properties.position; this.oldModelRotation = properties.rotation; - this.oldModelRadius = properties.radius; + this.oldModelHalfDiagonal = Vec3.length(properties.dimensions) / 2.0; this.positionAtGrab = this.palmPosition; this.rotationAtGrab = this.rotation; @@ -1873,7 +1873,7 @@ function controller(wichSide) { this.jointsIntersectingFromStart = []; for (var i = 0; i < jointList.length; i++) { var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition); - if (distance < this.oldModelRadius) { + if (distance < this.oldModelHalfDiagonal) { this.jointsIntersectingFromStart.push(i); } } @@ -1897,10 +1897,10 @@ function controller(wichSide) { if (closestJointIndex != -1) { print("closestJoint: " + jointList[closestJointIndex]); - print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")"); + print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelHalfDiagonal + ")"); } - if (closestJointDistance < this.oldModelRadius) { + if (closestJointDistance < this.oldModelHalfDiagonal) { if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1 || (leftController.grabbing && rightController.grabbing && @@ -1916,7 +1916,7 @@ function controller(wichSide) { var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation); MyAvatar.attach(this.modelURL, jointList[closestJointIndex], - attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius, + attachmentOffset, attachmentRotation, 2.0 * this.oldModelHalfDiagonal, true, false); Entities.deleteEntity(this.entityID); } @@ -1970,11 +1970,12 @@ function controller(wichSide) { var z = Vec3.dot(Vec3.subtract(P, A), this.right); var X = Vec3.sum(A, Vec3.multiply(B, x)); var d = Vec3.length(Vec3.subtract(P, X)); + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - var angularSize = 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; if (0 < x && angularSize > MIN_ANGULAR_SIZE) { if (angularSize > MAX_ANGULAR_SIZE) { - print("Angular size too big: " + 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14); + print("Angular size too big: " + angularSize); return { valid: false }; } @@ -2021,7 +2022,10 @@ function controller(wichSide) { origin: this.palmPosition, direction: this.front }); - var angularSize = 2 * Math.atan(intersection.properties.radius / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14; + + var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0; + + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), intersection.properties.position)) * 180 / 3.14; if (intersection.accurate && intersection.entityID.isKnownID && angularSize > MIN_ANGULAR_SIZE && angularSize < MAX_ANGULAR_SIZE) { this.glowedIntersectingModel = intersection.entityID; Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.25 }); @@ -2099,7 +2103,7 @@ function controller(wichSide) { var indicesToRemove = []; for (var i = 0; i < this.jointsIntersectingFromStart.length; ++i) { var distance = Vec3.distance(MyAvatar.getJointPosition(this.jointsIntersectingFromStart[i]), this.oldModelPosition); - if (distance >= this.oldModelRadius) { + if (distance >= this.oldModelHalfDiagonal) { indicesToRemove.push(this.jointsIntersectingFromStart[i]); } @@ -2192,7 +2196,12 @@ function controller(wichSide) { Vec3.multiplyQbyV(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].translation)), rotation: Quat.multiply(MyAvatar.getJointCombinedRotation(attachments[attachmentIndex].jointName), attachments[attachmentIndex].rotation), - radius: attachments[attachmentIndex].scale / 2.0, + + // TODO: how do we know the correct dimensions for detachment??? + dimensions: { x: attachments[attachmentIndex].scale / 2.0, + y: attachments[attachmentIndex].scale / 2.0, + z: attachments[attachmentIndex].scale / 2.0 }, + modelURL: attachments[attachmentIndex].modelURL }; @@ -2310,15 +2319,21 @@ function moveEntities() { Entities.editEntity(leftController.entityID, { position: newPosition, rotation: rotation, - radius: leftController.oldModelRadius * ratio + // TODO: how do we know the correct dimensions for detachment??? + //radius: leftController.oldModelHalfDiagonal * ratio + dimensions: { x: leftController.oldModelHalfDiagonal * ratio, + y: leftController.oldModelHalfDiagonal * ratio, + z: leftController.oldModelHalfDiagonal * ratio } + + }); leftController.oldModelPosition = newPosition; leftController.oldModelRotation = rotation; - leftController.oldModelRadius *= ratio; + leftController.oldModelHalfDiagonal *= ratio; rightController.oldModelPosition = newPosition; rightController.oldModelRotation = rotation; - rightController.oldModelRadius *= ratio; + rightController.oldModelHalfDiagonal *= ratio; return; } leftController.moveEntity(); @@ -2407,7 +2422,9 @@ function Tooltip() { text += "Pitch: " + angles.x.toFixed(this.decimals) + "\n" text += "Yaw: " + angles.y.toFixed(this.decimals) + "\n" text += "Roll: " + angles.z.toFixed(this.decimals) + "\n" - text += "Scale: " + 2 * properties.radius.toFixed(this.decimals) + "\n" + text += "Width: " + properties.dimensions.x.toFixed(this.decimals) + "\n" + text += "Height: " + properties.dimensions.y.toFixed(this.decimals) + "\n" + text += "Depth: " + properties.dimensions.z.toFixed(this.decimals) + "\n" text += "ID: " + properties.id + "\n" if (properties.type == "Model") { text += "Model URL: " + properties.modelURL + "\n" @@ -2477,7 +2494,9 @@ function mousePressEvent(event) { if (isLocked(properties)) { print("Model locked " + properties.id); } else { - print("Checking properties: " + properties.id + " " + properties.isKnownID); + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); // P P - Model // /| A - Palm // / | d B - unit vector toward tip @@ -2496,8 +2515,9 @@ function mousePressEvent(event) { var x = Vec3.dot(Vec3.subtract(P, A), B); var X = Vec3.sum(A, Vec3.multiply(B, x)); var d = Vec3.length(Vec3.subtract(P, X)); + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - var angularSize = 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; if (0 < x && angularSize > MIN_ANGULAR_SIZE) { if (angularSize < MAX_ANGULAR_SIZE) { entitySelected = true; @@ -2506,13 +2526,13 @@ function mousePressEvent(event) { orientation = MyAvatar.orientation; intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); } else { - print("Angular size too big: " + 2 * Math.atan(properties.radius / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14); + print("Angular size too big: " + angularSize); } } } } if (entitySelected) { - selectedEntityProperties.oldRadius = selectedEntityProperties.radius; + selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; selectedEntityProperties.oldPosition = { x: selectedEntityProperties.position.x, y: selectedEntityProperties.position.y, @@ -2550,8 +2570,12 @@ function mouseMoveEvent(event) { glowedEntityID.id = -1; glowedEntityID.isKnownID = false; } + + var halfDiagonal = Vec3.length(entityIntersection.properties.dimensions) / 2.0; - var angularSize = 2 * Math.atan(entityIntersection.properties.radius / Vec3.distance(Camera.getPosition(), entityIntersection.properties.position)) * 180 / 3.14; + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), + entityIntersection.properties.position)) * 180 / 3.14; + if (entityIntersection.entityID.isKnownID && angularSize > MIN_ANGULAR_SIZE && angularSize < MAX_ANGULAR_SIZE) { Entities.editEntity(entityIntersection.entityID, { glowLevel: 0.25 }); glowedEntityID = entityIntersection.entityID; @@ -2573,7 +2597,7 @@ function mouseMoveEvent(event) { } pickRay = Camera.computePickRay(event.x, event.y); if (wasShifted != event.isShifted || modifier != oldModifier) { - selectedEntityProperties.oldRadius = selectedEntityProperties.radius; + selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; selectedEntityProperties.oldPosition = { x: selectedEntityProperties.position.x, @@ -2603,9 +2627,12 @@ function mouseMoveEvent(event) { return; case 1: // Let's Scale - selectedEntityProperties.radius = (selectedEntityProperties.oldRadius * + selectedEntityProperties.dimensions = Vec3.multiply(selectedEntityProperties.dimensions, (1.0 + (mouseLastPosition.y - event.y) / SCALE_FACTOR)); - if (selectedEntityProperties.radius < 0.01) { + + var halfDiagonal = Vec3.length(selectedEntityProperties.dimensions) / 2.0; + + if (halfDiagonal < 0.01) { print("Scale too small ... bailling."); return; } @@ -2815,7 +2842,10 @@ function handeMenuEvent(menuItem) { array.push({ label: "Pitch:", value: angles.x.toFixed(decimals) }); array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) }); array.push({ label: "Roll:", value: angles.z.toFixed(decimals) }); - array.push({ label: "Scale:", value: 2 * properties.radius.toFixed(decimals) }); + + array.push({ label: "Width:", value: properties.dimensions.x.toFixed(decimals) }); + array.push({ label: "Height:", value: properties.dimensions.y.toFixed(decimals) }); + array.push({ label: "Depth:", value: properties.dimensions.z.toFixed(decimals) }); array.push({ label: "Velocity X:", value: properties.velocity.x.toFixed(decimals) }); array.push({ label: "Velocity Y:", value: properties.velocity.y.toFixed(decimals) }); @@ -2851,7 +2881,10 @@ function handeMenuEvent(menuItem) { angles.y = array[index++].value; angles.z = array[index++].value; properties.rotation = Quat.fromVec3Degrees(angles); - properties.radius = array[index++].value / 2; + + properties.dimensions.x = array[index++].value; + properties.dimensions.y = array[index++].value; + properties.dimensions.z = array[index++].value; properties.velocity.x = array[index++].value; properties.velocity.y = array[index++].value; diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index eb2a61a819..df6e272da7 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -33,7 +33,7 @@ ModelReferential::ModelReferential(Referential* referential, EntityTree* tree, A const EntityItem* item = _tree->findEntityByID(_entityID); if (item != NULL) { - _refScale = item->getRadius(); + _refScale = item->getLargestDimension(); _refRotation = item->getRotation(); _refPosition = item->getPosition() * (float)TREE_SCALE; update(); @@ -52,7 +52,7 @@ ModelReferential::ModelReferential(const QUuid& entityID, EntityTree* tree, Avat return; } - _refScale = item->getRadius(); + _refScale = item->getLargestDimension(); _refRotation = item->getRotation(); _refPosition = item->getPosition() * (float)TREE_SCALE; @@ -69,8 +69,8 @@ void ModelReferential::update() { } bool somethingChanged = false; - if (item->getRadius() != _refScale) { - _refScale = item->getRadius(); + if (item->getLargestDimension() != _refScale) { + _refScale = item->getLargestDimension(); _avatar->setTargetScale(_refScale * _scale, true); somethingChanged = true; } @@ -109,7 +109,7 @@ JointReferential::JointReferential(Referential* referential, EntityTree* tree, A const EntityItem* item = _tree->findEntityByID(_entityID); const Model* model = getModel(item); if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) { - _refScale = item->getRadius(); + _refScale = item->getLargestDimension(); model->getJointRotationInWorldFrame(_jointIndex, _refRotation); model->getJointPositionInWorldFrame(_jointIndex, _refPosition); } @@ -129,7 +129,7 @@ JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, E return; } - _refScale = item->getRadius(); + _refScale = item->getLargestDimension(); model->getJointRotationInWorldFrame(_jointIndex, _refRotation); model->getJointPositionInWorldFrame(_jointIndex, _refPosition); @@ -147,8 +147,8 @@ void JointReferential::update() { } bool somethingChanged = false; - if (item->getRadius() != _refScale) { - _refScale = item->getRadius(); + if (item->getLargestDimension() != _refScale) { + _refScale = item->getLargestDimension(); _avatar->setTargetScale(_refScale * _scale, true); somethingChanged = true; } diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 8dd88a79cc..495952f895 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -216,6 +216,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) EntityItem* entityItem = entityItems[i]; // render entityItem AACube entityCube = entityItem->getAACube(); + entityCube.scale(TREE_SCALE); // TODO: some entity types (like lights) might want to be rendered even diff --git a/interface/src/entities/RenderableBoxEntityItem.cpp b/interface/src/entities/RenderableBoxEntityItem.cpp index 673f41574e..0156f051ae 100644 --- a/interface/src/entities/RenderableBoxEntityItem.cpp +++ b/interface/src/entities/RenderableBoxEntityItem.cpp @@ -33,7 +33,8 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableBoxEntityItem::render"); assert(getType() == EntityTypes::Box); glm::vec3 position = getPosition() * (float)TREE_SCALE; - float size = getSize() * (float)TREE_SCALE; + glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; + glm::vec3 halfDimensions = dimensions / 2.0f; glm::quat rotation = getRotation(); @@ -45,7 +46,8 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glutSolidCube(size); + glScalef(dimensions.x, dimensions.y, dimensions.z); + glutSolidCube(1.0f); glPopMatrix(); } else { @@ -79,8 +81,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glNormalPointer(GL_FLOAT, 0, normals); glVertexPointer(3, GL_FLOAT, 0, vertices); - //glEnable(GL_BLEND); - glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]); glPushMatrix(); @@ -89,9 +89,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); // we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1 - float halfSize = size/2.0f; - - glScalef(halfSize, halfSize, halfSize); + glScalef(halfDimensions.x, halfDimensions.y, halfDimensions.z); glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices); glPopMatrix(); diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index e2a710123e..f74abd2a13 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -65,8 +65,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) { bool drawAsModel = hasModel(); glm::vec3 position = getPosition() * (float)TREE_SCALE; - float radius = getRadius() * (float)TREE_SCALE; float size = getSize() * (float)TREE_SCALE; + glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; if (drawAsModel) { glPushMatrix(); @@ -98,7 +98,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::quat rotation = getRotation(); if (needsSimulation() && _model->isActive()) { - _model->setScaleToFit(true, radius * 2.0f); + _model->setScaleToFit(true, dimensions); _model->setSnapModelToCenter(true); _model->setRotation(rotation); _model->setTranslation(position); diff --git a/interface/src/entities/RenderableSphereEntityItem.cpp b/interface/src/entities/RenderableSphereEntityItem.cpp index 01f41e83ae..d03a384063 100644 --- a/interface/src/entities/RenderableSphereEntityItem.cpp +++ b/interface/src/entities/RenderableSphereEntityItem.cpp @@ -32,11 +32,15 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableSphereEntityItem::render"); assert(getType() == EntityTypes::Sphere); glm::vec3 position = getPosition() * (float)TREE_SCALE; - float radius = getRadius() * (float)TREE_SCALE; + glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; + glm::quat rotation = getRotation(); glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]); glPushMatrix(); glTranslatef(position.x, position.y, position.z); - glutSolidSphere(radius, 15, 15); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glScalef(dimensions.x, dimensions.y, dimensions.z); + glutSolidSphere(0.5f, 15, 15); glPopMatrix(); }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index d49eefa4bd..867083fe90 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -54,7 +54,7 @@ Model::Model(QObject* parent) : QObject(parent), _scale(1.0f, 1.0f, 1.0f), _scaleToFit(false), - _scaleToFitLargestDimension(0.0f), + _scaleToFitDimensions(0.0f), _scaledToFit(false), _snapModelToCenter(false), _snappedToCenter(false), @@ -882,23 +882,26 @@ void Blender::run() { Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); } -void Model::setScaleToFit(bool scaleToFit, float largestDimension) { - if (_scaleToFit != scaleToFit || _scaleToFitLargestDimension != largestDimension) { +void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) { + if (_scaleToFit != scaleToFit || _scaleToFitDimensions != dimensions) { _scaleToFit = scaleToFit; - _scaleToFitLargestDimension = largestDimension; + _scaleToFitDimensions = dimensions; _scaledToFit = false; // force rescaling } } +void Model::setScaleToFit(bool scaleToFit, float largestDimension) { + setScaleToFit(scaleToFit, glm::vec3(largestDimension, largestDimension, largestDimension)); +} + void Model::scaleToFit() { Extents modelMeshExtents = getUnscaledMeshExtents(); // size is our "target size in world space" // we need to set our model scale so that the extents of the mesh, fit in a cube that size... - float maxDimension = glm::distance(modelMeshExtents.maximum, modelMeshExtents.minimum); - float maxScale = _scaleToFitLargestDimension / maxDimension; - glm::vec3 scale(maxScale, maxScale, maxScale); - setScaleInternal(scale); + glm::vec3 meshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum; + glm::vec3 rescaleDimensions = _scaleToFitDimensions / meshDimensions; + setScaleInternal(rescaleDimensions); _scaledToFit = true; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 66baaac90d..f56aed37a0 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -52,7 +52,8 @@ public: void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f); bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit - bool getScaleToFitDimension() const { return _scaleToFitLargestDimension; } /// the dimension model is scaled to + const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to + void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions); void setSnapModelToCenter(bool snapModelToCenter); bool getSnapModelToCenter() { return _snapModelToCenter; } @@ -181,7 +182,7 @@ protected: glm::vec3 _offset; bool _scaleToFit; /// If you set scaleToFit, we will calculate scale based on MeshExtents - float _scaleToFitLargestDimension; /// this is the dimension that scale to fit will use + glm::vec3 _scaleToFitDimensions; /// this is the dimensions that scale to fit will use bool _scaledToFit; /// have we scaled to fit bool _snapModelToCenter; /// is the model's offset automatically adjusted to center around 0,0,0 in model space diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index c683a71562..83d6d7eff9 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -20,13 +20,15 @@ EntityItem* BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return new BoxEntityItem(entityID, properties); + EntityItem* result = new BoxEntityItem(entityID, properties); + return result; } BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID, properties) -{ + EntityItem(entityItemID) +{ _type = EntityTypes::Box; + _created = properties.getCreated(); setProperties(properties, true); } @@ -44,18 +46,9 @@ EntityItemProperties BoxEntityItem::getProperties() const { bool BoxEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool somethingChanged = false; - somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class - if (properties._colorChanged || forceCopy) { - setColor(properties._color); - somethingChanged = true; - } - - if (properties._glowLevelChanged || forceCopy) { - setGlowLevel(properties._glowLevel); - somethingChanged = true; - } + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); if (somethingChanged) { bool wantDebug = false; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a472e7ec39..e64b1d503d 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -35,6 +35,9 @@ const glm::vec3 EntityItem::NO_GRAVITY = glm::vec3(0, 0, 0); const glm::vec3 EntityItem::REGULAR_GRAVITY = glm::vec3(0, (-9.8f / TREE_SCALE), 0); const glm::vec3 EntityItem::DEFAULT_GRAVITY = EntityItem::NO_GRAVITY; const QString EntityItem::DEFAULT_SCRIPT = QString(""); +const glm::quat EntityItem::DEFAULT_ROTATION; +const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); + void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; @@ -50,8 +53,8 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _created = 0; // TODO: when do we actually want to make this "now" _position = glm::vec3(0,0,0); - _radius = 0; - _rotation = ENTITY_DEFAULT_ROTATION; + _rotation = DEFAULT_ROTATION; + _dimensions = DEFAULT_DIMENSIONS; _glowLevel = DEFAULT_GLOW_LEVEL; _mass = DEFAULT_MASS; @@ -61,6 +64,16 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _lifetime = DEFAULT_LIFETIME; } +EntityItem::EntityItem(const EntityItemID& entityItemID) { + _type = EntityTypes::Unknown; + _lastEdited = 0; + _lastEditedFromRemote = 0; + _lastEditedFromRemoteInRemoteTime = 0; + _lastUpdated = 0; + _created = 0; + initFromEntityItemID(entityItemID); +} + EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) { _type = EntityTypes::Unknown; _lastEdited = 0; @@ -76,7 +89,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param EntityPropertyFlags requestedProperties; requestedProperties += PROP_POSITION; - requestedProperties += PROP_RADIUS; + requestedProperties += PROP_DIMENSIONS; // NOTE: PROP_RADIUS obsolete requestedProperties += PROP_ROTATION; requestedProperties += PROP_MASS; requestedProperties += PROP_VELOCITY; @@ -84,6 +97,9 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_DAMPING; requestedProperties += PROP_LIFETIME; requestedProperties += PROP_SCRIPT; + // TODO: add PROP_REGISTRATION_POINT, + // TODO: add PROP_ROTATIONAL_VELOCITY, + // TODO: add PROP_VISIBLE, return requestedProperties; } @@ -178,10 +194,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // These items would go here once supported.... // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, - // PROP_VISIBLE, APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, getPosition()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS, appendValue, getRadius()); + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, getDimensions()); // NOTE: PROP_RADIUS obsolete APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, getRotation()); APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, getMass()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity()); @@ -189,6 +204,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping()); APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime()); APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript()); + // TODO: add PROP_REGISTRATION_POINT, + // TODO: add PROP_ROTATIONAL_VELOCITY, + // TODO: add PROP_VISIBLE, appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -408,9 +426,23 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef EntityPropertyFlags propertyFlags = encodedPropertyFlags; dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); - + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, _position); - READ_ENTITY_PROPERTY(PROP_RADIUS, float, _radius); + + // Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS + if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) { + if (propertyFlags.getHasProperty(PROP_RADIUS)) { + float fromBuffer; + memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); + dataAt += sizeof(fromBuffer); + bytesRead += sizeof(fromBuffer); + if (overwriteLocalData) { + setRadiusInMeters(fromBuffer); + } + } + } else { + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, _dimensions); + } READ_ENTITY_PROPERTY_QUAT(PROP_ROTATION, _rotation); READ_ENTITY_PROPERTY(PROP_MASS, float, _mass); READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, _velocity); @@ -418,6 +450,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime); READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); + // TODO: add PROP_REGISTRATION_POINT, + // TODO: add PROP_ROTATIONAL_VELOCITY, + // TODO: add PROP_VISIBLE, bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -429,7 +464,7 @@ void EntityItem::debugDump() const { qDebug() << "EntityItem id:" << getEntityItemID(); qDebug(" edited ago:%f", getEditedAgo()); qDebug(" position:%f,%f,%f", _position.x, _position.y, _position.z); - qDebug(" radius:%f", getRadius()); + qDebug() << " dimensions:" << _dimensions; } // adjust any internal timestamps to fix clock skew for this server @@ -453,8 +488,14 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s } } +float EntityItem::getDistanceToBottomOfEntity() const { + // TODO: change this to support registration point + return _dimensions.y / 2.0f; +} + bool EntityItem::isRestingOnSurface() const { - return _position.y <= _radius + // TODO: change this to support registration point + return _position.y <= getDistanceToBottomOfEntity() && _velocity.y >= -EPSILON && _velocity.y <= EPSILON && _gravity.y < 0.0f; } @@ -491,8 +532,8 @@ void EntityItem::update(const quint64& updateTime) { position += velocity * timeElapsed; - // handle bounces off the ground... We bounce at the height of our radius... - if (position.y <= _radius) { + // 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); // if we've slowed considerably, then just stop moving @@ -500,7 +541,7 @@ void EntityItem::update(const quint64& updateTime) { velocity = NO_VELOCITY; } - position.y = _radius; + position.y = getDistanceToBottomOfEntity(); } // handle gravity.... @@ -512,7 +553,7 @@ void EntityItem::update(const quint64& updateTime) { // "ground" plane of the domain, but for now it if (hasGravity() && isRestingOnSurface()) { velocity.y = 0.0f; - position.y = _radius; + position.y = getDistanceToBottomOfEntity(); } // handle damping @@ -574,7 +615,7 @@ EntityItemProperties EntityItem::getProperties() const { properties._type = getType(); properties._position = getPosition() * (float) TREE_SCALE; - properties._radius = getRadius() * (float) TREE_SCALE; + properties.setDimensions(getDimensions() * (float) TREE_SCALE); properties._rotation = getRotation(); properties._mass = getMass(); @@ -585,7 +626,6 @@ EntityItemProperties EntityItem::getProperties() const { properties._script = getScript(); properties._positionChanged = false; - properties._radiusChanged = false; properties._rotationChanged = false; properties._massChanged = false; properties._velocityChanged = false; @@ -610,55 +650,19 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc _created = properties.getCreated(); } } - - if (properties._positionChanged || forceCopy) { - // clamp positions to the domain to prevent someone from moving an entity out of the domain - setPosition(glm::clamp(properties._position / (float) TREE_SCALE, 0.0f, 1.0f)); - somethingChanged = true; - } - if (properties._radiusChanged || forceCopy) { - setRadius(properties._radius / (float) TREE_SCALE); - somethingChanged = true; - } - - if (properties._rotationChanged || forceCopy) { - setRotation(properties._rotation); - somethingChanged = true; - } - - if (properties._massChanged || forceCopy) { - setMass(properties._mass); - somethingChanged = true; - } - - if (properties._velocityChanged || forceCopy) { - setVelocity(properties._velocity / (float) TREE_SCALE); - somethingChanged = true; - } - - if (properties._massChanged || forceCopy) { - setMass(properties._mass); - somethingChanged = true; - } - if (properties._gravityChanged || forceCopy) { - setGravity(properties._gravity / (float) TREE_SCALE); - somethingChanged = true; - } - - if (properties._dampingChanged || forceCopy) { - setDamping(properties._damping); - somethingChanged = true; - } - if (properties._lifetimeChanged || forceCopy) { - setLifetime(properties._lifetime); - somethingChanged = true; - } - - if (properties._scriptChanged || forceCopy) { - setScript(properties._script); - somethingChanged = true; - } + SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPositionInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); + //SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotationalVelocity, setRotationalVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed @@ -675,3 +679,50 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc return somethingChanged; } +float EntityItem::getSize() const { + return glm::length(_dimensions); +} + +// TODO: Add support for registration point +glm::vec3 EntityItem::getMinimumPoint() const { + // This assumes the registration point is in the center, we need to update this when we really support + // registration point + return _position - (_dimensions / 2.0f); +} + +// TODO: Add support for registration point +glm::vec3 EntityItem::getMaximumPoint() const { + // This assumes the registration point is in the center, we need to update this when we really support + // registration point + return _position + (_dimensions / 2.0f); +} + +// NOTE: This should only be used in cases of old bitstreams which only contain radius data +// 0,0,0 --> maxDimension,maxDimension,maxDimension +// ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) +// ... radius = cornerToCornerLength / 2.0f +// ... radius * 2.0f = cornerToCornerLength +// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) +// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) +// ... radius * 2.0f = sqrt(3 x maxDimension ^ 2) +// ... (radius * 2.0f) ^2 = 3 x maxDimension ^ 2 +// ... ((radius * 2.0f) ^2) / 3 = maxDimension ^ 2 +// ... sqrt(((radius * 2.0f) ^2) / 3) = maxDimension +// ... sqrt((diameter ^2) / 3) = maxDimension +// +void EntityItem::setRadius(float value) { + float diameter = value * 2.0f; + float maxDimension = sqrt((diameter * diameter) / 3.0f); + _dimensions = glm::vec3(maxDimension, maxDimension, maxDimension); +} + +// TODO: get rid of all users of this function... +// ... radius = cornerToCornerLength / 2.0f +// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) +// ... radius = sqrt(3 x maxDimension ^ 2) / 2.0f; +float EntityItem::getRadius() const { + float length = glm::length(_dimensions); + float radius = length / 2.0f; + return radius; +} + diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 2d6af48f15..e7cf296f44 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -25,6 +25,7 @@ #include "EntityItemProperties.h" #include "EntityTypes.h" +class EntityTreeElement; class EntityTreeElementExtraEncodeData; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; @@ -39,6 +40,7 @@ class EntityItem { public: DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly + EntityItem(const EntityItemID& entityItemID); EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual ~EntityItem() { } @@ -120,10 +122,21 @@ public: EntityTypes::EntityType getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } /// get position in domain scale units (0.0 - 1.0) void setPosition(const glm::vec3& value) { _position = value; } /// set position in domain scale units (0.0 - 1.0) + void setPositionInMeters(const glm::vec3& value) /// set position in meter units (0.0 - TREE_SCALE) + { setPosition(glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f)); } - float getRadius() const { return _radius; } /// get radius in domain scale units (0.0 - 1.0) - void setRadius(float value) { _radius = value; } /// set radius in domain scale units (0.0 - 1.0) + static const glm::vec3 DEFAULT_DIMENSIONS; + const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0) + float getDistanceToBottomOfEntity() const; /// get the distance from the position of the entity to its "bottom" in y axis + float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension + /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately + void setDimensions(const glm::vec3& value) { _dimensions = value; } + + /// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately + void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); } + + static const glm::quat DEFAULT_ROTATION; const glm::quat& getRotation() const { return _rotation; } void setRotation(const glm::quat& rotation) { _rotation = rotation; } @@ -173,9 +186,9 @@ public: bool lifetimeHasExpired() const; // position, size, and bounds related helpers - float getSize() const { return _radius * 2.0f; } /// get maximum dimension in domain scale units (0.0 - 1.0) - glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); } - glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); } + float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0) + glm::vec3 getMinimumPoint() const; + glm::vec3 getMaximumPoint() const; AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0) static const QString DEFAULT_SCRIPT; @@ -196,7 +209,7 @@ protected: quint64 _created; glm::vec3 _position; - float _radius; + glm::vec3 _dimensions; glm::quat _rotation; float _glowLevel; float _mass; @@ -205,6 +218,24 @@ protected: float _damping; float _lifetime; QString _script; + + // NOTE: Radius support is obsolete, but these private helper functions are available for this class to + // parse old data streams + + /// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis + void setRadius(float value); + /// set radius in meter units (0.0 - TREE_SCALE), this will also reset dimensions to be equal for each axis + void setRadiusInMeters(float value) { + float valueInTreeUnits = value / (float) TREE_SCALE; + setRadius(valueInTreeUnits); + } + +private: + // TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends + // so they can be the only ones accessing this method. + friend EntityTreeElement; + float getRadius() const; + }; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 65babb6e16..f79f64de25 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -18,6 +18,7 @@ #include "EntityItem.h" #include "EntityItemProperties.h" +#include "ModelEntityItem.h" EntityItemProperties::EntityItemProperties() : @@ -28,8 +29,8 @@ EntityItemProperties::EntityItemProperties() : _type(EntityTypes::Unknown), _position(0), - _radius(ENTITY_DEFAULT_RADIUS), - _rotation(ENTITY_DEFAULT_ROTATION), + _dimensions(EntityItem::DEFAULT_DIMENSIONS), + _rotation(EntityItem::DEFAULT_ROTATION), _mass(EntityItem::DEFAULT_MASS), _velocity(EntityItem::DEFAULT_VELOCITY), _gravity(EntityItem::DEFAULT_GRAVITY), @@ -38,7 +39,7 @@ EntityItemProperties::EntityItemProperties() : _script(EntityItem::DEFAULT_SCRIPT), _positionChanged(false), - _radiusChanged(false), + _dimensionsChanged(false), _rotationChanged(false), _massChanged(false), _velocityChanged(false), @@ -50,9 +51,9 @@ EntityItemProperties::EntityItemProperties() : _color(), _modelURL(""), _animationURL(""), - _animationIsPlaying(false), - _animationFrameIndex(0.0), - _animationFPS(ENTITY_DEFAULT_ANIMATION_FPS), + _animationIsPlaying(ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING), + _animationFrameIndex(ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX), + _animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS), _glowLevel(0.0f), _colorChanged(false), @@ -73,7 +74,7 @@ void EntityItemProperties::debugDump() const { qDebug() << " _id=" << _id; qDebug() << " _idSet=" << _idSet; qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z; - qDebug() << " _radius=" << _radius; + qDebug() << " _dimensions=" << getDimensions(); qDebug() << " _modelURL=" << _modelURL; qDebug() << " changed properties..."; EntityPropertyFlags props = getChangedProperties(); @@ -82,8 +83,8 @@ void EntityItemProperties::debugDump() const { EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; - if (_radiusChanged) { - changedProperties += PROP_RADIUS; + if (_dimensionsChanged) { + changedProperties += PROP_DIMENSIONS; } if (_positionChanged) { @@ -158,7 +159,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons QScriptValue position = vec3toScriptValue(engine, _position); properties.setProperty("position", position); - properties.setProperty("radius", _radius); + QScriptValue dimensions = vec3toScriptValue(engine, _dimensions); + properties.setProperty("dimensions", dimensions); QScriptValue rotation = quatToScriptValue(engine, _rotation); properties.setProperty("rotation", rotation); properties.setProperty("mass", _mass); @@ -198,7 +200,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons } void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { - QScriptValue typeScriptValue = object.property("type"); if (typeScriptValue.isValid()) { QString typeName; @@ -222,13 +223,19 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { } } - QScriptValue radius = object.property("radius"); - if (radius.isValid()) { - float newRadius; - newRadius = radius.toVariant().toFloat(); - if (_defaultSettings || newRadius != _radius) { - _radius = newRadius; - _radiusChanged = true; + QScriptValue dimensions = object.property("dimensions"); + if (dimensions.isValid()) { + QScriptValue x = dimensions.property("x"); + QScriptValue y = dimensions.property("y"); + QScriptValue z = dimensions.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + glm::vec3 newDimensions; + newDimensions.x = x.toVariant().toFloat(); + newDimensions.y = y.toVariant().toFloat(); + newDimensions.z = z.toVariant().toFloat(); + if (_defaultSettings || newDimensions != getDimensions()) { + setDimensions(newDimensions); + } } } @@ -403,7 +410,6 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { _glowLevelChanged = true; } } - _lastEdited = usecTimestampNow(); } @@ -432,7 +438,6 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP // bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, unsigned char* bufferOut, int sizeIn, int& sizeOut) { - OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro @@ -535,7 +540,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // PROP_VISIBLE, APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, properties.getPosition()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS, appendValue, properties.getRadius()); + APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete APPEND_ENTITY_PROPERTY(PROP_ROTATION, appendValue, properties.getRotation()); APPEND_ENTITY_PROPERTY(PROP_MASS, appendValue, properties.getMass()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, properties.getVelocity()); @@ -727,7 +732,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int processedBytes += propertyFlags.getEncodedLength(); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS, float, setRadius); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(PROP_ROTATION, setRotation); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MASS, float, setMass); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, glm::vec3, setVelocity); @@ -741,6 +746,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); + // TODO: add PROP_REGISTRATION_POINT, + // TODO: add PROP_ROTATIONAL_VELOCITY, + // TODO: add PROP_VISIBLE, return valid; } @@ -777,7 +785,6 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt void EntityItemProperties::markAllChanged() { _positionChanged = true; - _radiusChanged = true; _rotationChanged = true; _massChanged = true; _velocityChanged = true; @@ -795,3 +802,18 @@ void EntityItemProperties::markAllChanged() { _glowLevelChanged = true; } + + +// TODO: Add support for registration point +glm::vec3 EntityItemProperties::getMinimumPointMeters() const { + // This assumes the registration point is in the center, we need to update this when we really support + // registration point + return _position - (_dimensions / 2.0f); +} + +// TODO: Add support for registration point +glm::vec3 EntityItemProperties::getMaximumPointMeters() const { + // This assumes the registration point is in the center, we need to update this when we really support + // registration point + return _position + (_dimensions / 2.0f); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index fc506ce10c..881a0b4afc 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -31,16 +32,6 @@ #include "EntityTypes.h" -// TODO: should these be static members of EntityItem or EntityItemProperties? -const float ENTITY_DEFAULT_RADIUS = 0.1f / TREE_SCALE; -const float ENTITY_MINIMUM_ELEMENT_SIZE = (1.0f / 100000.0f) / TREE_SCALE; // smallest size container -const QString ENTITY_DEFAULT_MODEL_URL(""); -const glm::quat ENTITY_DEFAULT_ROTATION; -const QString ENTITY_DEFAULT_ANIMATION_URL(""); -const float ENTITY_DEFAULT_ANIMATION_FPS = 30.0f; - -const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1); -const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2); // PropertyFlags support enum EntityPropertyList { @@ -50,7 +41,8 @@ enum EntityPropertyList { // these properties are supported by the EntityItem base class PROP_VISIBLE, PROP_POSITION, - PROP_RADIUS, + PROP_RADIUS, // NOTE: PROP_RADIUS is obsolete and only included in old format streams + PROP_DIMENSIONS = PROP_RADIUS, PROP_ROTATION, PROP_MASS, PROP_VELOCITY, @@ -67,16 +59,23 @@ enum EntityPropertyList { PROP_ANIMATION_FRAME_INDEX, PROP_ANIMATION_PLAYING, - PROP_LAST_ITEM = PROP_ANIMATION_PLAYING + // these properties are supported by the EntityItem base class + PROP_REGISTRATION_POINT, + PROP_ROTATIONAL_VELOCITY, + + PROP_LAST_ITEM = PROP_ROTATIONAL_VELOCITY }; typedef PropertyFlags EntityPropertyFlags; +const quint64 UNKNOWN_CREATED_TIME = (quint64)(-1); +const quint64 USE_EXISTING_CREATED_TIME = (quint64)(-2); + /// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an /// entity and a JavaScript style hash/QScriptValue storing a set of properties. Used in scripting to set/get the complete /// set of entity item properties via JavaScript hashes/QScriptValues -/// all units for position, radius, etc are in meter units +/// all units for position, dimensions, etc are in meter units class EntityItemProperties { friend class EntityItem; // TODO: consider removing this friend relationship and use public methods friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods @@ -96,8 +95,8 @@ public: /// used by EntityScriptingInterface to return EntityItemProperties for unknown models void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; } - glm::vec3 getMinimumPointMeters() const { return _position - glm::vec3(_radius, _radius, _radius); } - glm::vec3 getMaximumPointMeters() const { return _position + glm::vec3(_radius, _radius, _radius); } + glm::vec3 getMinimumPointMeters() const; + glm::vec3 getMaximumPointMeters() const; AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; } @@ -109,18 +108,22 @@ public: void debugDump() const; + // properties of all entities EntityTypes::EntityType getType() const { return _type; } - const glm::vec3& getPosition() const { return _position; } - float getRadius() const { return _radius; } - float getMaxDimension() const { return _radius * 2.0f; } - glm::vec3 getDimensions() const { return glm::vec3(_radius, _radius, _radius) * 2.0f; } - const glm::quat& getRotation() const { return _rotation; } void setType(EntityTypes::EntityType type) { _type = type; } + + const glm::vec3& getPosition() const { return _position; } /// set position in meter units, will be clamped to domain bounds void setPosition(const glm::vec3& value) { _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; } - void setRadius(float value) { _radius = value; _radiusChanged = true; } + + + const glm::vec3& getDimensions() const { return _dimensions; } + void setDimensions(const glm::vec3& value) { _dimensions = value; _dimensionsChanged = true; } + float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } + + const glm::quat& getRotation() const { return _rotation; } void setRotation(const glm::quat& rotation) { _rotation = rotation; _rotationChanged = true; } float getMass() const { return _mass; } @@ -148,9 +151,9 @@ public: // NOTE: how do we handle _defaultSettings??? - bool containsBoundsProperties() const { return (_positionChanged || _radiusChanged); } + bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); } bool containsPositionChange() const { return _positionChanged; } - bool containsRadiusChange() const { return _radiusChanged; } + bool containsDimensionsChange() const { return _dimensionsChanged; } // TODO: this need to be more generic. for now, we're going to have the properties class support these as // named getter/setters, but we want to move them to generic types... @@ -184,7 +187,6 @@ public: EntityItemID& entityID, EntityItemProperties& properties); bool positionChanged() const { return _positionChanged; } - bool radiusChanged() const { return _radiusChanged; } bool rotationChanged() const { return _rotationChanged; } bool massChanged() const { return _massChanged; } bool velocityChanged() const { return _velocityChanged; } @@ -192,6 +194,8 @@ public: bool dampingChanged() const { return _dampingChanged; } bool lifetimeChanged() const { return _lifetimeChanged; } bool scriptChanged() const { return _scriptChanged; } + bool dimensionsChanged() const { return _dimensionsChanged; } + bool registrationPointChanged() const { return _registrationPointChanged; } bool colorChanged() const { return _colorChanged; } bool modelURLChanged() const { return _modelURLChanged; } bool animationURLChanged() const { return _animationURLChanged; } @@ -213,7 +217,7 @@ private: EntityTypes::EntityType _type; glm::vec3 _position; - float _radius; + glm::vec3 _dimensions; glm::quat _rotation; float _mass; glm::vec3 _velocity; @@ -221,9 +225,10 @@ private: float _damping; float _lifetime; QString _script; + glm::vec3 _registrationPoint; bool _positionChanged; - bool _radiusChanged; + bool _dimensionsChanged; bool _rotationChanged; bool _massChanged; bool _velocityChanged; @@ -231,6 +236,7 @@ private: bool _dampingChanged; bool _lifetimeChanged; bool _scriptChanged; + bool _registrationPointChanged; // TODO: this need to be more generic. for now, we're going to have the properties class support these as // named getter/setters, but we want to move them to generic types... @@ -358,6 +364,17 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP properties.O(color); \ } +#define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \ + if (properties._##P##Changed || forceCopy) { \ + M(properties._##P); \ + somethingChanged = true; \ + } + +#define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \ + if (properties.C() || forceCopy) { \ + S(properties.G()); \ + somethingChanged = true; \ + } #endif // hifi_EntityItemProperties_h diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 8f223abf7e..7f94d362eb 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -555,6 +555,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con return somethingIntersected; } +// TODO: change this to use better bounding shape for entity than sphere bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { QList::iterator entityItr = _entityItems->begin(); @@ -605,6 +606,7 @@ const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const return closestEntity; } +// TODO: change this to use better bounding shape for entity than sphere void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector& foundEntities) const { uint16_t numberOfEntities = _entityItems->size(); for (uint16_t i = 0; i < numberOfEntities; i++) { @@ -616,6 +618,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc } } +// TODO: change this to use better bounding shape for entity than sphere void EntityTreeElement::getEntities(const AACube& box, QVector& foundEntities) { QList::iterator entityItr = _entityItems->begin(); QList::iterator entityEnd = _entityItems->end(); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 1c1cd19831..7989d085c6 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -17,6 +17,13 @@ #include "ModelEntityItem.h" +const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); +const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString(""); +const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f; +const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false; +const float ModelEntityItem::DEFAULT_ANIMATION_FPS = 30.0f; + + EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return new ModelEntityItem(entityID, properties); } @@ -55,40 +62,13 @@ EntityItemProperties ModelEntityItem::getProperties() const { bool ModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool somethingChanged = false; somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class - if (properties._colorChanged || forceCopy) { - setColor(properties._color); - somethingChanged = true; - } - if (properties._modelURLChanged || forceCopy) { - setModelURL(properties._modelURL); - somethingChanged = true; - } - - if (properties._animationURLChanged || forceCopy) { - setAnimationURL(properties._animationURL); - somethingChanged = true; - } - - if (properties._animationIsPlayingChanged || forceCopy) { - setAnimationIsPlaying(properties._animationIsPlaying); - somethingChanged = true; - } - - if (properties._animationFrameIndexChanged || forceCopy) { - setAnimationFrameIndex(properties._animationFrameIndex); - somethingChanged = true; - } - - if (properties._animationFPSChanged || forceCopy) { - setAnimationFPS(properties._animationFPS); - somethingChanged = true; - } - - if (properties._glowLevelChanged || forceCopy) { - setGlowLevel(properties._glowLevel); - somethingChanged = true; - } + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS); if (somethingChanged) { bool wantDebug = false; @@ -169,9 +149,11 @@ int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* dat << "old ID=" << oldID << "new ID=" << _id; // radius - memcpy(&_radius, dataAt, sizeof(_radius)); - dataAt += sizeof(_radius); - bytesRead += sizeof(_radius); + float radius; + memcpy(&radius, dataAt, sizeof(radius)); + dataAt += sizeof(radius); + bytesRead += sizeof(radius); + setRadius(radius); // position memcpy(&_position, dataAt, sizeof(_position)); @@ -393,7 +375,7 @@ void ModelEntityItem::debugDump() const { qDebug() << "ModelEntityItem id:" << getEntityItemID(); qDebug() << " edited ago:" << getEditedAgo(); qDebug() << " position:" << getPosition() * (float)TREE_SCALE; - qDebug() << " radius:" << getRadius() * (float)TREE_SCALE; + qDebug() << " dimensions:" << getDimensions() * (float)TREE_SCALE; qDebug() << " model URL:" << getModelURL(); } diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index c8d2abf29a..7af2c08332 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -54,8 +54,12 @@ public: const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } bool hasModel() const { return !_modelURL.isEmpty(); } + + static const QString DEFAULT_MODEL_URL; const QString& getModelURL() const { return _modelURL; } + bool hasAnimation() const { return !_animationURL.isEmpty(); } + static const QString DEFAULT_ANIMATION_URL; const QString& getAnimationURL() const { return _animationURL; } QVector getSittingPoints() const { return _sittingPoints; } @@ -69,8 +73,13 @@ public: // model related properties void setModelURL(const QString& url) { _modelURL = url; } void setAnimationURL(const QString& url) { _animationURL = url; } + static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value) { _animationFrameIndex = value; } + + static const bool DEFAULT_ANIMATION_IS_PLAYING; void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; } + + static const float DEFAULT_ANIMATION_FPS; void setAnimationFPS(float value) { _animationFPS = value; } void setSittingPoints(QVector sittingPoints) { _sittingPoints = sittingPoints; } diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 836cc24524..09364ddbfe 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -43,15 +43,7 @@ EntityItemProperties SphereEntityItem::getProperties() const { bool SphereEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { bool somethingChanged = EntityItem::setProperties(properties, forceCopy); // set the properties in our base class - if (properties.colorChanged() || forceCopy) { - setColor(properties.getColor()); - somethingChanged = true; - } - - if (properties.glowLevelChanged() || forceCopy) { - setGlowLevel(properties.getGlowLevel()); - somethingChanged = true; - } + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); if (somethingChanged) { bool wantDebug = false; diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 65a86a80ca..28fa8f4040 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -39,15 +39,14 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, _oldEntityCube = _existingEntity->getAACube(); _oldEntityBox = _oldEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds - // If the new properties has position OR radius changes, but not both, we need to + // If the new properties has position OR dimension changes, but not both, we need to // get the old property value and set it in our properties in order for our bounds // calculations to work. - if (_properties.containsPositionChange() && !_properties.containsRadiusChange()) { - float oldRadiusInMeters = _existingEntity->getRadius() * (float)TREE_SCALE; - _properties.setRadius(oldRadiusInMeters); + if (_properties.containsPositionChange() && !_properties.containsDimensionsChange()) { + glm::vec3 oldDimensionsInMeters = _existingEntity->getDimensions() * (float)TREE_SCALE; + _properties.setDimensions(oldDimensionsInMeters); } - - if (!_properties.containsPositionChange() && _properties.containsRadiusChange()) { + if (!_properties.containsPositionChange() && _properties.containsDimensionsChange()) { glm::vec3 oldPositionInMeters = _existingEntity->getPosition() * (float)TREE_SCALE; _properties.setPosition(oldPositionInMeters); } diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index f3937dd2e3..5513c09a61 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -75,8 +75,11 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeParticleErase: return 1; + + case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_SUPPORT_SPLIT_MTU; + return VERSION_ENTITIES_SUPPORT_DIMENSIONS; + case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index bb64388dd6..207cf680d3 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -117,6 +117,7 @@ const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1; const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2; const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3; const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU; +const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h diff --git a/tests/octree/src/ModelTests.cpp b/tests/octree/src/ModelTests.cpp index b91963726f..405b4a95d3 100644 --- a/tests/octree/src/ModelTests.cpp +++ b/tests/octree/src/ModelTests.cpp @@ -45,7 +45,7 @@ void EntityTests::entityTreeTests(bool verbose) { entityID.isKnownID = false; // this is a temporary workaround to allow local tree entities to be added with known IDs EntityItemProperties properties; float oneMeter = 1.0f; - float halfMeter = oneMeter / 2.0f; + //float halfMeter = oneMeter / 2.0f; float halfOfDomain = TREE_SCALE * 0.5f; glm::vec3 positionNearOriginInMeters(oneMeter, oneMeter, oneMeter); // when using properties, these are in meter not tree units glm::vec3 positionAtCenterInMeters(halfOfDomain, halfOfDomain, halfOfDomain); @@ -60,7 +60,8 @@ void EntityTests::entityTreeTests(bool verbose) { } properties.setPosition(positionAtCenterInMeters); - properties.setRadius(halfMeter); + // TODO: Fix these unit tests. + //properties.setRadius(halfMeter); //properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx"); tree.addEntity(entityID, properties); @@ -265,8 +266,10 @@ void EntityTests::entityTreeTests(bool verbose) { glm::vec3 randomPositionInTreeUnits = randomPositionInMeters / (float)TREE_SCALE; properties.setPosition(randomPositionInMeters); - properties.setRadius(halfMeter); -//properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx"); + + // TODO: fix these unit tests + //properties.setRadius(halfMeter); + //properties.setModelURL("https://s3-us-west-1.amazonaws.com/highfidelity-public/ozan/theater.fbx"); if (extraVerbose) { qDebug() << "iteration:" << i From 3d066de169080fcda3d965d98509f01c067441fb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 17:42:30 -0700 Subject: [PATCH 04/38] add support for non blocking forms --- .../scripting/WindowScriptingInterface.cpp | 383 +++++++++++++----- .../src/scripting/WindowScriptingInterface.h | 27 +- 2 files changed, 298 insertions(+), 112 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 7a85fc7117..031899689c 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -27,7 +27,11 @@ WindowScriptingInterface* WindowScriptingInterface::getInstance() { return &sharedInstance; } -WindowScriptingInterface::WindowScriptingInterface() { +WindowScriptingInterface::WindowScriptingInterface() : + _editDialog(NULL), + _nonBlockingFormActive(false), + _formResult(QDialog::Rejected) +{ } QScriptValue WindowScriptingInterface::alert(const QString& message) { @@ -84,6 +88,26 @@ QScriptValue WindowScriptingInterface::s3Browse(const QString& nameFilter) { return retVal; } +void WindowScriptingInterface::nonBlockingForm(const QString& title, QScriptValue form) { + QMetaObject::invokeMethod(this, "showNonBlockingForm", Qt::BlockingQueuedConnection, + Q_ARG(const QString&, title), Q_ARG(QScriptValue, form)); +} + +void WindowScriptingInterface::reloadNonBlockingForm(QScriptValue newValues) { + QMetaObject::invokeMethod(this, "doReloadNonBlockingForm", Qt::BlockingQueuedConnection, + Q_ARG(QScriptValue, newValues)); +} + + +QScriptValue WindowScriptingInterface::getNonBlockingFormResult(QScriptValue form) { + QScriptValue retVal; + QMetaObject::invokeMethod(this, "doGetNonBlockingFormResult", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QScriptValue, retVal), + Q_ARG(QScriptValue, form)); + return retVal; +} + + /// Display an alert box /// \param const QString& message message to display /// \return QScriptValue::UndefinedValue @@ -126,12 +150,126 @@ void WindowScriptingInterface::chooseDirectory() { button->setText(buttonText); } +void WindowScriptingInterface::inlineButtonClicked() { + QPushButton* button = reinterpret_cast(sender()); + QString name = button->property("name").toString(); + emit inlineButtonClicked(name); +} + QString WindowScriptingInterface::jsRegExp2QtRegExp(QString string) { // Converts string representation of RegExp from JavaScript format to Qt format. return string.mid(1, string.length() - 2) // No enclosing slashes. .replace("\\/", "/"); // No escaping of forward slash. } +void WindowScriptingInterface::showNonBlockingForm(const QString& title, QScriptValue form) { + if (!form.isArray() || (form.isArray() && form.property("length").toInt32() <= 0)) { + return; + } + + // what should we do if someone calls us while we still think we have a dialog showing??? + if (_editDialog) { + qDebug() << "Show Non-Blocking Form called when form already active."; + return; + } + + _form = form; + _editDialog = createForm(title, _form); + _nonBlockingFormActive = true; + + connect(_editDialog, SIGNAL(accepted()), this, SLOT(nonBlockingFormAccepted())); + connect(_editDialog, SIGNAL(rejected()), this, SLOT(nonBlockingFormRejected())); + + _editDialog->setModal(true); + _editDialog->show(); +} + +void WindowScriptingInterface::doReloadNonBlockingForm(QScriptValue newValues) { + if (!newValues.isArray() || (newValues.isArray() && newValues.property("length").toInt32() <= 0)) { + return; + } + + // what should we do if someone calls us while we still think we have a dialog showing??? + if (!_editDialog) { + qDebug() << "Reload Non-Blocking Form called when no form is active."; + return; + } + + for (int i = 0; i < newValues.property("length").toInt32(); ++i) { + QScriptValue item = newValues.property(i); + + if (item.property("oldIndex").isValid()) { + int oldIndex = item.property("oldIndex").toInt32(); + QScriptValue oldItem = _form.property(oldIndex); + if (oldItem.isValid()) { + QLineEdit* originalEdit = _edits[oldItem.property("editIndex").toInt32()]; + originalEdit->setText(item.property("value").toString()); + } + } + } +} + + +bool WindowScriptingInterface::nonBlockingFormActive() { + return _nonBlockingFormActive; +} + +QScriptValue WindowScriptingInterface::doGetNonBlockingFormResult(QScriptValue array) { + QScriptValue retVal; + + if (_formResult == QDialog::Accepted) { + int e = -1; + int d = -1; + for (int i = 0; i < _form.property("length").toInt32(); ++i) { + QScriptValue item = _form.property(i); + QScriptValue value = item.property("value"); + + if (item.property("button").toString() != "") { + // Nothing to do + } else if (item.property("type").toString() == "inlineButton") { + // Nothing to do + } else if (item.property("type").toString() == "header") { + // Nothing to do + } else if (item.property("directory").toString() != "") { + d += 1; + value = _directories.at(d)->property("path").toString(); + item.setProperty("directory", value); + _form.setProperty(i, item); + } else { + e += 1; + bool ok = true; + if (value.isNumber()) { + value = _edits.at(e)->text().toDouble(&ok); + } else if (value.isString()) { + value = _edits.at(e)->text(); + } else if (value.isBool()) { + if (_edits.at(e)->text() == "true") { + value = true; + } else if (_edits.at(e)->text() == "false") { + value = false; + } else { + ok = false; + } + } + if (ok) { + item.setProperty("value", value); + _form.setProperty(i, item); + } + } + } + } + + delete _editDialog; + _editDialog = NULL; + _form = QScriptValue(); + _edits.clear(); + _directories.clear(); + + array = _form; + return (_formResult == QDialog::Accepted); +} + + /// Display a form layout with an edit box /// \param const QString& title title to display /// \param const QScriptValue form to display as an array of objects: @@ -140,129 +278,152 @@ QString WindowScriptingInterface::jsRegExp2QtRegExp(QString string) { /// - button ("Cancel") /// \return QScriptValue `true` if 'OK' was clicked, `false` otherwise QScriptValue WindowScriptingInterface::showForm(const QString& title, QScriptValue form) { + if (form.isArray() && form.property("length").toInt32() <= 0) { + return false; + } + QDialog* editDialog = createForm(title, form); - if (form.isArray() && form.property("length").toInt32() > 0) { - QDialog* editDialog = new QDialog(Application::getInstance()->getWindow()); - editDialog->setWindowTitle(title); - - bool cancelButton = false; - - QVBoxLayout* layout = new QVBoxLayout(); - editDialog->setLayout(layout); - - QScrollArea* area = new QScrollArea(); - layout->addWidget(area); - area->setWidgetResizable(true); - QWidget* container = new QWidget(); - QFormLayout* formLayout = new QFormLayout(); - container->setLayout(formLayout); - container->sizePolicy().setHorizontalStretch(1); - formLayout->setRowWrapPolicy(QFormLayout::DontWrapRows); - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - formLayout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop); - formLayout->setLabelAlignment(Qt::AlignLeft); - - area->setWidget(container); - - QVector edits; - QVector directories; + int result = editDialog->exec(); + + if (result == QDialog::Accepted) { + int e = -1; + int d = -1; for (int i = 0; i < form.property("length").toInt32(); ++i) { QScriptValue item = form.property(i); + QScriptValue value = item.property("value"); if (item.property("button").toString() != "") { - cancelButton = cancelButton || item.property("button").toString().toLower() == "cancel"; - + // Nothing to do + } else if (item.property("type").toString() == "inlineButton") { + // Nothing to do + } else if (item.property("type").toString() == "header") { + // Nothing to do } else if (item.property("directory").toString() != "") { - QString path = item.property("directory").toString(); - QString title = item.property("title").toString(); - if (title == "") { - title = "Choose Directory"; - } - QString displayAsString = item.property("displayAs").toString(); - QRegExp displayAs = QRegExp(displayAsString != "" ? jsRegExp2QtRegExp(displayAsString) : "^(.*)$"); - QString validateAsString = item.property("validateAs").toString(); - QRegExp validateAs = QRegExp(validateAsString != "" ? jsRegExp2QtRegExp(validateAsString) : ".*"); - QString errorMessage = item.property("errorMessage").toString(); - if (errorMessage == "") { - errorMessage = "Invalid directory"; - } - - QPushButton* directory = new QPushButton(displayAs.cap(1)); - directory->setProperty("title", title); - directory->setProperty("path", path); - directory->setProperty("displayAs", displayAs); - directory->setProperty("validateAs", validateAs); - directory->setProperty("errorMessage", errorMessage); - displayAs.indexIn(path); - directory->setText(displayAs.cap(1) != "" ? displayAs.cap(1) : "."); - - directory->setMinimumWidth(200); - directories.push_back(directory); - - formLayout->addRow(new QLabel(item.property("label").toString()), directory); - connect(directory, SIGNAL(clicked(bool)), SLOT(chooseDirectory())); - + d += 1; + value = _directories.at(d)->property("path").toString(); + item.setProperty("directory", value); + form.setProperty(i, item); } else { - QLineEdit* edit = new QLineEdit(item.property("value").toString()); - edit->setMinimumWidth(200); - edits.push_back(edit); - formLayout->addRow(new QLabel(item.property("label").toString()), edit); - } - } - - QDialogButtonBox* buttons = new QDialogButtonBox( - QDialogButtonBox::Ok - | (cancelButton ? QDialogButtonBox::Cancel : QDialogButtonBox::NoButton) - ); - connect(buttons, SIGNAL(accepted()), editDialog, SLOT(accept())); - connect(buttons, SIGNAL(rejected()), editDialog, SLOT(reject())); - layout->addWidget(buttons); - - int result = editDialog->exec(); - if (result == QDialog::Accepted) { - int e = -1; - int d = -1; - for (int i = 0; i < form.property("length").toInt32(); ++i) { - QScriptValue item = form.property(i); - QScriptValue value = item.property("value"); - - if (item.property("button").toString() != "") { - // Nothing to do - } else if (item.property("directory").toString() != "") { - d += 1; - value = directories.at(d)->property("path").toString(); - item.setProperty("directory", value); + e += 1; + bool ok = true; + if (value.isNumber()) { + value = _edits.at(e)->text().toDouble(&ok); + } else if (value.isString()) { + value = _edits.at(e)->text(); + } else if (value.isBool()) { + if (_edits.at(e)->text() == "true") { + value = true; + } else if (_edits.at(e)->text() == "false") { + value = false; + } else { + ok = false; + } + } + if (ok) { + item.setProperty("value", value); form.setProperty(i, item); - } else { - e += 1; - bool ok = true; - if (value.isNumber()) { - value = edits.at(e)->text().toDouble(&ok); - } else if (value.isString()) { - value = edits.at(e)->text(); - } else if (value.isBool()) { - if (edits.at(e)->text() == "true") { - value = true; - } else if (edits.at(e)->text() == "false") { - value = false; - } else { - ok = false; - } - } - if (ok) { - item.setProperty("value", value); - form.setProperty(i, item); - } } } } - - delete editDialog; - - return (result == QDialog::Accepted); } - return false; + delete editDialog; + _edits.clear(); + _directories.clear(); + return (result == QDialog::Accepted); +} + + + +QDialog* WindowScriptingInterface::createForm(const QString& title, QScriptValue form) { + QDialog* editDialog = new QDialog(Application::getInstance()->getWindow()); + editDialog->setWindowTitle(title); + + bool cancelButton = false; + + QVBoxLayout* layout = new QVBoxLayout(); + editDialog->setLayout(layout); + + QScrollArea* area = new QScrollArea(); + layout->addWidget(area); + area->setWidgetResizable(true); + QWidget* container = new QWidget(); + QFormLayout* formLayout = new QFormLayout(); + container->setLayout(formLayout); + container->sizePolicy().setHorizontalStretch(1); + formLayout->setRowWrapPolicy(QFormLayout::DontWrapRows); + formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + formLayout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop); + formLayout->setLabelAlignment(Qt::AlignLeft); + + area->setWidget(container); + + for (int i = 0; i < form.property("length").toInt32(); ++i) { + QScriptValue item = form.property(i); + + if (item.property("button").toString() != "") { + cancelButton = cancelButton || item.property("button").toString().toLower() == "cancel"; + + } else if (item.property("directory").toString() != "") { + QString path = item.property("directory").toString(); + QString title = item.property("title").toString(); + if (title == "") { + title = "Choose Directory"; + } + QString displayAsString = item.property("displayAs").toString(); + QRegExp displayAs = QRegExp(displayAsString != "" ? jsRegExp2QtRegExp(displayAsString) : "^(.*)$"); + QString validateAsString = item.property("validateAs").toString(); + QRegExp validateAs = QRegExp(validateAsString != "" ? jsRegExp2QtRegExp(validateAsString) : ".*"); + QString errorMessage = item.property("errorMessage").toString(); + if (errorMessage == "") { + errorMessage = "Invalid directory"; + } + + QPushButton* directory = new QPushButton(displayAs.cap(1)); + directory->setProperty("title", title); + directory->setProperty("path", path); + directory->setProperty("displayAs", displayAs); + directory->setProperty("validateAs", validateAs); + directory->setProperty("errorMessage", errorMessage); + displayAs.indexIn(path); + directory->setText(displayAs.cap(1) != "" ? displayAs.cap(1) : "."); + + directory->setMinimumWidth(200); + _directories.push_back(directory); + + formLayout->addRow(new QLabel(item.property("label").toString()), directory); + connect(directory, SIGNAL(clicked(bool)), SLOT(chooseDirectory())); + + } else if (item.property("type").toString() == "inlineButton") { + QString buttonLabel = item.property("buttonLabel").toString(); + + QPushButton* inlineButton = new QPushButton(buttonLabel); + inlineButton->setMinimumWidth(200); + inlineButton->setProperty("name", item.property("name").toString()); + formLayout->addRow(new QLabel(item.property("label").toString()), inlineButton); + connect(inlineButton, SIGNAL(clicked(bool)), SLOT(inlineButtonClicked())); + + } else if (item.property("type").toString() == "header") { + formLayout->addRow(new QLabel(item.property("label").toString())); + } else { + QLineEdit* edit = new QLineEdit(item.property("value").toString()); + edit->setMinimumWidth(200); + int editIndex = _edits.size(); + _edits.push_back(edit); + item.setProperty("editIndex", editIndex); + formLayout->addRow(new QLabel(item.property("label").toString()), edit); + } + } + + QDialogButtonBox* buttons = new QDialogButtonBox( + QDialogButtonBox::Ok + | (cancelButton ? QDialogButtonBox::Cancel : QDialogButtonBox::NoButton) + ); + connect(buttons, SIGNAL(accepted()), editDialog, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), editDialog, SLOT(reject())); + layout->addWidget(buttons); + + return editDialog; } /// Display a prompt with a text box diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index ec7e1b224e..84f6da287c 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -34,6 +34,14 @@ public slots: QScriptValue save(const QString& title = "", const QString& directory = "", const QString& nameFilter = ""); QScriptValue s3Browse(const QString& nameFilter = ""); + void nonBlockingForm(const QString& title, QScriptValue array); + void reloadNonBlockingForm(QScriptValue array); + QScriptValue getNonBlockingFormResult(QScriptValue array); + +signals: + void inlineButtonClicked(const QString& name); + void nonBlockingFormClosed(); + private slots: QScriptValue showAlert(const QString& message); QScriptValue showConfirm(const QString& message); @@ -42,12 +50,29 @@ private slots: QScriptValue showBrowse(const QString& title, const QString& directory, const QString& nameFilter, QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen); QScriptValue showS3Browse(const QString& nameFilter); + + void showNonBlockingForm(const QString& title, QScriptValue array); + void doReloadNonBlockingForm(QScriptValue array); + bool nonBlockingFormActive(); + QScriptValue doGetNonBlockingFormResult(QScriptValue array); + void chooseDirectory(); + void inlineButtonClicked(); + + void nonBlockingFormAccepted() { _nonBlockingFormActive = false; _formResult = QDialog::Accepted; emit nonBlockingFormClosed(); } + void nonBlockingFormRejected() { _nonBlockingFormActive = false; _formResult = QDialog::Rejected; emit nonBlockingFormClosed(); } private: WindowScriptingInterface(); - QString jsRegExp2QtRegExp(QString string); + QDialog* createForm(const QString& title, QScriptValue form); + + QDialog* _editDialog; + QScriptValue _form; + bool _nonBlockingFormActive; + int _formResult; + QVector _edits; + QVector _directories; }; #endif // hifi_WindowScriptingInterface_h From df0dc3bdd76adcafb2d13d15d282246c9018f5ef Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 17:44:23 -0700 Subject: [PATCH 05/38] add getUnscaledMeshExtents to FBXGeometry --- libraries/fbx/src/FBXReader.cpp | 13 +++++++++++++ libraries/fbx/src/FBXReader.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 79deef236a..6f87bcf1f8 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -80,6 +80,19 @@ bool FBXGeometry::hasBlendedMeshes() const { return false; } +Extents FBXGeometry::getUnscaledMeshExtents() const { + const Extents& extents = meshExtents; + + // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which + // is captured in the offset matrix + glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f)); + glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f)); + Extents scaledExtents = { minimum, maximum }; + + return scaledExtents; +} + + static int fbxGeometryMetaTypeId = qRegisterMetaType(); static int fbxAnimationFrameMetaTypeId = qRegisterMetaType(); static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType >(); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index b5340978c1..d07a33f3d4 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -234,6 +234,9 @@ public: QStringList getJointNames() const; bool hasBlendedMeshes() const; + + /// Returns the unscaled extents of the model's mesh + Extents getUnscaledMeshExtents() const; }; Q_DECLARE_METATYPE(FBXGeometry) From 44230a315bc19ac637c4a288e1a233178328f9ea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 17:45:50 -0700 Subject: [PATCH 06/38] add naturalDimensions and moved sitting points to exclusively be in properties --- libraries/entities/src/EntityItemProperties.cpp | 5 +++++ libraries/entities/src/EntityItemProperties.h | 7 +++++++ .../entities/src/EntityScriptingInterface.cpp | 16 +++++++++------- libraries/entities/src/EntityTree.h | 3 +++ libraries/entities/src/ModelEntityItem.cpp | 1 - libraries/entities/src/ModelEntityItem.h | 3 --- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f79f64de25..12eb8eff92 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -56,6 +56,7 @@ EntityItemProperties::EntityItemProperties() : _animationFPS(ModelEntityItem::DEFAULT_ANIMATION_FPS), _glowLevel(0.0f), + _naturalDimensions(1.0f, 1.0f, 1.0f), _colorChanged(false), _modelURLChanged(false), _animationURLChanged(false), @@ -161,6 +162,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons properties.setProperty("position", position); QScriptValue dimensions = vec3toScriptValue(engine, _dimensions); properties.setProperty("dimensions", dimensions); + + QScriptValue naturalDimensions = vec3toScriptValue(engine, _naturalDimensions); + properties.setProperty("naturalDimensions", naturalDimensions); + QScriptValue rotation = quatToScriptValue(engine, _rotation); properties.setProperty("rotation", rotation); properties.setProperty("mass", _mass); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 881a0b4afc..9c93a11cfc 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -207,6 +207,12 @@ public: void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; } void markAllChanged(); + QVector getSittingPoints() const { return _sittingPoints; } + void setSittingPoints(QVector sittingPoints) { _sittingPoints = sittingPoints; } + + const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; } + void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; } + private: void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } @@ -248,6 +254,7 @@ private: float _animationFPS; float _glowLevel; QVector _sittingPoints; + glm::vec3 _naturalDimensions; bool _colorChanged; bool _modelURLChanged; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 971d7066eb..3c34a6f6c7 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -68,18 +68,20 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(EntityItemID EntityItem* entity = const_cast(_entityTree->findEntityByEntityItemID(identity)); if (entity) { - - // TODO: improve sitting points in the future, for now we've included the old model behavior for entity - // types that are models + results = entity->getProperties(); + + // TODO: improve sitting points and naturalDimensions in the future, + // for now we've included the old sitting points model behavior for entity types that are models + // we've also added this hack for setting natural dimensions of models if (entity->getType() == EntityTypes::Model) { - ModelEntityItem* model = dynamic_cast(entity); const FBXGeometry* geometry = _entityTree->getGeometryForEntity(entity); if (geometry) { - model->setSittingPoints(geometry->sittingPoints); + results.setSittingPoints(geometry->sittingPoints); + Extents meshExtents = geometry->getUnscaledMeshExtents(); + results.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum); } } - - results = entity->getProperties(); + } else { results.setIsUnknownID(); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 47ae04846d..d97a87faca 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -122,6 +122,9 @@ public: const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem) { return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL; } + const Model* getModelForEntityItem(const EntityItem* entityItem) { + return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL; + } EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/; void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 7989d085c6..83958c329b 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -47,7 +47,6 @@ EntityItemProperties ModelEntityItem::getProperties() const { properties._animationIsPlaying = getAnimationIsPlaying(); properties._animationFrameIndex = getAnimationFrameIndex(); properties._animationFPS = getAnimationFPS(); - properties._sittingPoints = getSittingPoints(); // sitting support properties._colorChanged = false; properties._modelURLChanged = false; properties._animationURLChanged = false; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 7af2c08332..4ed47d4894 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -61,7 +61,6 @@ public: bool hasAnimation() const { return !_animationURL.isEmpty(); } static const QString DEFAULT_ANIMATION_URL; const QString& getAnimationURL() const { return _animationURL; } - QVector getSittingPoints() const { return _sittingPoints; } void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); } void setColor(const xColor& value) { @@ -81,7 +80,6 @@ public: static const float DEFAULT_ANIMATION_FPS; void setAnimationFPS(float value) { _animationFPS = value; } - void setSittingPoints(QVector sittingPoints) { _sittingPoints = sittingPoints; } void mapJoints(const QStringList& modelJointNames); QVector getAnimationFrame(); @@ -101,7 +99,6 @@ protected: rgbColor _color; QString _modelURL; - QVector _sittingPoints; quint64 _lastAnimated; QString _animationURL; From a7fda032d1b699c3ddb3ab455f2b58a49ad7557a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 17:46:31 -0700 Subject: [PATCH 07/38] added reset dimensions support to editModels.js --- examples/editModels.js | 173 +++++++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 43 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 2888141bf1..80fd1064ef 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2422,9 +2422,14 @@ function Tooltip() { text += "Pitch: " + angles.x.toFixed(this.decimals) + "\n" text += "Yaw: " + angles.y.toFixed(this.decimals) + "\n" text += "Roll: " + angles.z.toFixed(this.decimals) + "\n" - text += "Width: " + properties.dimensions.x.toFixed(this.decimals) + "\n" - text += "Height: " + properties.dimensions.y.toFixed(this.decimals) + "\n" - text += "Depth: " + properties.dimensions.z.toFixed(this.decimals) + "\n" + text += "Dimensions: " + properties.dimensions.x.toFixed(this.decimals) + ", " + + properties.dimensions.y.toFixed(this.decimals) + ", " + + properties.dimensions.z.toFixed(this.decimals) + "\n"; + + text += "Natural Dimensions: " + properties.naturalDimensions.x.toFixed(this.decimals) + ", " + + properties.naturalDimensions.y.toFixed(this.decimals) + ", " + + properties.naturalDimensions.z.toFixed(this.decimals) + "\n"; + text += "ID: " + properties.id + "\n" if (properties.type == "Model") { text += "Model URL: " + properties.modelURL + "\n" @@ -2780,6 +2785,13 @@ Controller.mouseReleaseEvent.connect(mouseReleaseEvent); setupModelMenus(); +var propertiesForEditedEntity; +var editEntityFormArray; +var editModelID = -1; +var dimensionX; +var dimensionY; +var dimensionZ; + function handeMenuEvent(menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); if (menuItem == "Delete") { @@ -2808,7 +2820,7 @@ function handeMenuEvent(menuItem) { print(" Delete Entity.... not holding..."); } } else if (menuItem == "Edit Properties...") { - var editModelID = -1; + editModelID = -1; if (leftController.grabbing) { print(" Edit Properties.... leftController.entityID="+ leftController.entityID); editModelID = leftController.entityID; @@ -2824,85 +2836,93 @@ function handeMenuEvent(menuItem) { if (editModelID != -1) { print(" Edit Properties.... about to edit properties..."); - var properties = Entities.getEntityProperties(editModelID); + propertiesForEditedEntity = Entities.getEntityProperties(editModelID); + var properties = propertiesForEditedEntity; var array = new Array(); + var index = 0; var decimals = 3; if (properties.type == "Model") { array.push({ label: "Model URL:", value: properties.modelURL }); + index++; array.push({ label: "Animation URL:", value: properties.animationURL }); + index++; array.push({ label: "Animation is playing:", value: properties.animationIsPlaying }); + index++; array.push({ label: "Animation FPS:", value: properties.animationFPS }); + index++; array.push({ label: "Animation Frame:", value: properties.animationFrameIndex }); + index++; } + array.push({ label: "Position:", type: "header" }); + index++; array.push({ label: "X:", value: properties.position.x.toFixed(decimals) }); + index++; array.push({ label: "Y:", value: properties.position.y.toFixed(decimals) }); + index++; array.push({ label: "Z:", value: properties.position.z.toFixed(decimals) }); + index++; + + array.push({ label: "Rotation:", type: "header" }); + index++; var angles = Quat.safeEulerAngles(properties.rotation); array.push({ label: "Pitch:", value: angles.x.toFixed(decimals) }); + index++; array.push({ label: "Yaw:", value: angles.y.toFixed(decimals) }); + index++; array.push({ label: "Roll:", value: angles.z.toFixed(decimals) }); + index++; + array.push({ label: "Dimensions:", type: "header" }); + index++; array.push({ label: "Width:", value: properties.dimensions.x.toFixed(decimals) }); + dimensionX = index; + index++; array.push({ label: "Height:", value: properties.dimensions.y.toFixed(decimals) }); + dimensionY = index; + index++; array.push({ label: "Depth:", value: properties.dimensions.z.toFixed(decimals) }); + dimensionZ = index; + index++; + array.push({ label: "", type: "inlineButton", buttonLabel: "Reset to Natural Dimensions", name: "resetDimensions" }); + index++; + array.push({ label: "Velocity:", type: "header" }); + index++; array.push({ label: "Velocity X:", value: properties.velocity.x.toFixed(decimals) }); + index++; array.push({ label: "Velocity Y:", value: properties.velocity.y.toFixed(decimals) }); + index++; array.push({ label: "Velocity Z:", value: properties.velocity.z.toFixed(decimals) }); + index++; array.push({ label: "Damping:", value: properties.damping.toFixed(decimals) }); + index++; array.push({ label: "Gravity X:", value: properties.gravity.x.toFixed(decimals) }); + index++; array.push({ label: "Gravity Y:", value: properties.gravity.y.toFixed(decimals) }); + index++; array.push({ label: "Gravity Z:", value: properties.gravity.z.toFixed(decimals) }); + index++; array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) }); + index++; if (properties.type == "Box" || properties.type == "Sphere") { + array.push({ label: "Color:", type: "header" }); + index++; array.push({ label: "Red:", value: properties.color.red }); + index++; array.push({ label: "Green:", value: properties.color.green }); + index++; array.push({ label: "Blue:", value: properties.color.blue }); + index++; } array.push({ button: "Cancel" }); - - if (Window.form("Edit Properties", array)) { - var index = 0; - if (properties.type == "Model") { - properties.modelURL = array[index++].value; - properties.animationURL = array[index++].value; - properties.animationIsPlaying = array[index++].value; - properties.animationFPS = array[index++].value; - properties.animationFrameIndex = array[index++].value; - } - properties.position.x = array[index++].value; - properties.position.y = array[index++].value; - properties.position.z = array[index++].value; - angles.x = array[index++].value; - angles.y = array[index++].value; - angles.z = array[index++].value; - properties.rotation = Quat.fromVec3Degrees(angles); + index++; - properties.dimensions.x = array[index++].value; - properties.dimensions.y = array[index++].value; - properties.dimensions.z = array[index++].value; - - properties.velocity.x = array[index++].value; - properties.velocity.y = array[index++].value; - properties.velocity.z = array[index++].value; - properties.damping = array[index++].value; - properties.gravity.x = array[index++].value; - properties.gravity.y = array[index++].value; - properties.gravity.z = array[index++].value; - properties.lifetime = array[index++].value; // give ourselves that many more seconds - - if (properties.type == "Box" || properties.type == "Sphere") { - properties.color.red = array[index++].value; - properties.color.green = array[index++].value; - properties.color.blue = array[index++].value; - } - Entities.editEntity(editModelID, properties); - } - modelSelected = false; + editEntityFormArray = array; + Window.nonBlockingForm("Edit Properties", array); } } else if (menuItem == "Paste Models") { modelImporter.paste(); @@ -2963,3 +2983,70 @@ Controller.keyReleaseEvent.connect(function (event) { handeMenuEvent("Delete"); } }); + +Window.inlineButtonClicked.connect(function (name) { + if (name == "resetDimensions") { + var decimals = 3; + + Window.reloadNonBlockingForm([ + { value: propertiesForEditedEntity.naturalDimensions.x.toFixed(decimals), oldIndex: dimensionX }, + { value: propertiesForEditedEntity.naturalDimensions.y.toFixed(decimals), oldIndex: dimensionY }, + { value: propertiesForEditedEntity.naturalDimensions.z.toFixed(decimals), oldIndex: dimensionZ } + ]); + } +}); +Window.nonBlockingFormClosed.connect(function() { + print("JAVASCRIPT.... nonBlockingFormClosed...."); + array = editEntityFormArray; + if (Window.getNonBlockingFormResult(array)) { + print("getNonBlockingFormResult()...."); + + var properties = propertiesForEditedEntity; + var index = 0; + if (properties.type == "Model") { + properties.modelURL = array[index++].value; + properties.animationURL = array[index++].value; + properties.animationIsPlaying = array[index++].value; + properties.animationFPS = array[index++].value; + properties.animationFrameIndex = array[index++].value; + } + index++; // skip header + properties.position.x = array[index++].value; + properties.position.y = array[index++].value; + properties.position.z = array[index++].value; + + index++; // skip header + var angles = Quat.safeEulerAngles(properties.rotation); + angles.x = array[index++].value; + angles.y = array[index++].value; + angles.z = array[index++].value; + properties.rotation = Quat.fromVec3Degrees(angles); + + index++; // skip header + properties.dimensions.x = array[index++].value; + properties.dimensions.y = array[index++].value; + properties.dimensions.z = array[index++].value; + index++; // skip reset button + + index++; // skip header + properties.velocity.x = array[index++].value; + properties.velocity.y = array[index++].value; + properties.velocity.z = array[index++].value; + properties.damping = array[index++].value; + properties.gravity.x = array[index++].value; + properties.gravity.y = array[index++].value; + properties.gravity.z = array[index++].value; + properties.lifetime = array[index++].value; // give ourselves that many more seconds + + if (properties.type == "Box" || properties.type == "Sphere") { + index++; // skip header + properties.color.red = array[index++].value; + properties.color.green = array[index++].value; + properties.color.blue = array[index++].value; + } + Entities.editEntity(editModelID, properties); + } + modelSelected = false; +}); + + From fd59f58989e6e89d2cc4c23bc29317a0b8ad6a0a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 20:18:01 -0700 Subject: [PATCH 08/38] added script property to EntityProperties setting/getting and scripting --- examples/editModels.js | 4 +++- libraries/entities/src/EntityItemProperties.cpp | 4 ++-- libraries/entities/src/EntityItemProperties.h | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 80fd1064ef..47a6c1343b 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1313,6 +1313,7 @@ var toolBar = (function () { position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, color: { red: 255, green: 0, blue: 0 } + }); } else { print("Can't create box: Box would be out of bounds."); @@ -2394,7 +2395,7 @@ function Tooltip() { this.x = 285; this.y = 115; this.width = 500; - this.height = 145; + this.height = 180; // 145; this.margin = 5; this.decimals = 3; @@ -2448,6 +2449,7 @@ function Tooltip() { text += "Lifetime: " + properties.lifetime + "\n" } text += "Age: " + properties.ageAsText + "\n" + text += "Script: " + properties.script + "\n" Overlays.editOverlay(this.textOverlay, { text: text }); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 12eb8eff92..c47484dbe7 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -552,7 +552,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_GRAVITY, appendValue, properties.getGravity()); APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, properties.getDamping()); APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, properties.getLifetime()); - //APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, properties.getScript()); // not supported by edit messages + APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, properties.getScript()); APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL()); @@ -744,7 +744,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRAVITY, glm::vec3, setGravity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DAMPING, float, setDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime); - //READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); // not yet supported by edit messages... + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_SCRIPT,setScript); READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_COLOR, setColor); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 9c93a11cfc..f94b104457 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -165,6 +165,7 @@ public: bool getAnimationIsPlaying() const { return _animationIsPlaying; } float getAnimationFPS() const { return _animationFPS; } float getGlowLevel() const { return _glowLevel; } + const QString& getScript() const { return _script; } // model related properties void setColor(const xColor& value) { _color = value; _colorChanged = true; } @@ -174,6 +175,7 @@ public: void setAnimationIsPlaying(bool value) { _animationIsPlaying = value; _animationIsPlayingChanged = true; } void setAnimationFPS(float value) { _animationFPS = value; _animationFPSChanged = true; } void setGlowLevel(float value) { _glowLevel = value; _glowLevelChanged = true; } + void setScript(const QString& value) { _script = value; _scriptChanged = true; } static bool encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, From fac7d20c8a56798e0b02ec41b945f2cd53223f9c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 9 Sep 2014 20:38:58 -0700 Subject: [PATCH 09/38] basic support for PROP_REGISTRATION_POINT, PROP_ROTATIONAL_VELOCITY, and PROP_VISIBLE --- libraries/entities/src/EntityItem.cpp | 25 +++++++++++-------- libraries/entities/src/EntityItem.h | 15 +++++++++++ .../entities/src/EntityItemProperties.cpp | 6 +++++ libraries/entities/src/EntityItemProperties.h | 4 +++ 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e64b1d503d..40c97b1877 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -37,6 +37,9 @@ const glm::vec3 EntityItem::DEFAULT_GRAVITY = EntityItem::NO_GRAVITY; const QString EntityItem::DEFAULT_SCRIPT = QString(""); const glm::quat EntityItem::DEFAULT_ROTATION; const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); +const glm::vec3 EntityItem::DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center +const glm::quat EntityItem::DEFAULT_ROTATIONAL_VELOCITY; +const bool EntityItem::DEFAULT_VISIBLE = true; void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { @@ -97,9 +100,9 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_DAMPING; requestedProperties += PROP_LIFETIME; requestedProperties += PROP_SCRIPT; - // TODO: add PROP_REGISTRATION_POINT, - // TODO: add PROP_ROTATIONAL_VELOCITY, - // TODO: add PROP_VISIBLE, + requestedProperties += PROP_REGISTRATION_POINT; + requestedProperties += PROP_ROTATIONAL_VELOCITY; + requestedProperties += PROP_VISIBLE; return requestedProperties; } @@ -204,9 +207,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_DAMPING, appendValue, getDamping()); APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime()); APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript()); - // TODO: add PROP_REGISTRATION_POINT, - // TODO: add PROP_ROTATIONAL_VELOCITY, - // TODO: add PROP_VISIBLE, + APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint()); + APPEND_ENTITY_PROPERTY(PROP_ROTATIONAL_VELOCITY, appendValue, getRotationalVelocity()); + APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -450,9 +453,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_DAMPING, float, _damping); READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime); READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); - // TODO: add PROP_REGISTRATION_POINT, - // TODO: add PROP_ROTATIONAL_VELOCITY, - // TODO: add PROP_VISIBLE, + READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); + READ_ENTITY_PROPERTY_QUAT(PROP_ROTATIONAL_VELOCITY, _rotationalVelocity); + READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -660,8 +663,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - //SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotationalVelocity, setRotationalVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotationalVelocity, setRotationalVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); if (somethingChanged) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e7cf296f44..8381c74772 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -194,6 +194,18 @@ public: static const QString DEFAULT_SCRIPT; const QString& getScript() const { return _script; } void setScript(const QString& value) { _script = value; } + + static const glm::vec3 DEFAULT_REGISTRATION_POINT; + const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity + void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; } /// registration point as ratio of entity + + static const glm::quat DEFAULT_ROTATIONAL_VELOCITY; + const glm::quat& getRotationalVelocity() const { return _rotationalVelocity; } + void setRotationalVelocity(const glm::quat& value) { _rotationalVelocity = value; } + + static const bool DEFAULT_VISIBLE; + bool getVisible() const { return _visible; } + void setVisible(bool value) { _visible = value; } protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -218,6 +230,9 @@ protected: float _damping; float _lifetime; QString _script; + glm::vec3 _registrationPoint; + glm::quat _rotationalVelocity; + bool _visible; // NOTE: Radius support is obsolete, but these private helper functions are available for this class to // parse old data streams diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index c47484dbe7..5c4e215e9a 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -37,6 +37,9 @@ EntityItemProperties::EntityItemProperties() : _damping(EntityItem::DEFAULT_DAMPING), _lifetime(EntityItem::DEFAULT_LIFETIME), _script(EntityItem::DEFAULT_SCRIPT), + _registrationPoint(EntityItem::DEFAULT_REGISTRATION_POINT), + _rotationalVelocity(EntityItem::DEFAULT_ROTATIONAL_VELOCITY), + _visible(EntityItem::DEFAULT_VISIBLE), _positionChanged(false), _dimensionsChanged(false), @@ -47,6 +50,9 @@ EntityItemProperties::EntityItemProperties() : _dampingChanged(false), _lifetimeChanged(false), _scriptChanged(false), + _registrationPointChanged(false), + _rotationalVelocityChanged(false), + _visibleChanged(false), _color(), _modelURL(""), diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index f94b104457..3a5bfbe8f0 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -234,6 +234,8 @@ private: float _lifetime; QString _script; glm::vec3 _registrationPoint; + glm::quat _rotationalVelocity; + bool _visible; bool _positionChanged; bool _dimensionsChanged; @@ -245,6 +247,8 @@ private: bool _lifetimeChanged; bool _scriptChanged; bool _registrationPointChanged; + bool _rotationalVelocityChanged; + bool _visibleChanged; // TODO: this need to be more generic. for now, we're going to have the properties class support these as // named getter/setters, but we want to move them to generic types... From 53da483381bbd69207e3e6b364f1f15f16b76b42 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 09:05:46 -0700 Subject: [PATCH 10/38] more work on visible, registration point, and rotational velocity --- examples/editModels.js | 6 +- interface/src/entities/EntityTreeRenderer.cpp | 39 ++--- libraries/entities/src/EntityItem.cpp | 37 +++-- libraries/entities/src/EntityItem.h | 8 +- .../entities/src/EntityItemProperties.cpp | 142 ++++++++++-------- libraries/entities/src/EntityItemProperties.h | 19 +++ 6 files changed, 149 insertions(+), 102 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 47a6c1343b..17300931aa 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2909,6 +2909,9 @@ function handeMenuEvent(menuItem) { array.push({ label: "Lifetime:", value: properties.lifetime.toFixed(decimals) }); index++; + + array.push({ label: "Visible:", value: properties.visible }); + index++; if (properties.type == "Box" || properties.type == "Sphere") { array.push({ label: "Color:", type: "header" }); @@ -3038,7 +3041,8 @@ Window.nonBlockingFormClosed.connect(function() { properties.gravity.x = array[index++].value; properties.gravity.y = array[index++].value; properties.gravity.z = array[index++].value; - properties.lifetime = array[index++].value; // give ourselves that many more seconds + properties.lifetime = array[index++].value; + properties.visible = array[index++].value; if (properties.type == "Box" || properties.type == "Sphere") { index++; // skip header diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 495952f895..4d8d20f4e0 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -214,27 +214,30 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) for (uint16_t i = 0; i < numberOfEntities; i++) { EntityItem* entityItem = entityItems[i]; - // render entityItem - AACube entityCube = entityItem->getAACube(); - - entityCube.scale(TREE_SCALE); - // TODO: some entity types (like lights) might want to be rendered even - // when they are outside of the view frustum... - float distance = distanceToCamera(entityCube.calcCenter(), *args->_viewFrustum); - if (shouldRenderEntity(entityCube.getLargestDimension(), distance) && - args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) { + if (entityItem->isVisible()) { + // render entityItem + AACube entityCube = entityItem->getAACube(); - Glower* glower = NULL; - if (entityItem->getGlowLevel() > 0.0f) { - glower = new Glower(entityItem->getGlowLevel()); + entityCube.scale(TREE_SCALE); + + // TODO: some entity types (like lights) might want to be rendered even + // when they are outside of the view frustum... + float distance = distanceToCamera(entityCube.calcCenter(), *args->_viewFrustum); + if (shouldRenderEntity(entityCube.getLargestDimension(), distance) && + args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) { + + Glower* glower = NULL; + if (entityItem->getGlowLevel() > 0.0f) { + glower = new Glower(entityItem->getGlowLevel()); + } + entityItem->render(args); + if (glower) { + delete glower; + } + } else { + args->_itemsOutOfView++; } - entityItem->render(args); - if (glower) { - delete glower; - } - } else { - args->_itemsOutOfView++; } } } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 40c97b1877..fcafca3279 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -65,6 +65,9 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _gravity = DEFAULT_GRAVITY; _damping = DEFAULT_DAMPING; _lifetime = DEFAULT_LIFETIME; + _registrationPoint = DEFAULT_REGISTRATION_POINT; + _rotationalVelocity = DEFAULT_ROTATIONAL_VELOCITY; + _visible = DEFAULT_VISIBLE; } EntityItem::EntityItem(const EntityItemID& entityItemID) { @@ -456,6 +459,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); READ_ENTITY_PROPERTY_QUAT(PROP_ROTATIONAL_VELOCITY, _rotationalVelocity); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); +qDebug() << "EntityItem::readEntityDataFromBuffer() ... _visible=" << _visible; bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -617,25 +621,19 @@ EntityItemProperties EntityItem::getProperties() const { properties._type = getType(); - properties._position = getPosition() * (float) TREE_SCALE; - properties.setDimensions(getDimensions() * (float) TREE_SCALE); - properties._rotation = getRotation(); - - properties._mass = getMass(); - properties._velocity = getVelocity() * (float) TREE_SCALE; - properties._gravity = getGravity() * (float) TREE_SCALE; - properties._damping = getDamping(); - properties._lifetime = getLifetime(); - properties._script = getScript(); - - properties._positionChanged = false; - properties._rotationChanged = false; - properties._massChanged = false; - properties._velocityChanged = false; - properties._gravityChanged = false; - properties._dampingChanged = false; - properties._lifetimeChanged = false; - properties._scriptChanged = false; + COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPositionInMeters); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensionsInMeters); // NOTE: radius is obsolete + COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(mass, getMass); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getVelocityInMeters); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravityInMeters); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotationalVelocity, getRotationalVelocity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); properties._defaultSettings = false; @@ -666,6 +664,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotationalVelocity, setRotationalVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 8381c74772..5b285eb9da 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -121,12 +121,14 @@ public: // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } /// get position in domain scale units (0.0 - 1.0) + glm::vec3 getPositionInMeters() const { return _position * (float) TREE_SCALE; } /// get position in meters void setPosition(const glm::vec3& value) { _position = value; } /// set position in domain scale units (0.0 - 1.0) void setPositionInMeters(const glm::vec3& value) /// set position in meter units (0.0 - TREE_SCALE) { setPosition(glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f)); } static const glm::vec3 DEFAULT_DIMENSIONS; const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0) + glm::vec3 getDimensionsInMeters() const { return _dimensions * (float) TREE_SCALE; } /// get dimensions in meters float getDistanceToBottomOfEntity() const; /// get the distance from the position of the entity to its "bottom" in y axis float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension @@ -151,7 +153,8 @@ public: static const glm::vec3 DEFAULT_VELOCITY; static const glm::vec3 NO_VELOCITY; static const float EPSILON_VELOCITY_LENGTH; - const glm::vec3& getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second + const glm::vec3 getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second + glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second bool hasVelocity() const { return _velocity != NO_VELOCITY; } @@ -159,6 +162,7 @@ public: static const glm::vec3 REGULAR_GRAVITY; static const glm::vec3 NO_GRAVITY; const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared + glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared bool hasGravity() const { return _gravity != NO_GRAVITY; } @@ -206,6 +210,8 @@ public: static const bool DEFAULT_VISIBLE; bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; } + bool isVisible() const { return _visible; } + bool isInvisible() const { return !_visible; } protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 5c4e215e9a..1459ceab3c 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -90,65 +90,25 @@ void EntityItemProperties::debugDump() const { EntityPropertyFlags EntityItemProperties::getChangedProperties() const { EntityPropertyFlags changedProperties; - if (_dimensionsChanged) { - changedProperties += PROP_DIMENSIONS; - } - - if (_positionChanged) { - changedProperties += PROP_POSITION; - } - - if (_rotationChanged) { - changedProperties += PROP_ROTATION; - } - - if (_massChanged) { - changedProperties += PROP_MASS; - } - - if (_velocityChanged) { - changedProperties += PROP_VELOCITY; - } - - if (_gravityChanged) { - changedProperties += PROP_GRAVITY; - } - - if (_dampingChanged) { - changedProperties += PROP_DAMPING; - } - - if (_lifetimeChanged) { - changedProperties += PROP_LIFETIME; - } - - if (_scriptChanged) { - changedProperties += PROP_SCRIPT; - } - - if (_colorChanged) { - changedProperties += PROP_COLOR; - } - - if (_modelURLChanged) { - changedProperties += PROP_MODEL_URL; - } - - if (_animationURLChanged) { - changedProperties += PROP_ANIMATION_URL; - } - - if (_animationIsPlayingChanged) { - changedProperties += PROP_ANIMATION_PLAYING; - } - - if (_animationFrameIndexChanged) { - changedProperties += PROP_ANIMATION_FRAME_INDEX; - } - - if (_animationFPSChanged) { - changedProperties += PROP_ANIMATION_FPS; - } + + CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions); + CHECK_PROPERTY_CHANGE(PROP_POSITION, position); + CHECK_PROPERTY_CHANGE(PROP_ROTATION, rotation); + CHECK_PROPERTY_CHANGE(PROP_MASS, mass); + CHECK_PROPERTY_CHANGE(PROP_VELOCITY, velocity); + CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity); + CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping); + CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime); + CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); + CHECK_PROPERTY_CHANGE(PROP_COLOR, color); + CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); + CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL); + CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying); + CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex); + CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FPS, animationFPS); + CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); + CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); + CHECK_PROPERTY_CHANGE(PROP_ROTATIONAL_VELOCITY, rotationalVelocity); return changedProperties; } @@ -185,6 +145,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons properties.setProperty("ageAsText", formatSecondsElapsed(getAge())); // gettable, but not settable properties.setProperty("script", _script); + QScriptValue registrationPoint = vec3toScriptValue(engine, _registrationPoint); + properties.setProperty("registrationPoint", registrationPoint); + + QScriptValue rotationalVelocity = quatToScriptValue(engine, _rotationalVelocity); + properties.setProperty("rotationalVelocity", rotationalVelocity); + + properties.setProperty("visible", _visible); + QScriptValue color = xColorToScriptValue(engine, _color); properties.setProperty("color", color); properties.setProperty("modelURL", _modelURL); @@ -343,6 +311,52 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { } } + QScriptValue registrationPoint = object.property("registrationPoint"); + if (registrationPoint.isValid()) { + QScriptValue x = registrationPoint.property("x"); + QScriptValue y = registrationPoint.property("y"); + QScriptValue z = registrationPoint.property("z"); + if (x.isValid() && y.isValid() && z.isValid()) { + glm::vec3 newValue; + newValue.x = x.toVariant().toFloat(); + newValue.y = y.toVariant().toFloat(); + newValue.z = z.toVariant().toFloat(); + if (_defaultSettings || newValue != _registrationPoint) { + _registrationPoint = newValue; + _registrationPointChanged = true; + } + } + } + + QScriptValue rotationalVelocity = object.property("rotationalVelocity"); + if (rotationalVelocity.isValid()) { + QScriptValue x = rotationalVelocity.property("x"); + QScriptValue y = rotationalVelocity.property("y"); + QScriptValue z = rotationalVelocity.property("z"); + QScriptValue w = rotationalVelocity.property("w"); + if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { + glm::quat newRotation; + newRotation.x = x.toVariant().toFloat(); + newRotation.y = y.toVariant().toFloat(); + newRotation.z = z.toVariant().toFloat(); + newRotation.w = w.toVariant().toFloat(); + if (_defaultSettings || newRotation != _rotationalVelocity) { + _rotationalVelocity = newRotation; + _rotationalVelocityChanged = true; + } + } + } + + QScriptValue visible = object.property("visible"); + if (visible.isValid()) { + bool newValue; + newValue = visible.toVariant().toBool(); + if (_defaultSettings || newValue != _visible) { + _visible = newValue; + _visibleChanged = true; + } + } + QScriptValue color = object.property("color"); if (color.isValid()) { QScriptValue red = color.property("red"); @@ -548,7 +562,6 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem // These items would go here once supported.... // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, - // PROP_VISIBLE, APPEND_ENTITY_PROPERTY(PROP_POSITION, appendPosition, properties.getPosition()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, appendValue, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete @@ -565,6 +578,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, properties.getAnimationIsPlaying()); + APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, properties.getRegistrationPoint()); + APPEND_ENTITY_PROPERTY(PROP_ROTATIONAL_VELOCITY, appendValue, properties.getRotationalVelocity()); + APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -757,9 +773,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); - // TODO: add PROP_REGISTRATION_POINT, - // TODO: add PROP_ROTATIONAL_VELOCITY, - // TODO: add PROP_VISIBLE, + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); + READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(PROP_ROTATIONAL_VELOCITY, setRotationalVelocity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); return valid; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 3a5bfbe8f0..02c13d3228 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -215,6 +215,17 @@ public: const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; } void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; } + const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } + void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; _registrationPointChanged = true; } + + const glm::quat& getRotationalVelocity() const { return _rotationalVelocity; } + void setRotationalVelocity(const glm::quat& value) { _rotationalVelocity = value; _rotationalVelocityChanged = true; } + + bool getVisible() const { return _visible; } + void setVisible(bool value) { _visible = value; _visibleChanged = true; } + + + private: void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } @@ -389,5 +400,13 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP somethingChanged = true; \ } +#define COPY_ENTITY_PROPERTY_TO_PROPERTIES(M,G) \ + properties._##M = G(); \ + properties._##M##Changed = false; + +#define CHECK_PROPERTY_CHANGE(P,M) \ + if (_##M##Changed) { \ + changedProperties += P; \ + } #endif // hifi_EntityItemProperties_h From 7283e7818f8b9e9e3621d38d0d5f61cd0a85a921 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 09:19:24 -0700 Subject: [PATCH 11/38] moved macros to sep file --- libraries/entities/src/EntityItemProperties.h | 125 +--------------- .../entities/src/EntityItemPropertiesMacros.h | 137 ++++++++++++++++++ 2 files changed, 138 insertions(+), 124 deletions(-) create mode 100644 libraries/entities/src/EntityItemPropertiesMacros.h diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 02c13d3228..a4519a6f45 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -29,10 +29,9 @@ #include "EntityItemID.h" +#include "EntityItemPropertiesMacros.h" #include "EntityTypes.h" - - // PropertyFlags support enum EntityPropertyList { PROP_PAGED_PROPERTY, @@ -287,126 +286,4 @@ Q_DECLARE_METATYPE(EntityItemProperties); QScriptValue EntityItemPropertiesToScriptValue(QScriptEngine* engine, const EntityItemProperties& properties); void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemProperties& properties); -#define APPEND_ENTITY_PROPERTY(P,O,V) \ - if (requestedProperties.getHasProperty(P)) { \ - LevelDetails propertyLevel = packetData->startLevel(); \ - successPropertyFits = packetData->O(V); \ - if (successPropertyFits) { \ - propertyFlags |= P; \ - propertiesDidntFit -= P; \ - propertyCount++; \ - packetData->endLevel(propertyLevel); \ - } else { \ - packetData->discardLevel(propertyLevel); \ - appendState = OctreeElement::PARTIAL; \ - } \ - } else { \ - propertiesDidntFit -= P; \ - } - -#define READ_ENTITY_PROPERTY(P,T,M) \ - if (propertyFlags.getHasProperty(P)) { \ - T fromBuffer; \ - memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \ - dataAt += sizeof(fromBuffer); \ - bytesRead += sizeof(fromBuffer); \ - if (overwriteLocalData) { \ - M = fromBuffer; \ - } \ - } - -#define READ_ENTITY_PROPERTY_QUAT(P,M) \ - if (propertyFlags.getHasProperty(P)) { \ - glm::quat fromBuffer; \ - int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \ - dataAt += bytes; \ - bytesRead += bytes; \ - if (overwriteLocalData) { \ - M = fromBuffer; \ - } \ - } - -#define READ_ENTITY_PROPERTY_STRING(P,O) \ - if (propertyFlags.getHasProperty(P)) { \ - uint16_t length; \ - memcpy(&length, dataAt, sizeof(length)); \ - dataAt += sizeof(length); \ - bytesRead += sizeof(length); \ - QString value((const char*)dataAt); \ - dataAt += length; \ - bytesRead += length; \ - if (overwriteLocalData) { \ - O(value); \ - } \ - } - -#define READ_ENTITY_PROPERTY_COLOR(P,M) \ - if (propertyFlags.getHasProperty(P)) { \ - if (overwriteLocalData) { \ - memcpy(M, dataAt, sizeof(M)); \ - } \ - dataAt += sizeof(rgbColor); \ - bytesRead += sizeof(rgbColor); \ - } - -#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \ - if (propertyFlags.getHasProperty(P)) { \ - T fromBuffer; \ - memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \ - dataAt += sizeof(fromBuffer); \ - processedBytes += sizeof(fromBuffer); \ - properties.O(fromBuffer); \ - } - -#define READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(P,O) \ - if (propertyFlags.getHasProperty(P)) { \ - glm::quat fromBuffer; \ - int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \ - dataAt += bytes; \ - processedBytes += bytes; \ - properties.O(fromBuffer); \ - } - -#define READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(P,O) \ - if (propertyFlags.getHasProperty(P)) { \ - uint16_t length; \ - memcpy(&length, dataAt, sizeof(length)); \ - dataAt += sizeof(length); \ - processedBytes += sizeof(length); \ - QString value((const char*)dataAt); \ - dataAt += length; \ - processedBytes += length; \ - properties.O(value); \ - } - -#define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \ - if (propertyFlags.getHasProperty(P)) { \ - xColor color; \ - memcpy(&color, dataAt, sizeof(color)); \ - dataAt += sizeof(color); \ - processedBytes += sizeof(color); \ - properties.O(color); \ - } - -#define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \ - if (properties._##P##Changed || forceCopy) { \ - M(properties._##P); \ - somethingChanged = true; \ - } - -#define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \ - if (properties.C() || forceCopy) { \ - S(properties.G()); \ - somethingChanged = true; \ - } - -#define COPY_ENTITY_PROPERTY_TO_PROPERTIES(M,G) \ - properties._##M = G(); \ - properties._##M##Changed = false; - -#define CHECK_PROPERTY_CHANGE(P,M) \ - if (_##M##Changed) { \ - changedProperties += P; \ - } - #endif // hifi_EntityItemProperties_h diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h new file mode 100644 index 0000000000..f107e6c666 --- /dev/null +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -0,0 +1,137 @@ +// +// EntityItemPropertiesMacros.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 9/10/14. +// Copyright 2014 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_EntityItemPropertiesMacros_h +#define hifi_EntityItemPropertiesMacros_h + +#define APPEND_ENTITY_PROPERTY(P,O,V) \ + if (requestedProperties.getHasProperty(P)) { \ + LevelDetails propertyLevel = packetData->startLevel(); \ + successPropertyFits = packetData->O(V); \ + if (successPropertyFits) { \ + propertyFlags |= P; \ + propertiesDidntFit -= P; \ + propertyCount++; \ + packetData->endLevel(propertyLevel); \ + } else { \ + packetData->discardLevel(propertyLevel); \ + appendState = OctreeElement::PARTIAL; \ + } \ + } else { \ + propertiesDidntFit -= P; \ + } + +#define READ_ENTITY_PROPERTY(P,T,M) \ + if (propertyFlags.getHasProperty(P)) { \ + T fromBuffer; \ + memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \ + dataAt += sizeof(fromBuffer); \ + bytesRead += sizeof(fromBuffer); \ + if (overwriteLocalData) { \ + M = fromBuffer; \ + } \ + } + +#define READ_ENTITY_PROPERTY_QUAT(P,M) \ + if (propertyFlags.getHasProperty(P)) { \ + glm::quat fromBuffer; \ + int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \ + dataAt += bytes; \ + bytesRead += bytes; \ + if (overwriteLocalData) { \ + M = fromBuffer; \ + } \ + } + +#define READ_ENTITY_PROPERTY_STRING(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + uint16_t length; \ + memcpy(&length, dataAt, sizeof(length)); \ + dataAt += sizeof(length); \ + bytesRead += sizeof(length); \ + QString value((const char*)dataAt); \ + dataAt += length; \ + bytesRead += length; \ + if (overwriteLocalData) { \ + O(value); \ + } \ + } + +#define READ_ENTITY_PROPERTY_COLOR(P,M) \ + if (propertyFlags.getHasProperty(P)) { \ + if (overwriteLocalData) { \ + memcpy(M, dataAt, sizeof(M)); \ + } \ + dataAt += sizeof(rgbColor); \ + bytesRead += sizeof(rgbColor); \ + } + +#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \ + if (propertyFlags.getHasProperty(P)) { \ + T fromBuffer; \ + memcpy(&fromBuffer, dataAt, sizeof(fromBuffer)); \ + dataAt += sizeof(fromBuffer); \ + processedBytes += sizeof(fromBuffer); \ + properties.O(fromBuffer); \ + } + +#define READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + glm::quat fromBuffer; \ + int bytes = unpackOrientationQuatFromBytes(dataAt, fromBuffer); \ + dataAt += bytes; \ + processedBytes += bytes; \ + properties.O(fromBuffer); \ + } + +#define READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + uint16_t length; \ + memcpy(&length, dataAt, sizeof(length)); \ + dataAt += sizeof(length); \ + processedBytes += sizeof(length); \ + QString value((const char*)dataAt); \ + dataAt += length; \ + processedBytes += length; \ + properties.O(value); \ + } + +#define READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(P,O) \ + if (propertyFlags.getHasProperty(P)) { \ + xColor color; \ + memcpy(&color, dataAt, sizeof(color)); \ + dataAt += sizeof(color); \ + processedBytes += sizeof(color); \ + properties.O(color); \ + } + +#define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \ + if (properties._##P##Changed || forceCopy) { \ + M(properties._##P); \ + somethingChanged = true; \ + } + +#define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \ + if (properties.C() || forceCopy) { \ + S(properties.G()); \ + somethingChanged = true; \ + } + +#define COPY_ENTITY_PROPERTY_TO_PROPERTIES(M,G) \ + properties._##M = G(); \ + properties._##M##Changed = false; + +#define CHECK_PROPERTY_CHANGE(P,M) \ + if (_##M##Changed) { \ + changedProperties += P; \ + } + +#endif // hifi_EntityItemPropertiesMacros_h From bb52c4a1b37522a7bb427251f57e61a278a706e3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 11:28:45 -0700 Subject: [PATCH 12/38] store angular valocity as 3 vector --- examples/editModels.js | 17 +++++++++++--- libraries/entities/src/EntityItem.cpp | 23 +++++++++++++++---- libraries/entities/src/EntityItem.h | 10 ++++---- .../entities/src/EntityItemProperties.cpp | 10 ++++---- libraries/entities/src/EntityItemProperties.h | 6 ++--- 5 files changed, 45 insertions(+), 21 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 17300931aa..901c7d01f0 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2891,11 +2891,17 @@ function handeMenuEvent(menuItem) { array.push({ label: "Velocity:", type: "header" }); index++; - array.push({ label: "Velocity X:", value: properties.velocity.x.toFixed(decimals) }); + array.push({ label: "Linear X:", value: properties.velocity.x.toFixed(decimals) }); index++; - array.push({ label: "Velocity Y:", value: properties.velocity.y.toFixed(decimals) }); + array.push({ label: "Linear Y:", value: properties.velocity.y.toFixed(decimals) }); index++; - array.push({ label: "Velocity Z:", value: properties.velocity.z.toFixed(decimals) }); + array.push({ label: "Linear Z:", value: properties.velocity.z.toFixed(decimals) }); + index++; + array.push({ label: "Angular Pitch:", value: properties.rotationalVelocity.x.toFixed(decimals) }); + index++; + array.push({ label: "Angular Yaw:", value: properties.rotationalVelocity.y.toFixed(decimals) }); + index++; + array.push({ label: "Angular Roll:", value: properties.rotationalVelocity.z.toFixed(decimals) }); index++; array.push({ label: "Damping:", value: properties.damping.toFixed(decimals) }); index++; @@ -3037,6 +3043,11 @@ Window.nonBlockingFormClosed.connect(function() { properties.velocity.x = array[index++].value; properties.velocity.y = array[index++].value; properties.velocity.z = array[index++].value; + + properties.rotationalVelocity.x = array[index++].value; + properties.rotationalVelocity.y = array[index++].value; + properties.rotationalVelocity.z = array[index++].value; + properties.damping = array[index++].value; properties.gravity.x = array[index++].value; properties.gravity.y = array[index++].value; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fcafca3279..ac397444ed 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -38,7 +38,8 @@ const QString EntityItem::DEFAULT_SCRIPT = QString(""); const glm::quat EntityItem::DEFAULT_ROTATION; const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); const glm::vec3 EntityItem::DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center -const glm::quat EntityItem::DEFAULT_ROTATIONAL_VELOCITY; +const glm::vec3 EntityItem::NO_ROTATIONAL_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f); +const glm::vec3 EntityItem::DEFAULT_ROTATIONAL_VELOCITY = NO_ROTATIONAL_VELOCITY; const bool EntityItem::DEFAULT_VISIBLE = true; @@ -457,9 +458,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime); READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); - READ_ENTITY_PROPERTY_QUAT(PROP_ROTATIONAL_VELOCITY, _rotationalVelocity); + READ_ENTITY_PROPERTY(PROP_ROTATIONAL_VELOCITY, glm::vec3, _rotationalVelocity); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); -qDebug() << "EntityItem::readEntityDataFromBuffer() ... _visible=" << _visible; bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -508,7 +508,7 @@ bool EntityItem::isRestingOnSurface() const { } void EntityItem::update(const quint64& updateTime) { - bool wantDebug = false; + bool wantDebug = true; float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND); @@ -525,6 +525,15 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << "********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated; } + if (hasRotationalVelocity()) { + glm::quat rotation = getRotation(); + glm::vec3 rotationalVelocity = glm::radians(getRotationalVelocity()); + float angle = timeElapsed * glm::length(rotationalVelocity); + glm::quat dQ = glm::angleAxis(angle, glm::normalize(rotationalVelocity)); + rotation = dQ * rotation; + setRotation(rotation); + } + if (hasVelocity() || hasGravity()) { glm::vec3 position = getPosition(); glm::vec3 velocity = getVelocity(); @@ -535,6 +544,7 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << " old AACube:" << getAACube(); qDebug() << " old position:" << position; qDebug() << " old velocity:" << velocity; + qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity(); } position += velocity * timeElapsed; @@ -563,7 +573,7 @@ void EntityItem::update(const quint64& updateTime) { position.y = getDistanceToBottomOfEntity(); } - // handle damping + // handle damping for velocity glm::vec3 dampingResistance = velocity * getDamping(); if (wantDebug) { qDebug() << " getDamping():" << getDamping(); @@ -597,6 +607,9 @@ EntityItem::SimulationState EntityItem::getSimulationState() const { if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) { return EntityItem::Moving; } + if (hasRotationalVelocity()) { + return EntityItem::Changing; + } if (isMortal()) { return EntityItem::Mortal; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5b285eb9da..a9647045c8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -203,9 +203,11 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; } /// registration point as ratio of entity - static const glm::quat DEFAULT_ROTATIONAL_VELOCITY; - const glm::quat& getRotationalVelocity() const { return _rotationalVelocity; } - void setRotationalVelocity(const glm::quat& value) { _rotationalVelocity = value; } + static const glm::vec3 NO_ROTATIONAL_VELOCITY; + static const glm::vec3 DEFAULT_ROTATIONAL_VELOCITY; + const glm::vec3& getRotationalVelocity() const { return _rotationalVelocity; } + void setRotationalVelocity(const glm::vec3& value) { _rotationalVelocity = value; } + bool hasRotationalVelocity() const { return _rotationalVelocity != NO_ROTATIONAL_VELOCITY; } static const bool DEFAULT_VISIBLE; bool getVisible() const { return _visible; } @@ -237,7 +239,7 @@ protected: float _lifetime; QString _script; glm::vec3 _registrationPoint; - glm::quat _rotationalVelocity; + glm::vec3 _rotationalVelocity; bool _visible; // NOTE: Radius support is obsolete, but these private helper functions are available for this class to diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 1459ceab3c..908a200982 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -148,7 +148,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons QScriptValue registrationPoint = vec3toScriptValue(engine, _registrationPoint); properties.setProperty("registrationPoint", registrationPoint); - QScriptValue rotationalVelocity = quatToScriptValue(engine, _rotationalVelocity); + QScriptValue rotationalVelocity = vec3toScriptValue(engine, _rotationalVelocity); properties.setProperty("rotationalVelocity", rotationalVelocity); properties.setProperty("visible", _visible); @@ -333,13 +333,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { QScriptValue x = rotationalVelocity.property("x"); QScriptValue y = rotationalVelocity.property("y"); QScriptValue z = rotationalVelocity.property("z"); - QScriptValue w = rotationalVelocity.property("w"); - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { - glm::quat newRotation; + if (x.isValid() && y.isValid() && z.isValid()) { + glm::vec3 newRotation; newRotation.x = x.toVariant().toFloat(); newRotation.y = y.toVariant().toFloat(); newRotation.z = z.toVariant().toFloat(); - newRotation.w = w.toVariant().toFloat(); if (_defaultSettings || newRotation != _rotationalVelocity) { _rotationalVelocity = newRotation; _rotationalVelocityChanged = true; @@ -774,7 +772,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); - READ_ENTITY_PROPERTY_QUAT_TO_PROPERTIES(PROP_ROTATIONAL_VELOCITY, setRotationalVelocity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATIONAL_VELOCITY, glm::vec3, setRotationalVelocity); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); return valid; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index a4519a6f45..05154853d9 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -217,8 +217,8 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; _registrationPointChanged = true; } - const glm::quat& getRotationalVelocity() const { return _rotationalVelocity; } - void setRotationalVelocity(const glm::quat& value) { _rotationalVelocity = value; _rotationalVelocityChanged = true; } + const glm::vec3& getRotationalVelocity() const { return _rotationalVelocity; } + void setRotationalVelocity(const glm::vec3& value) { _rotationalVelocity = value; _rotationalVelocityChanged = true; } bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; _visibleChanged = true; } @@ -244,7 +244,7 @@ private: float _lifetime; QString _script; glm::vec3 _registrationPoint; - glm::quat _rotationalVelocity; + glm::vec3 _rotationalVelocity; bool _visible; bool _positionChanged; From f33690cc385cc2b7e62959b90a889fb370a595b1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 11:55:23 -0700 Subject: [PATCH 13/38] fix velocity and gravity to be in meters --- libraries/entities/src/EntityItem.cpp | 11 +++++++---- libraries/entities/src/EntityItem.h | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ac397444ed..7b73a2f450 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -508,7 +508,7 @@ bool EntityItem::isRestingOnSurface() const { } void EntityItem::update(const quint64& updateTime) { - bool wantDebug = true; + bool wantDebug = false; float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND); @@ -537,6 +537,7 @@ void EntityItem::update(const quint64& updateTime) { if (hasVelocity() || hasGravity()) { glm::vec3 position = getPosition(); glm::vec3 velocity = getVelocity(); + glm::vec3 newPosition = position + (velocity * timeElapsed); if (wantDebug) { qDebug() << "EntityItem::update()...."; @@ -545,9 +546,11 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << " old position:" << position; qDebug() << " old velocity:" << velocity; qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity(); + qDebug() << " newPosition:" << newPosition; + qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); } - position += velocity * timeElapsed; + position = newPosition; // handle bounces off the ground... We bounce at the distance to the bottom of our entity if (position.y <= getDistanceToBottomOfEntity()) { @@ -669,8 +672,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensionsInMeters); // NOTE: radius is obsolete SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(mass, setMass); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocityInMeters); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravityInMeters); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a9647045c8..5ade0fe527 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -156,6 +156,7 @@ public: const glm::vec3 getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second + void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters bool hasVelocity() const { return _velocity != NO_VELOCITY; } static const glm::vec3 DEFAULT_GRAVITY; @@ -164,6 +165,7 @@ public: const glm::vec3& getGravity() const { return _gravity; } /// gravity in domain scale units (0.0-1.0) per second squared glm::vec3 getGravityInMeters() const { return _gravity * (float) TREE_SCALE; } /// get gravity in meters void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in domain scale units (0.0-1.0) per second squared + void setGravityInMeters(const glm::vec3& value) { _gravity = value / (float) TREE_SCALE; } /// gravity in meters bool hasGravity() const { return _gravity != NO_GRAVITY; } // TODO: this should eventually be updated to support resting on collisions with other surfaces From 8023735eb30daac84b83a4e163117021a48aa9c6 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 14:46:27 -0700 Subject: [PATCH 14/38] changed rotational to angular and added angular damping --- examples/editModels.js | 21 ++-- libraries/entities/src/EntityItem.cpp | 51 +++++--- libraries/entities/src/EntityItem.h | 17 ++- .../entities/src/EntityItemProperties.cpp | 114 +++++++++--------- libraries/entities/src/EntityItemProperties.h | 20 +-- .../entities/src/EntityItemPropertiesMacros.h | 21 ++++ 6 files changed, 149 insertions(+), 95 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 901c7d01f0..ee37dff277 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2897,13 +2897,15 @@ function handeMenuEvent(menuItem) { index++; array.push({ label: "Linear Z:", value: properties.velocity.z.toFixed(decimals) }); index++; - array.push({ label: "Angular Pitch:", value: properties.rotationalVelocity.x.toFixed(decimals) }); + array.push({ label: "Linear Damping:", value: properties.damping.toFixed(decimals) }); index++; - array.push({ label: "Angular Yaw:", value: properties.rotationalVelocity.y.toFixed(decimals) }); + array.push({ label: "Angular Pitch:", value: properties.angularVelocity.x.toFixed(decimals) }); index++; - array.push({ label: "Angular Roll:", value: properties.rotationalVelocity.z.toFixed(decimals) }); + array.push({ label: "Angular Yaw:", value: properties.angularVelocity.y.toFixed(decimals) }); index++; - array.push({ label: "Damping:", value: properties.damping.toFixed(decimals) }); + array.push({ label: "Angular Roll:", value: properties.angularVelocity.z.toFixed(decimals) }); + index++; + array.push({ label: "Angular Damping:", value: properties.angularDamping.toFixed(decimals) }); index++; array.push({ label: "Gravity X:", value: properties.gravity.x.toFixed(decimals) }); @@ -3043,12 +3045,13 @@ Window.nonBlockingFormClosed.connect(function() { properties.velocity.x = array[index++].value; properties.velocity.y = array[index++].value; properties.velocity.z = array[index++].value; - - properties.rotationalVelocity.x = array[index++].value; - properties.rotationalVelocity.y = array[index++].value; - properties.rotationalVelocity.z = array[index++].value; - properties.damping = array[index++].value; + + properties.angularVelocity.x = array[index++].value; + properties.angularVelocity.y = array[index++].value; + properties.angularVelocity.z = array[index++].value; + properties.angularDamping = array[index++].value; + properties.gravity.x = array[index++].value; properties.gravity.y = array[index++].value; properties.gravity.z = array[index++].value; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7b73a2f450..693f8bd177 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -27,7 +27,7 @@ const float EntityItem::IMMORTAL = -1.0f; /// special lifetime which means the e const float EntityItem::DEFAULT_GLOW_LEVEL = 0.0f; const float EntityItem::DEFAULT_MASS = 1.0f; const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL; -const float EntityItem::DEFAULT_DAMPING = 0.99f; +const float EntityItem::DEFAULT_DAMPING = 0.5f; const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0); const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 10000.0f) / (float)TREE_SCALE; // really small const glm::vec3 EntityItem::DEFAULT_VELOCITY = EntityItem::NO_VELOCITY; @@ -38,11 +38,11 @@ const QString EntityItem::DEFAULT_SCRIPT = QString(""); const glm::quat EntityItem::DEFAULT_ROTATION; const glm::vec3 EntityItem::DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f); const glm::vec3 EntityItem::DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center -const glm::vec3 EntityItem::NO_ROTATIONAL_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f); -const glm::vec3 EntityItem::DEFAULT_ROTATIONAL_VELOCITY = NO_ROTATIONAL_VELOCITY; +const glm::vec3 EntityItem::NO_ANGULAR_VELOCITY = glm::vec3(0.0f, 0.0f, 0.0f); +const glm::vec3 EntityItem::DEFAULT_ANGULAR_VELOCITY = NO_ANGULAR_VELOCITY; +const float EntityItem::DEFAULT_ANGULAR_DAMPING = 0.5f; const bool EntityItem::DEFAULT_VISIBLE = true; - void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _id = entityItemID.id; _creatorTokenID = entityItemID.creatorTokenID; @@ -67,7 +67,8 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _damping = DEFAULT_DAMPING; _lifetime = DEFAULT_LIFETIME; _registrationPoint = DEFAULT_REGISTRATION_POINT; - _rotationalVelocity = DEFAULT_ROTATIONAL_VELOCITY; + _angularVelocity = DEFAULT_ANGULAR_VELOCITY; + _angularDamping = DEFAULT_ANGULAR_DAMPING; _visible = DEFAULT_VISIBLE; } @@ -105,7 +106,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_LIFETIME; requestedProperties += PROP_SCRIPT; requestedProperties += PROP_REGISTRATION_POINT; - requestedProperties += PROP_ROTATIONAL_VELOCITY; + requestedProperties += PROP_ANGULAR_VELOCITY; + requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; return requestedProperties; @@ -212,7 +214,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_LIFETIME, appendValue, getLifetime()); APPEND_ENTITY_PROPERTY(PROP_SCRIPT, appendValue, getScript()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, getRegistrationPoint()); - APPEND_ENTITY_PROPERTY(PROP_ROTATIONAL_VELOCITY, appendValue, getRotationalVelocity()); + APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, getAngularVelocity()); + APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, getVisible()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, @@ -458,7 +461,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LIFETIME, float, _lifetime); READ_ENTITY_PROPERTY_STRING(PROP_SCRIPT,setScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, _registrationPoint); - READ_ENTITY_PROPERTY(PROP_ROTATIONAL_VELOCITY, glm::vec3, _rotationalVelocity); + READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, _angularVelocity); + READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -497,6 +501,9 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s float EntityItem::getDistanceToBottomOfEntity() const { // TODO: change this to support registration point + // TODO: fix this to correctly handle rotation... since _dimensions is in entity space, + // if the entity has been rotated, then the distance to world.y=0 is not the same + // as the dimensions.y return _dimensions.y / 2.0f; } @@ -525,13 +532,25 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << "********** EntityItem::update() .... SETTING _lastUpdated=" << _lastUpdated; } - if (hasRotationalVelocity()) { + if (hasAngularVelocity()) { glm::quat rotation = getRotation(); - glm::vec3 rotationalVelocity = glm::radians(getRotationalVelocity()); - float angle = timeElapsed * glm::length(rotationalVelocity); - glm::quat dQ = glm::angleAxis(angle, glm::normalize(rotationalVelocity)); + glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); + float angle = timeElapsed * glm::length(angularVelocity); + glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); rotation = dQ * rotation; setRotation(rotation); + + // handle damping for angular velocity + if (getAngularDamping() > 0.0f) { + glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); + if (wantDebug) { + qDebug() << " getDamping():" << getDamping(); + qDebug() << " dampingResistance:" << dampingResistance; + qDebug() << " dampingResistance * timeElapsed:" << dampingResistance * timeElapsed; + } + glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); + setAngularVelocity(newAngularVelocity); + } } if (hasVelocity() || hasGravity()) { @@ -610,7 +629,7 @@ EntityItem::SimulationState EntityItem::getSimulationState() const { if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) { return EntityItem::Moving; } - if (hasRotationalVelocity()) { + if (hasAngularVelocity()) { return EntityItem::Changing; } if (isMortal()) { @@ -647,7 +666,8 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime); COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript); COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotationalVelocity, getRotationalVelocity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getAngularVelocity); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping); COPY_ENTITY_PROPERTY_TO_PROPERTIES(glowLevel, getGlowLevel); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); @@ -678,7 +698,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotationalVelocity, setRotationalVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5ade0fe527..a95bb3f462 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -205,11 +205,15 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; } /// registration point as ratio of entity - static const glm::vec3 NO_ROTATIONAL_VELOCITY; - static const glm::vec3 DEFAULT_ROTATIONAL_VELOCITY; - const glm::vec3& getRotationalVelocity() const { return _rotationalVelocity; } - void setRotationalVelocity(const glm::vec3& value) { _rotationalVelocity = value; } - bool hasRotationalVelocity() const { return _rotationalVelocity != NO_ROTATIONAL_VELOCITY; } + static const glm::vec3 NO_ANGULAR_VELOCITY; + static const glm::vec3 DEFAULT_ANGULAR_VELOCITY; + const glm::vec3& getAngularVelocity() const { return _angularVelocity; } + void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; } + bool hasAngularVelocity() const { return _angularVelocity != NO_ANGULAR_VELOCITY; } + + static const float DEFAULT_ANGULAR_DAMPING; + float getAngularDamping() const { return _angularDamping; } + void setAngularDamping(float value) { _angularDamping = value; } static const bool DEFAULT_VISIBLE; bool getVisible() const { return _visible; } @@ -241,7 +245,8 @@ protected: float _lifetime; QString _script; glm::vec3 _registrationPoint; - glm::vec3 _rotationalVelocity; + glm::vec3 _angularVelocity; + float _angularDamping; bool _visible; // NOTE: Radius support is obsolete, but these private helper functions are available for this class to diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 908a200982..71e6a0b71a 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -38,7 +38,8 @@ EntityItemProperties::EntityItemProperties() : _lifetime(EntityItem::DEFAULT_LIFETIME), _script(EntityItem::DEFAULT_SCRIPT), _registrationPoint(EntityItem::DEFAULT_REGISTRATION_POINT), - _rotationalVelocity(EntityItem::DEFAULT_ROTATIONAL_VELOCITY), + _angularVelocity(EntityItem::DEFAULT_ANGULAR_VELOCITY), + _angularDamping(EntityItem::DEFAULT_ANGULAR_DAMPING), _visible(EntityItem::DEFAULT_VISIBLE), _positionChanged(false), @@ -51,7 +52,8 @@ EntityItemProperties::EntityItemProperties() : _lifetimeChanged(false), _scriptChanged(false), _registrationPointChanged(false), - _rotationalVelocityChanged(false), + _angularVelocityChanged(false), + _angularDampingChanged(false), _visibleChanged(false), _color(), @@ -108,7 +110,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FPS, animationFPS); CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); - CHECK_PROPERTY_CHANGE(PROP_ROTATIONAL_VELOCITY, rotationalVelocity); + CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); + CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); return changedProperties; } @@ -117,51 +120,36 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons QScriptValue properties = engine->newObject(); if (_idSet) { - properties.setProperty("id", _id.toString()); - bool isKnownID = (_id != UNKNOWN_ENTITY_ID); - properties.setProperty("isKnownID", isKnownID); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString()); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(isKnownID, (_id != UNKNOWN_ENTITY_ID)); + } else { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(isKnownID, false); } - properties.setProperty("type", EntityTypes::getEntityTypeName(_type)); - - QScriptValue position = vec3toScriptValue(engine, _position); - properties.setProperty("position", position); - QScriptValue dimensions = vec3toScriptValue(engine, _dimensions); - properties.setProperty("dimensions", dimensions); - - QScriptValue naturalDimensions = vec3toScriptValue(engine, _naturalDimensions); - properties.setProperty("naturalDimensions", naturalDimensions); - - QScriptValue rotation = quatToScriptValue(engine, _rotation); - properties.setProperty("rotation", rotation); - properties.setProperty("mass", _mass); - QScriptValue velocity = vec3toScriptValue(engine, _velocity); - properties.setProperty("velocity", velocity); - QScriptValue gravity = vec3toScriptValue(engine, _gravity); - properties.setProperty("gravity", gravity); - properties.setProperty("damping", _damping); - properties.setProperty("lifetime", _lifetime); - properties.setProperty("age", getAge()); // gettable, but not settable - properties.setProperty("ageAsText", formatSecondsElapsed(getAge())); // gettable, but not settable - properties.setProperty("script", _script); - - QScriptValue registrationPoint = vec3toScriptValue(engine, _registrationPoint); - properties.setProperty("registrationPoint", registrationPoint); - - QScriptValue rotationalVelocity = vec3toScriptValue(engine, _rotationalVelocity); - properties.setProperty("rotationalVelocity", rotationalVelocity); - - properties.setProperty("visible", _visible); - - QScriptValue color = xColorToScriptValue(engine, _color); - properties.setProperty("color", color); - properties.setProperty("modelURL", _modelURL); - - properties.setProperty("animationURL", _animationURL); - properties.setProperty("animationIsPlaying", _animationIsPlaying); - properties.setProperty("animationFrameIndex", _animationFrameIndex); - properties.setProperty("animationFPS", _animationFPS); - properties.setProperty("glowLevel", _glowLevel); + //properties.setProperty("type", EntityTypes::getEntityTypeName(_type)); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type)); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(position); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(dimensions); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(naturalDimensions); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE_QUAT(rotation); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(velocity); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(gravity); + COPY_PROPERTY_TO_QSCRIPTVALUE(damping); + COPY_PROPERTY_TO_QSCRIPTVALUE(lifetime); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(age, getAge()); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE(script); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(registrationPoint); + COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(angularVelocity); + COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping); + COPY_PROPERTY_TO_QSCRIPTVALUE(visible); + COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color); + COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL); + COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying); + COPY_PROPERTY_TO_QSCRIPTVALUE(animationFrameIndex); + COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS); + COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); // Sitting properties support QScriptValue sittingPoints = engine->newObject(); @@ -173,7 +161,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons sittingPoints.setProperty(i, sittingPoint); } sittingPoints.setProperty("length", _sittingPoints.size()); - properties.setProperty("sittingPoints", sittingPoints); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable return properties; } @@ -328,23 +316,33 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { } } - QScriptValue rotationalVelocity = object.property("rotationalVelocity"); - if (rotationalVelocity.isValid()) { - QScriptValue x = rotationalVelocity.property("x"); - QScriptValue y = rotationalVelocity.property("y"); - QScriptValue z = rotationalVelocity.property("z"); + QScriptValue angularVelocity = object.property("angularVelocity"); + if (angularVelocity.isValid()) { + QScriptValue x = angularVelocity.property("x"); + QScriptValue y = angularVelocity.property("y"); + QScriptValue z = angularVelocity.property("z"); if (x.isValid() && y.isValid() && z.isValid()) { glm::vec3 newRotation; newRotation.x = x.toVariant().toFloat(); newRotation.y = y.toVariant().toFloat(); newRotation.z = z.toVariant().toFloat(); - if (_defaultSettings || newRotation != _rotationalVelocity) { - _rotationalVelocity = newRotation; - _rotationalVelocityChanged = true; + if (_defaultSettings || newRotation != _angularVelocity) { + _angularVelocity = newRotation; + _angularVelocityChanged = true; } } } + QScriptValue angularDamping = object.property("angularDamping"); + if (angularDamping.isValid()) { + float newValue; + newValue = angularDamping.toVariant().toFloat(); + if (_defaultSettings || newValue != _angularDamping) { + _angularDamping = newValue; + _angularDampingChanged = true; + } + } + QScriptValue visible = object.property("visible"); if (visible.isValid()) { bool newValue; @@ -577,7 +575,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, appendValue, properties.getAnimationIsPlaying()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, appendValue, properties.getRegistrationPoint()); - APPEND_ENTITY_PROPERTY(PROP_ROTATIONAL_VELOCITY, appendValue, properties.getRotationalVelocity()); + APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, appendValue, properties.getAngularVelocity()); + APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, appendValue, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, appendValue, properties.getVisible()); } if (propertyCount > 0) { @@ -772,7 +771,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATIONAL_VELOCITY, glm::vec3, setRotationalVelocity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, glm::vec3, setAngularVelocity); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); return valid; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 05154853d9..8b76c7542c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -60,9 +60,10 @@ enum EntityPropertyList { // these properties are supported by the EntityItem base class PROP_REGISTRATION_POINT, - PROP_ROTATIONAL_VELOCITY, + PROP_ANGULAR_VELOCITY, + PROP_ANGULAR_DAMPING, - PROP_LAST_ITEM = PROP_ROTATIONAL_VELOCITY + PROP_LAST_ITEM = PROP_ANGULAR_DAMPING }; typedef PropertyFlags EntityPropertyFlags; @@ -217,14 +218,15 @@ public: const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; _registrationPointChanged = true; } - const glm::vec3& getRotationalVelocity() const { return _rotationalVelocity; } - void setRotationalVelocity(const glm::vec3& value) { _rotationalVelocity = value; _rotationalVelocityChanged = true; } + const glm::vec3& getAngularVelocity() const { return _angularVelocity; } + void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; _angularVelocityChanged = true; } + + float getAngularDamping() const { return _angularDamping; } + void setAngularDamping(float value) { _angularDamping = value; _angularDampingChanged = true; } bool getVisible() const { return _visible; } void setVisible(bool value) { _visible = value; _visibleChanged = true; } - - private: void setLastEdited(quint64 usecTime) { _lastEdited = usecTime; } @@ -244,7 +246,8 @@ private: float _lifetime; QString _script; glm::vec3 _registrationPoint; - glm::vec3 _rotationalVelocity; + glm::vec3 _angularVelocity; + float _angularDamping; bool _visible; bool _positionChanged; @@ -257,7 +260,8 @@ private: bool _lifetimeChanged; bool _scriptChanged; bool _registrationPointChanged; - bool _rotationalVelocityChanged; + bool _angularVelocityChanged; + bool _angularDampingChanged; bool _visibleChanged; // TODO: this need to be more generic. for now, we're going to have the properties class support these as diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index f107e6c666..11c7c18842 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -134,4 +134,25 @@ changedProperties += P; \ } + +#define COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(P) \ + QScriptValue P = vec3toScriptValue(engine, _##P); \ + properties.setProperty(#P, P); + +#define COPY_PROPERTY_TO_QSCRIPTVALUE_QUAT(P) \ + QScriptValue P = quatToScriptValue(engine, _##P); \ + properties.setProperty(#P, P); + +#define COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(P) \ + QScriptValue P = xColorToScriptValue(engine, _##P); \ + properties.setProperty(#P, P); + +#define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \ + properties.setProperty(#P, G); + + +#define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \ + properties.setProperty(#P, _##P); + + #endif // hifi_EntityItemPropertiesMacros_h From 0d80c32306f0ebde96e1c46561dcb84efaf233c2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 14:51:58 -0700 Subject: [PATCH 15/38] editModels debug cleanup --- examples/editModels.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index ee37dff277..ca45c94995 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -3000,7 +3000,6 @@ Controller.keyReleaseEvent.connect(function (event) { Window.inlineButtonClicked.connect(function (name) { if (name == "resetDimensions") { var decimals = 3; - Window.reloadNonBlockingForm([ { value: propertiesForEditedEntity.naturalDimensions.x.toFixed(decimals), oldIndex: dimensionX }, { value: propertiesForEditedEntity.naturalDimensions.y.toFixed(decimals), oldIndex: dimensionY }, @@ -3009,11 +3008,8 @@ Window.inlineButtonClicked.connect(function (name) { } }); Window.nonBlockingFormClosed.connect(function() { - print("JAVASCRIPT.... nonBlockingFormClosed...."); array = editEntityFormArray; if (Window.getNonBlockingFormResult(array)) { - print("getNonBlockingFormResult()...."); - var properties = propertiesForEditedEntity; var index = 0; if (properties.type == "Model") { From 8339dfaeb318f5649d93246cb6b1349ac6a37a86 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 15:05:27 -0700 Subject: [PATCH 16/38] fix EntityItemProperties::markAllChanged() --- libraries/entities/src/EntityItemProperties.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 71e6a0b71a..b22d4fb926 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -807,7 +807,6 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt return true; } - void EntityItemProperties::markAllChanged() { _positionChanged = true; _rotationChanged = true; @@ -817,7 +816,10 @@ void EntityItemProperties::markAllChanged() { _dampingChanged = true; _lifetimeChanged = true; _scriptChanged = true; - + _registrationPointChanged = true; + _angularVelocityChanged = true; + _angularDampingChanged = true; + _visibleChanged = true; _colorChanged = true; _modelURLChanged = true; _animationURLChanged = true; @@ -825,7 +827,6 @@ void EntityItemProperties::markAllChanged() { _animationFrameIndexChanged = true; _animationFPSChanged = true; _glowLevelChanged = true; - } From cbdaf76b881c4e2825d54ec58b92bf67524aff2a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 15:39:00 -0700 Subject: [PATCH 17/38] dry up the EntityItemProperties::copyFromScriptValue() with macros for repeated blocks --- .../entities/src/EntityItemProperties.cpp | 282 ++---------------- libraries/entities/src/EntityItemProperties.h | 3 + .../entities/src/EntityItemPropertiesMacros.h | 85 +++++- 3 files changed, 110 insertions(+), 260 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index b22d4fb926..c2eebe82a9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -167,270 +167,34 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons } void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { + + QScriptValue typeScriptValue = object.property("type"); if (typeScriptValue.isValid()) { - QString typeName; - typeName = typeScriptValue.toVariant().toString(); - _type = EntityTypes::getEntityTypeFromName(typeName); + setType(typeScriptValue.toVariant().toString()); } - QScriptValue position = object.property("position"); - if (position.isValid()) { - QScriptValue x = position.property("x"); - QScriptValue y = position.property("y"); - QScriptValue z = position.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newPosition; - newPosition.x = x.toVariant().toFloat(); - newPosition.y = y.toVariant().toFloat(); - newPosition.z = z.toVariant().toFloat(); - if (_defaultSettings || newPosition != _position) { - setPosition(newPosition); // gives us automatic clamping - } - } - } + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(position, setPosition); + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(dimensions, setDimensions); + COPY_PROPERTY_FROM_QSCRIPTVALUE_QUAT(rotation, setRotation); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(mass, setMass); + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(velocity, setVelocity); + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(gravity, setGravity); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(damping, setDamping); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(lifetime, setLifetime); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(script, setScript); + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(registrationPoint, setRegistrationPoint); + COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(angularVelocity, setAngularVelocity); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(angularDamping, setAngularDamping); + COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible); + COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL); + COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFrameIndex, setAnimationFrameIndex); + COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(glowLevel, setGlowLevel); - QScriptValue dimensions = object.property("dimensions"); - if (dimensions.isValid()) { - QScriptValue x = dimensions.property("x"); - QScriptValue y = dimensions.property("y"); - QScriptValue z = dimensions.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newDimensions; - newDimensions.x = x.toVariant().toFloat(); - newDimensions.y = y.toVariant().toFloat(); - newDimensions.z = z.toVariant().toFloat(); - if (_defaultSettings || newDimensions != getDimensions()) { - setDimensions(newDimensions); - } - } - } - - QScriptValue rotation = object.property("rotation"); - if (rotation.isValid()) { - QScriptValue x = rotation.property("x"); - QScriptValue y = rotation.property("y"); - QScriptValue z = rotation.property("z"); - QScriptValue w = rotation.property("w"); - if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { - glm::quat newRotation; - newRotation.x = x.toVariant().toFloat(); - newRotation.y = y.toVariant().toFloat(); - newRotation.z = z.toVariant().toFloat(); - newRotation.w = w.toVariant().toFloat(); - if (_defaultSettings || newRotation != _rotation) { - _rotation = newRotation; - _rotationChanged = true; - } - } - } - - QScriptValue mass = object.property("mass"); - if (mass.isValid()) { - float newValue; - newValue = mass.toVariant().toFloat(); - if (_defaultSettings || newValue != _mass) { - _mass = newValue; - _massChanged = true; - } - } - - QScriptValue velocity = object.property("velocity"); - if (velocity.isValid()) { - QScriptValue x = velocity.property("x"); - QScriptValue y = velocity.property("y"); - QScriptValue z = velocity.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newValue; - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - if (_defaultSettings || newValue != _velocity) { - _velocity = newValue; - _velocityChanged = true; - } - } - } - - QScriptValue gravity = object.property("gravity"); - if (gravity.isValid()) { - QScriptValue x = gravity.property("x"); - QScriptValue y = gravity.property("y"); - QScriptValue z = gravity.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newValue; - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - if (_defaultSettings || newValue != _gravity) { - _gravity = newValue; - _gravityChanged = true; - } - } - } - - QScriptValue damping = object.property("damping"); - if (damping.isValid()) { - float newValue; - newValue = damping.toVariant().toFloat(); - if (_defaultSettings || newValue != _damping) { - _damping = newValue; - _dampingChanged = true; - } - } - - QScriptValue lifetime = object.property("lifetime"); - if (lifetime.isValid()) { - float newValue; - newValue = lifetime.toVariant().toFloat(); - if (_defaultSettings || newValue != _lifetime) { - _lifetime = newValue; - _lifetimeChanged = true; - } - } - - QScriptValue script = object.property("script"); - if (script.isValid()) { - QString newValue; - newValue = script.toVariant().toString(); - if (_defaultSettings || newValue != _script) { - _script = newValue; - _scriptChanged = true; - } - } - - QScriptValue registrationPoint = object.property("registrationPoint"); - if (registrationPoint.isValid()) { - QScriptValue x = registrationPoint.property("x"); - QScriptValue y = registrationPoint.property("y"); - QScriptValue z = registrationPoint.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newValue; - newValue.x = x.toVariant().toFloat(); - newValue.y = y.toVariant().toFloat(); - newValue.z = z.toVariant().toFloat(); - if (_defaultSettings || newValue != _registrationPoint) { - _registrationPoint = newValue; - _registrationPointChanged = true; - } - } - } - - QScriptValue angularVelocity = object.property("angularVelocity"); - if (angularVelocity.isValid()) { - QScriptValue x = angularVelocity.property("x"); - QScriptValue y = angularVelocity.property("y"); - QScriptValue z = angularVelocity.property("z"); - if (x.isValid() && y.isValid() && z.isValid()) { - glm::vec3 newRotation; - newRotation.x = x.toVariant().toFloat(); - newRotation.y = y.toVariant().toFloat(); - newRotation.z = z.toVariant().toFloat(); - if (_defaultSettings || newRotation != _angularVelocity) { - _angularVelocity = newRotation; - _angularVelocityChanged = true; - } - } - } - - QScriptValue angularDamping = object.property("angularDamping"); - if (angularDamping.isValid()) { - float newValue; - newValue = angularDamping.toVariant().toFloat(); - if (_defaultSettings || newValue != _angularDamping) { - _angularDamping = newValue; - _angularDampingChanged = true; - } - } - - QScriptValue visible = object.property("visible"); - if (visible.isValid()) { - bool newValue; - newValue = visible.toVariant().toBool(); - if (_defaultSettings || newValue != _visible) { - _visible = newValue; - _visibleChanged = true; - } - } - - QScriptValue color = object.property("color"); - if (color.isValid()) { - QScriptValue red = color.property("red"); - QScriptValue green = color.property("green"); - QScriptValue blue = color.property("blue"); - if (red.isValid() && green.isValid() && blue.isValid()) { - xColor newColor; - newColor.red = red.toVariant().toInt(); - newColor.green = green.toVariant().toInt(); - newColor.blue = blue.toVariant().toInt(); - if (_defaultSettings || (newColor.red != _color.red || - newColor.green != _color.green || - newColor.blue != _color.blue)) { - _color = newColor; - _colorChanged = true; - } - } - } - - QScriptValue modelURL = object.property("modelURL"); - if (modelURL.isValid()) { - QString newModelURL; - newModelURL = modelURL.toVariant().toString(); - if (_defaultSettings || newModelURL != _modelURL) { - _modelURL = newModelURL; - _modelURLChanged = true; - } - } - - QScriptValue animationURL = object.property("animationURL"); - if (animationURL.isValid()) { - QString newAnimationURL; - newAnimationURL = animationURL.toVariant().toString(); - if (_defaultSettings || newAnimationURL != _animationURL) { - _animationURL = newAnimationURL; - _animationURLChanged = true; - } - } - - QScriptValue animationIsPlaying = object.property("animationIsPlaying"); - if (animationIsPlaying.isValid()) { - bool newIsAnimationPlaying; - newIsAnimationPlaying = animationIsPlaying.toVariant().toBool(); - if (_defaultSettings || newIsAnimationPlaying != _animationIsPlaying) { - _animationIsPlaying = newIsAnimationPlaying; - _animationIsPlayingChanged = true; - } - } - - QScriptValue animationFrameIndex = object.property("animationFrameIndex"); - if (animationFrameIndex.isValid()) { - float newFrameIndex; - newFrameIndex = animationFrameIndex.toVariant().toFloat(); - if (_defaultSettings || newFrameIndex != _animationFrameIndex) { - _animationFrameIndex = newFrameIndex; - _animationFrameIndexChanged = true; - } - } - - QScriptValue animationFPS = object.property("animationFPS"); - if (animationFPS.isValid()) { - float newFPS; - newFPS = animationFPS.toVariant().toFloat(); - if (_defaultSettings || newFPS != _animationFPS) { - _animationFPS = newFPS; - _animationFPSChanged = true; - } - } - - QScriptValue glowLevel = object.property("glowLevel"); - if (glowLevel.isValid()) { - float newGlowLevel; - newGlowLevel = glowLevel.toVariant().toFloat(); - if (_defaultSettings || newGlowLevel != _glowLevel) { - _glowLevel = newGlowLevel; - _glowLevelChanged = true; - } - } _lastEdited = usecTimestampNow(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8b76c7542c..c8ad2fe471 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -236,6 +236,9 @@ private: quint64 _created; EntityTypes::EntityType _type; + + void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); } + glm::vec3 _position; glm::vec3 _dimensions; glm::quat _rotation; diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 11c7c18842..46c78c09ea 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -150,9 +150,92 @@ #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(P, G) \ properties.setProperty(#P, G); - #define COPY_PROPERTY_TO_QSCRIPTVALUE(P) \ properties.setProperty(#P, _##P); +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + float newValue = P.toVariant().toFloat(); \ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } + +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + bool newValue = P.toVariant().toBool(); \ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } + +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(P, S)\ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + QString newValue = P.toVariant().toString();\ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } + +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + QScriptValue x = P.property("x"); \ + QScriptValue y = P.property("y"); \ + QScriptValue z = P.property("z"); \ + if (x.isValid() && y.isValid() && z.isValid()) {\ + glm::vec3 newValue; \ + newValue.x = x.toVariant().toFloat(); \ + newValue.y = y.toVariant().toFloat(); \ + newValue.z = z.toVariant().toFloat(); \ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } \ + } + +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_QUAT(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + QScriptValue x = P.property("x"); \ + QScriptValue y = P.property("y"); \ + QScriptValue z = P.property("z"); \ + QScriptValue w = P.property("w"); \ + if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) { \ + glm::quat newValue; \ + newValue.x = x.toVariant().toFloat(); \ + newValue.y = y.toVariant().toFloat(); \ + newValue.z = z.toVariant().toFloat(); \ + newValue.w = w.toVariant().toFloat(); \ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } \ + } + +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(P, S) \ + QScriptValue P = object.property(#P); \ + if (P.isValid()) { \ + QScriptValue r = P.property("red"); \ + QScriptValue g = P.property("green"); \ + QScriptValue b = P.property("blue"); \ + if (r.isValid() && g.isValid() && b.isValid()) {\ + xColor newColor; \ + newColor.red = r.toVariant().toInt(); \ + newColor.green = g.toVariant().toInt(); \ + newColor.blue = b.toVariant().toInt(); \ + if (_defaultSettings || \ + (newColor.red != _color.red || \ + newColor.green != _color.green || \ + newColor.blue != _color.blue)) { \ + S(newColor); \ + } \ + } \ + } + + #endif // hifi_EntityItemPropertiesMacros_h From a3e47aa3010b25af37203c43cb91133c627e9fb0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 17:46:50 -0700 Subject: [PATCH 18/38] fix angular velocity damping so we don't get bad quats --- libraries/entities/src/EntityItem.cpp | 33 +++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 693f8bd177..fc66b9bc6c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -535,21 +535,27 @@ void EntityItem::update(const quint64& updateTime) { if (hasAngularVelocity()) { glm::quat rotation = getRotation(); glm::vec3 angularVelocity = glm::radians(getAngularVelocity()); - float angle = timeElapsed * glm::length(angularVelocity); - glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); - rotation = dQ * rotation; - setRotation(rotation); + float angularSpeed = glm::length(angularVelocity); + + if (angularSpeed < EPSILON_VELOCITY_LENGTH) { + setAngularVelocity(NO_ANGULAR_VELOCITY); + } else { + float angle = timeElapsed * angularSpeed; + glm::quat dQ = glm::angleAxis(angle, glm::normalize(angularVelocity)); + rotation = dQ * rotation; + setRotation(rotation); - // handle damping for angular velocity - if (getAngularDamping() > 0.0f) { - glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); - if (wantDebug) { - qDebug() << " getDamping():" << getDamping(); - qDebug() << " dampingResistance:" << dampingResistance; - qDebug() << " dampingResistance * timeElapsed:" << dampingResistance * timeElapsed; + // handle damping for angular velocity + if (getAngularDamping() > 0.0f) { + glm::vec3 dampingResistance = getAngularVelocity() * getAngularDamping(); + glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); + setAngularVelocity(newAngularVelocity); + if (wantDebug) { + qDebug() << " getDamping():" << getDamping(); + qDebug() << " dampingResistance:" << dampingResistance; + qDebug() << " newAngularVelocity:" << newAngularVelocity; + } } - glm::vec3 newAngularVelocity = getAngularVelocity() - (dampingResistance * timeElapsed); - setAngularVelocity(newAngularVelocity); } } @@ -649,7 +655,6 @@ void EntityItem::copyChangedProperties(const EntityItem& other) { EntityItemProperties EntityItem::getProperties() const { EntityItemProperties properties; - properties._id = getID(); properties._idSet = true; properties._created = _created; From a3e3a1dc2b70719c64680223c9dab1177112d45f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 10 Sep 2014 20:07:45 -0700 Subject: [PATCH 19/38] cleanup dead code --- libraries/entities/src/EntityItemProperties.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index c2eebe82a9..8223cb5e34 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -126,7 +126,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(isKnownID, false); } - //properties.setProperty("type", EntityTypes::getEntityTypeName(_type)); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type)); COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(position); COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(dimensions); From f00947ada7adeaf8e63301591c0658d61c451054 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 08:33:41 -0700 Subject: [PATCH 20/38] handle registration point in rendering of box, sphere, and model entities --- examples/editModels.js | 10 +++++ .../src/entities/RenderableBoxEntityItem.cpp | 18 ++++++--- .../entities/RenderableModelEntityItem.cpp | 2 +- .../entities/RenderableSphereEntityItem.cpp | 14 +++++-- interface/src/renderer/Model.cpp | 34 +++++++++-------- interface/src/renderer/Model.h | 19 +++++++--- libraries/entities/src/EntityItem.cpp | 38 ++++++++++--------- libraries/entities/src/EntityItem.h | 5 ++- 8 files changed, 91 insertions(+), 49 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index ca45c94995..740c992888 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2865,6 +2865,13 @@ function handeMenuEvent(menuItem) { array.push({ label: "Z:", value: properties.position.z.toFixed(decimals) }); index++; + array.push({ label: "Registration X:", value: properties.registrationPoint.x.toFixed(decimals) }); + index++; + array.push({ label: "Registration Y:", value: properties.registrationPoint.y.toFixed(decimals) }); + index++; + array.push({ label: "Registration Z:", value: properties.registrationPoint.z.toFixed(decimals) }); + index++; + array.push({ label: "Rotation:", type: "header" }); index++; var angles = Quat.safeEulerAngles(properties.rotation); @@ -3023,6 +3030,9 @@ Window.nonBlockingFormClosed.connect(function() { properties.position.x = array[index++].value; properties.position.y = array[index++].value; properties.position.z = array[index++].value; + properties.registrationPoint.x = array[index++].value; + properties.registrationPoint.y = array[index++].value; + properties.registrationPoint.z = array[index++].value; index++; // skip header var angles = Quat.safeEulerAngles(properties.rotation); diff --git a/interface/src/entities/RenderableBoxEntityItem.cpp b/interface/src/entities/RenderableBoxEntityItem.cpp index 0156f051ae..1397bf8e34 100644 --- a/interface/src/entities/RenderableBoxEntityItem.cpp +++ b/interface/src/entities/RenderableBoxEntityItem.cpp @@ -32,7 +32,8 @@ EntityItem* RenderableBoxEntityItem::factory(const EntityItemID& entityID, const void RenderableBoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableBoxEntityItem::render"); assert(getType() == EntityTypes::Box); - glm::vec3 position = getPosition() * (float)TREE_SCALE; + glm::vec3 position = getPositionInMeters(); + glm::vec3 center = getCenter() * (float)TREE_SCALE; glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; glm::vec3 halfDimensions = dimensions / 2.0f; glm::quat rotation = getRotation(); @@ -43,7 +44,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { if (useGlutCube) { glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]); glPushMatrix(); - glTranslatef(position.x, position.y, position.z); + glTranslatef(center.x, center.y, center.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glScalef(dimensions.x, dimensions.y, dimensions.z); @@ -87,10 +88,15 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - // we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1 - glScalef(halfDimensions.x, halfDimensions.y, halfDimensions.z); - glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + // we need to do half the size because the geometry in the VBOs are from -1,-1,-1 to 1,1,1 + glScalef(halfDimensions.x, halfDimensions.y, halfDimensions.z); + glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices); + glPopMatrix(); glPopMatrix(); glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index f74abd2a13..643cceb030 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -99,7 +99,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::quat rotation = getRotation(); if (needsSimulation() && _model->isActive()) { _model->setScaleToFit(true, dimensions); - _model->setSnapModelToCenter(true); + _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setRotation(rotation); _model->setTranslation(position); diff --git a/interface/src/entities/RenderableSphereEntityItem.cpp b/interface/src/entities/RenderableSphereEntityItem.cpp index d03a384063..d5286b0ab3 100644 --- a/interface/src/entities/RenderableSphereEntityItem.cpp +++ b/interface/src/entities/RenderableSphereEntityItem.cpp @@ -31,7 +31,8 @@ EntityItem* RenderableSphereEntityItem::factory(const EntityItemID& entityID, co void RenderableSphereEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableSphereEntityItem::render"); assert(getType() == EntityTypes::Sphere); - glm::vec3 position = getPosition() * (float)TREE_SCALE; + glm::vec3 position = getPositionInMeters(); + glm::vec3 center = getCenterInMeters(); glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; glm::quat rotation = getRotation(); @@ -40,7 +41,14 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glScalef(dimensions.x, dimensions.y, dimensions.z); - glutSolidSphere(0.5f, 15, 15); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + + glScalef(dimensions.x, dimensions.y, dimensions.z); + glutSolidSphere(0.5f, 15, 15); + glPopMatrix(); glPopMatrix(); }; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 867083fe90..280f5bd21a 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -56,8 +56,8 @@ Model::Model(QObject* parent) : _scaleToFit(false), _scaleToFitDimensions(0.0f), _scaledToFit(false), - _snapModelToCenter(false), - _snappedToCenter(false), + _snapModelToRegistrationPoint(false), + _snappedToRegistrationPoint(false), _showTrueJointTransforms(true), _lodDistance(0.0f), _pupilDilation(0.0f), @@ -157,8 +157,8 @@ void Model::setOffset(const glm::vec3& offset) { _offset = offset; // if someone manually sets our offset, then we are no longer snapped to center - _snapModelToCenter = false; - _snappedToCenter = false; + _snapModelToRegistrationPoint = false; + _snappedToRegistrationPoint = false; } void Model::initProgram(ProgramObject& program, Model::Locations& locations, @@ -905,30 +905,34 @@ void Model::scaleToFit() { _scaledToFit = true; } -void Model::setSnapModelToCenter(bool snapModelToCenter) { - if (_snapModelToCenter != snapModelToCenter) { - _snapModelToCenter = snapModelToCenter; - _snappedToCenter = false; // force re-centering +void Model::setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint) { + glm::vec3 clampedRegistrationPoint = glm::clamp(registrationPoint, 0.0f, 1.0f); + if (_snapModelToRegistrationPoint != snapModelToRegistrationPoint || _registrationPoint != clampedRegistrationPoint) { + _snapModelToRegistrationPoint = snapModelToRegistrationPoint; + _registrationPoint = clampedRegistrationPoint; + _snappedToRegistrationPoint = false; // force re-centering } } -void Model::snapToCenter() { +void Model::snapToRegistrationPoint() { Extents modelMeshExtents = getUnscaledMeshExtents(); - glm::vec3 halfDimensions = (modelMeshExtents.maximum - modelMeshExtents.minimum) * 0.5f; - glm::vec3 offset = -modelMeshExtents.minimum - halfDimensions; + glm::vec3 dimensions = (modelMeshExtents.maximum - modelMeshExtents.minimum); + glm::vec3 offset = -modelMeshExtents.minimum - (dimensions * _registrationPoint); _offset = offset; - _snappedToCenter = true; + _snappedToRegistrationPoint = true; } void Model::simulate(float deltaTime, bool fullUpdate) { - fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit) || (_snapModelToCenter && !_snappedToCenter); + fullUpdate = updateGeometry() || fullUpdate || (_scaleToFit && !_scaledToFit) + || (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint); + if (isActive() && fullUpdate) { // check for scale to fit if (_scaleToFit && !_scaledToFit) { scaleToFit(); } - if (_snapModelToCenter && !_snappedToCenter) { - snapToCenter(); + if (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint) { + snapToRegistrationPoint(); } simulateInternal(deltaTime); } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index f56aed37a0..6c27970d8e 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -55,8 +55,15 @@ public: const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions); - void setSnapModelToCenter(bool snapModelToCenter); - bool getSnapModelToCenter() { return _snapModelToCenter; } + void setSnapModelToCenter(bool snapModelToCenter) { + setSnapModelToRegistrationPoint(snapModelToCenter, glm::vec3(0.5f,0.5f,0.5f)); + }; + bool getSnapModelToCenter() { + return _snapModelToRegistrationPoint && _registrationPoint == glm::vec3(0.5f,0.5f,0.5f); + } + + void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); + bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } void setScale(const glm::vec3& scale); const glm::vec3& getScale() const { return _scale; } @@ -185,8 +192,10 @@ protected: glm::vec3 _scaleToFitDimensions; /// this is the dimensions that scale to fit will use bool _scaledToFit; /// have we scaled to fit - bool _snapModelToCenter; /// is the model's offset automatically adjusted to center around 0,0,0 in model space - bool _snappedToCenter; /// are we currently snapped to center + bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space + bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point + glm::vec3 _registrationPoint; /// the point in model space our center is snapped to + bool _showTrueJointTransforms; QVector _localLights; @@ -207,7 +216,7 @@ protected: void setScaleInternal(const glm::vec3& scale); void scaleToFit(); - void snapToCenter(); + void snapToRegistrationPoint(); void simulateInternal(float deltaTime); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fc66b9bc6c..d84b11284f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -499,14 +499,6 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s } } -float EntityItem::getDistanceToBottomOfEntity() const { - // TODO: change this to support registration point - // TODO: fix this to correctly handle rotation... since _dimensions is in entity space, - // if the entity has been rotated, then the distance to world.y=0 is not the same - // as the dimensions.y - return _dimensions.y / 2.0f; -} - bool EntityItem::isRestingOnSurface() const { // TODO: change this to support registration point return _position.y <= getDistanceToBottomOfEntity() @@ -727,20 +719,30 @@ float EntityItem::getSize() const { return glm::length(_dimensions); } -// TODO: Add support for registration point -glm::vec3 EntityItem::getMinimumPoint() const { - // This assumes the registration point is in the center, we need to update this when we really support - // registration point - return _position - (_dimensions / 2.0f); +// TODO: fix this to correctly handle rotation... since _dimensions is in entity space, +// if the entity has been rotated, then the distance to world.y=0 is not the same +// as the dimensions.y +float EntityItem::getDistanceToBottomOfEntity() const { + glm::vec3 minimumPoint = getMinimumPoint(); + return minimumPoint.y; } -// TODO: Add support for registration point -glm::vec3 EntityItem::getMaximumPoint() const { - // This assumes the registration point is in the center, we need to update this when we really support - // registration point - return _position + (_dimensions / 2.0f); +// TODO: doesn't this need to handle rotation? +glm::vec3 EntityItem::getMinimumPoint() const { + return _position - (_dimensions * _registrationPoint); } +// TODO: doesn't this need to handle rotation? +glm::vec3 EntityItem::getMaximumPoint() const { + glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + return _position + (_dimensions * registrationRemainder); +} + +glm::vec3 EntityItem::getCenter() const { + return _position + (_dimensions * (glm::vec3(0.5f,0.5f,0.5f) - _registrationPoint)); +} + + // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension // ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a95bb3f462..08d44fc553 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -126,6 +126,9 @@ public: void setPositionInMeters(const glm::vec3& value) /// set position in meter units (0.0 - TREE_SCALE) { setPosition(glm::clamp(value / (float) TREE_SCALE, 0.0f, 1.0f)); } + glm::vec3 getCenter() const; /// calculates center of the entity in domain scale units (0.0 - 1.0) + glm::vec3 getCenterInMeters() const { return getCenter() * (float) TREE_SCALE; } + static const glm::vec3 DEFAULT_DIMENSIONS; const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in domain scale units (0.0 - 1.0) glm::vec3 getDimensionsInMeters() const { return _dimensions * (float) TREE_SCALE; } /// get dimensions in meters @@ -203,7 +206,7 @@ public: static const glm::vec3 DEFAULT_REGISTRATION_POINT; const glm::vec3& getRegistrationPoint() const { return _registrationPoint; } /// registration point as ratio of entity - void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = value; } /// registration point as ratio of entity + void setRegistrationPoint(const glm::vec3& value) { _registrationPoint = glm::clamp(value, 0.0f, 1.0f); } /// registration point as ratio of entity static const glm::vec3 NO_ANGULAR_VELOCITY; static const glm::vec3 DEFAULT_ANGULAR_VELOCITY; From 13cffa6e44e8d3b9a0146e5d0da820e7ea58dd0f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 12:12:25 -0700 Subject: [PATCH 21/38] moved Extents to shared --- libraries/fbx/src/FBXReader.cpp | 21 --------- libraries/fbx/src/FBXReader.h | 27 +----------- libraries/shared/src/Extents.cpp | 74 ++++++++++++++++++++++++++++++++ libraries/shared/src/Extents.h | 53 +++++++++++++++++++++++ 4 files changed, 129 insertions(+), 46 deletions(-) create mode 100644 libraries/shared/src/Extents.cpp create mode 100644 libraries/shared/src/Extents.h diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 6f87bcf1f8..88888ac381 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -33,27 +33,6 @@ using namespace std; -void Extents::reset() { - minimum = glm::vec3(FLT_MAX); - maximum = glm::vec3(-FLT_MAX); -} - -bool Extents::containsPoint(const glm::vec3& point) const { - return (point.x >= minimum.x && point.x <= maximum.x - && point.y >= minimum.y && point.y <= maximum.y - && point.z >= minimum.z && point.z <= maximum.z); -} - -void Extents::addExtents(const Extents& extents) { - minimum = glm::min(minimum, extents.minimum); - maximum = glm::max(maximum, extents.maximum); -} - -void Extents::addPoint(const glm::vec3& point) { - minimum = glm::min(minimum, point); - maximum = glm::max(maximum, point); -} - bool FBXMesh::hasSpecularTexture() const { foreach (const FBXMeshPart& part, parts) { if (!part.specularTexture.filename.isEmpty()) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index d07a33f3d4..e54e218a5b 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -18,8 +18,10 @@ #include #include +#include #include + #include #include @@ -35,31 +37,6 @@ extern const int NUM_FACESHIFT_BLENDSHAPES; /// The names of the joints in the Maya HumanIK rig, terminated with an empty string. extern const char* HUMANIK_JOINTS[]; -class Extents { -public: - /// set minimum and maximum to FLT_MAX and -FLT_MAX respectively - void reset(); - - /// \param extents another intance of extents - /// expand current limits to contain other extents - void addExtents(const Extents& extents); - - /// \param point new point to compare against existing limits - /// compare point to current limits and expand them if necessary to contain point - void addPoint(const glm::vec3& point); - - /// \param point - /// \return true if point is within current limits - bool containsPoint(const glm::vec3& point) const; - - /// \return whether or not the extents are empty - bool isEmpty() const { return minimum == maximum; } - bool isValid() const { return !((minimum == glm::vec3(FLT_MAX)) && (maximum == glm::vec3(-FLT_MAX))); } - - glm::vec3 minimum; - glm::vec3 maximum; -}; - /// A node within an FBX document. class FBXNode { public: diff --git a/libraries/shared/src/Extents.cpp b/libraries/shared/src/Extents.cpp new file mode 100644 index 0000000000..02e09bfa3c --- /dev/null +++ b/libraries/shared/src/Extents.cpp @@ -0,0 +1,74 @@ +// +// Extents.cpp +// libraries/shared/src +// +// Created by Andrzej Kapolka on 9/18/13. +// Moved to shared by Brad Hefta-Gaub on 9/11/14 +// Copyright 2013-2104 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 +#include +#include + +#include "Extents.h" + +void Extents::reset() { + minimum = glm::vec3(FLT_MAX); + maximum = glm::vec3(-FLT_MAX); +} + +bool Extents::containsPoint(const glm::vec3& point) const { + return (point.x >= minimum.x && point.x <= maximum.x + && point.y >= minimum.y && point.y <= maximum.y + && point.z >= minimum.z && point.z <= maximum.z); +} + +void Extents::addExtents(const Extents& extents) { + minimum = glm::min(minimum, extents.minimum); + maximum = glm::max(maximum, extents.maximum); +} + +void Extents::addPoint(const glm::vec3& point) { + minimum = glm::min(minimum, point); + maximum = glm::max(maximum, point); +} + +void Extents::rotate(const glm::quat& rotation) { + glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z); + glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z); + glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z); + glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z); + glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z); + glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z); + glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z); + glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z); + + glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear; + glm::vec3 bottomRightNearRotated = rotation * bottomRightNear; + glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar; + glm::vec3 bottomRightFarRotated = rotation * bottomRightFar; + glm::vec3 topLeftNearRotated = rotation * topLeftNear; + glm::vec3 topRightNearRotated = rotation * topRightNear; + glm::vec3 topLeftFarRotated = rotation * topLeftFar; + glm::vec3 topRightFarRotated = rotation * topRightFar; + + minimum = glm::min(bottomLeftNearRotated, + glm::min(bottomRightNearRotated, + glm::min(bottomLeftFarRotated, + glm::min(bottomRightFarRotated, + glm::min(topLeftNearRotated, + glm::min(topRightNearRotated, + glm::min(topLeftFarRotated,topRightFarRotated))))))); + + maximum = glm::max(bottomLeftNearRotated, + glm::max(bottomRightNearRotated, + glm::max(bottomLeftFarRotated, + glm::max(bottomRightFarRotated, + glm::max(topLeftNearRotated, + glm::max(topRightNearRotated, + glm::max(topLeftFarRotated,topRightFarRotated))))))); +} diff --git a/libraries/shared/src/Extents.h b/libraries/shared/src/Extents.h new file mode 100644 index 0000000000..c0e68bd2b1 --- /dev/null +++ b/libraries/shared/src/Extents.h @@ -0,0 +1,53 @@ +// +// Extents.h +// libraries/shared/src +// +// Created by Andrzej Kapolka on 9/18/13. +// Moved to shared by Brad Hefta-Gaub on 9/11/14 +// Copyright 2013-2104 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_Extents_h +#define hifi_Extents_h + +#include + +class Extents { +public: + /// set minimum and maximum to FLT_MAX and -FLT_MAX respectively + void reset(); + + /// \param extents another intance of extents + /// expand current limits to contain other extents + void addExtents(const Extents& extents); + + /// \param point new point to compare against existing limits + /// compare point to current limits and expand them if necessary to contain point + void addPoint(const glm::vec3& point); + + /// \param point + /// \return true if point is within current limits + bool containsPoint(const glm::vec3& point) const; + + /// \return whether or not the extents are empty + bool isEmpty() const { return minimum == maximum; } + bool isValid() const { return !((minimum == glm::vec3(FLT_MAX)) && (maximum == glm::vec3(-FLT_MAX))); } + + /// rotate the extents around orign by rotation + void rotate(const glm::quat& rotation); + + /// \return new Extents which is original rotated around orign by rotation + Extents getRotated(const glm::quat& rotation) const { + Extents temp = { minimum, maximum }; + temp.rotate(rotation); + return temp; + } + + glm::vec3 minimum; + glm::vec3 maximum; +}; + +#endif // hifi_Extents_h \ No newline at end of file From 7cadc3433a5a61ddbf359327b252d120110d2696 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 12:13:34 -0700 Subject: [PATCH 22/38] improve constness for operators on PropertyFlags<> --- libraries/shared/src/PropertyFlags.h | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/libraries/shared/src/PropertyFlags.h b/libraries/shared/src/PropertyFlags.h index 9b21ff9f9f..846c4886b0 100644 --- a/libraries/shared/src/PropertyFlags.h +++ b/libraries/shared/src/PropertyFlags.h @@ -49,7 +49,7 @@ public: Enum lastFlag() const { return (Enum)_maxFlag; } void setHasProperty(Enum flag, bool value = true); - bool getHasProperty(Enum flag); + bool getHasProperty(Enum flag) const; QByteArray encode(); void decode(const QByteArray& fromEncoded); @@ -61,42 +61,42 @@ public: PropertyFlags& operator=(const PropertyFlags& other); - PropertyFlags& operator|=(PropertyFlags other); + PropertyFlags& operator|=(const PropertyFlags& other); PropertyFlags& operator|=(Enum flag); - PropertyFlags& operator&=(PropertyFlags other); + PropertyFlags& operator&=(const PropertyFlags& other); PropertyFlags& operator&=(Enum flag); - PropertyFlags& operator+=(PropertyFlags other); + PropertyFlags& operator+=(const PropertyFlags& other); PropertyFlags& operator+=(Enum flag); - PropertyFlags& operator-=(PropertyFlags other); + PropertyFlags& operator-=(const PropertyFlags& other); PropertyFlags& operator-=(Enum flag); - PropertyFlags& operator<<=(PropertyFlags other); + PropertyFlags& operator<<=(const PropertyFlags& other); PropertyFlags& operator<<=(Enum flag); - PropertyFlags operator|(PropertyFlags other) const; + PropertyFlags operator|(const PropertyFlags& other) const; PropertyFlags operator|(Enum flag) const; - PropertyFlags operator&(PropertyFlags other) const; + PropertyFlags operator&(const PropertyFlags& other) const; PropertyFlags operator&(Enum flag) const; - PropertyFlags operator+(PropertyFlags other) const; + PropertyFlags operator+(const PropertyFlags& other) const; PropertyFlags operator+(Enum flag) const; - PropertyFlags operator-(PropertyFlags other) const; + PropertyFlags operator-(const PropertyFlags& other) const; PropertyFlags operator-(Enum flag) const; - PropertyFlags operator<<(PropertyFlags other) const; + PropertyFlags operator<<(const PropertyFlags& other) const; PropertyFlags operator<<(Enum flag) const; // NOTE: due to the nature of the compact storage of these property flags, and the fact that the upper bound of the // enum is not know, these operators will only perform their bitwise operations on the set of properties that have // been previously set - PropertyFlags& operator^=(PropertyFlags other); + PropertyFlags& operator^=(const PropertyFlags& other); PropertyFlags& operator^=(Enum flag); - PropertyFlags operator^(PropertyFlags other) const; + PropertyFlags operator^(const PropertyFlags& other) const; PropertyFlags operator^(Enum flag) const; PropertyFlags operator~() const; @@ -146,7 +146,7 @@ template inline void PropertyFlags::setHasProperty(Enum fla } } -template inline bool PropertyFlags::getHasProperty(Enum flag) { +template inline bool PropertyFlags::getHasProperty(Enum flag) const { if (flag > _maxFlag) { return _trailingFlipped; // usually false } @@ -253,7 +253,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator|=(PropertyFlags other) { +template inline PropertyFlags& PropertyFlags::operator|=(const PropertyFlags& other) { _flags |= other._flags; _maxFlag = std::max(_maxFlag, other._maxFlag); _minFlag = std::min(_minFlag, other._minFlag); @@ -268,7 +268,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator&=(PropertyFlags other) { +template inline PropertyFlags& PropertyFlags::operator&=(const PropertyFlags& other) { _flags &= other._flags; shinkIfNeeded(); return *this; @@ -281,7 +281,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator^=(PropertyFlags other) { +template inline PropertyFlags& PropertyFlags::operator^=(const PropertyFlags& other) { _flags ^= other._flags; shinkIfNeeded(); return *this; @@ -294,7 +294,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator+=(PropertyFlags other) { +template inline PropertyFlags& PropertyFlags::operator+=(const PropertyFlags& other) { for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { if (other.getHasProperty((Enum)flag)) { setHasProperty((Enum)flag, true); @@ -308,7 +308,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator-=(PropertyFlags other) { +template inline PropertyFlags& PropertyFlags::operator-=(const PropertyFlags& other) { for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { if (other.getHasProperty((Enum)flag)) { setHasProperty((Enum)flag, false); @@ -322,7 +322,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags& PropertyFlags::operator<<=(PropertyFlags other) { +template inline PropertyFlags& PropertyFlags::operator<<=(const PropertyFlags& other) { for(int flag = (int)other.firstFlag(); flag <= (int)other.lastFlag(); flag++) { if (other.getHasProperty((Enum)flag)) { setHasProperty((Enum)flag, true); @@ -336,7 +336,7 @@ template inline PropertyFlags& PropertyFlags::operato return *this; } -template inline PropertyFlags PropertyFlags::operator|(PropertyFlags other) const { +template inline PropertyFlags PropertyFlags::operator|(const PropertyFlags& other) const { PropertyFlags result(*this); result |= other; return result; @@ -349,7 +349,7 @@ template inline PropertyFlags PropertyFlags::operator return result; } -template inline PropertyFlags PropertyFlags::operator&(PropertyFlags other) const { +template inline PropertyFlags PropertyFlags::operator&(const PropertyFlags& other) const { PropertyFlags result(*this); result &= other; return result; @@ -362,7 +362,7 @@ template inline PropertyFlags PropertyFlags::operator return result; } -template inline PropertyFlags PropertyFlags::operator^(PropertyFlags other) const { +template inline PropertyFlags PropertyFlags::operator^(const PropertyFlags& other) const { PropertyFlags result(*this); result ^= other; return result; @@ -375,7 +375,7 @@ template inline PropertyFlags PropertyFlags::operator return result; } -template inline PropertyFlags PropertyFlags::operator+(PropertyFlags other) const { +template inline PropertyFlags PropertyFlags::operator+(const PropertyFlags& other) const { PropertyFlags result(*this); result += other; return result; @@ -387,7 +387,7 @@ template inline PropertyFlags PropertyFlags::operator return result; } -template inline PropertyFlags PropertyFlags::operator-(PropertyFlags other) const { +template inline PropertyFlags PropertyFlags::operator-(const PropertyFlags& other) const { PropertyFlags result(*this); result -= other; return result; @@ -399,7 +399,7 @@ template inline PropertyFlags PropertyFlags::operator return result; } -template inline PropertyFlags PropertyFlags::operator<<(PropertyFlags other) const { +template inline PropertyFlags PropertyFlags::operator<<(const PropertyFlags& other) const { PropertyFlags result(*this); result <<= other; return result; From d616c7fa0c4c4608cce3732a21bd6b0eadce27b1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 12:23:35 -0700 Subject: [PATCH 23/38] handy conversions between AABox, AACube, and Extents --- libraries/shared/src/AABox.cpp | 6 ++++++ libraries/shared/src/AABox.h | 2 ++ libraries/shared/src/AACube.cpp | 14 ++++++++++++++ libraries/shared/src/AACube.h | 5 ++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index 4c01801d5d..00e6db7d33 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -11,6 +11,7 @@ #include "AABox.h" #include "AACube.h" +#include "Extents.h" #include "GeometryUtil.h" #include "SharedUtil.h" @@ -19,6 +20,11 @@ AABox::AABox(const AACube& other) : _corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) { } +AABox::AABox(const Extents& other) : + _corner(other.minimum), + _scale(other.maximum - other.minimum) { +} + AABox::AABox(const glm::vec3& corner, float size) : _corner(corner), _scale(size, size, size) { }; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 30ebc00afb..5e5cff4574 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -23,11 +23,13 @@ #include "StreamUtils.h" class AACube; +class Extents; class AABox { public: AABox(const AACube& other); + AABox(const Extents& other); AABox(const glm::vec3& corner, float size); AABox(const glm::vec3& corner, const glm::vec3& dimensions); AABox(); diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index bf8e972455..55940ba50b 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -9,11 +9,25 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "AABox.h" #include "AACube.h" +#include "Extents.h" #include "GeometryUtil.h" #include "SharedUtil.h" +AACube::AACube(const AABox& other) : + _corner(other.getCorner()), _scale(other.getLargestDimension()) { +} + +AACube::AACube(const Extents& other) : + _corner(other.minimum) +{ + glm::vec3 dimensions = other.maximum - other.minimum; + _scale = glm::max(dimensions.x, dimensions.y, dimensions.z); +} + AACube::AACube(const glm::vec3& corner, float size) : _corner(corner), _scale(size) { }; diff --git a/libraries/shared/src/AACube.h b/libraries/shared/src/AACube.h index 705c025d74..f56f2dee2e 100644 --- a/libraries/shared/src/AACube.h +++ b/libraries/shared/src/AACube.h @@ -1,6 +1,6 @@ // // AACube.h -// libraries/octree/src +// libraries/shared/src // // Created by Brad Hefta-Gaub on 04/11/13. // Copyright 2013 High Fidelity, Inc. @@ -22,10 +22,13 @@ #include "BoxBase.h" class AABox; +class Extents; class AACube { public: + AACube(const AABox& other); + AACube(const Extents& other); AACube(const glm::vec3& corner, float size); AACube(); ~AACube() {}; From 2757f160453bd0545c0722e90e0ae4aa10ec4101 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 12:29:47 -0700 Subject: [PATCH 24/38] remove calls to calculateRotatedExtents() use Extents.rotate() instead --- .../entities/RenderableModelEntityItem.cpp | 2 +- interface/src/ui/overlays/ModelOverlay.cpp | 2 +- libraries/entities/src/EntityTreeElement.cpp | 2 +- libraries/fbx/src/FBXReader.cpp | 37 ------------------- libraries/fbx/src/FBXReader.h | 2 - 5 files changed, 3 insertions(+), 42 deletions(-) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 643cceb030..6944120552 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -144,7 +144,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { float depth = unRotatedExtents.z; Extents rotatedExtents = _model->getUnscaledMeshExtents(); - calculateRotatedExtents(rotatedExtents, rotation); + rotatedExtents.rotate(rotation); glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index b1d55de12a..8d89fe28f0 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -58,7 +58,7 @@ void ModelOverlay::render() { float depth = unRotatedExtents.z; Extents rotatedExtents = _model.getUnscaledMeshExtents(); - calculateRotatedExtents(rotatedExtents, _rotation); + rotatedExtents.rotate(_rotation); glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 7f94d362eb..e5987bbbc2 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -509,7 +509,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con Extents rotatedExtents = extents; - calculateRotatedExtents(rotatedExtents, entity->getRotation()); + rotatedExtents.rotate(entity->getRotation()); rotatedExtents.minimum += entity->getPosition(); rotatedExtents.maximum += entity->getPosition(); diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 88888ac381..d81e297b24 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -2111,40 +2111,3 @@ FBXGeometry readSVO(const QByteArray& model) { return geometry; } - -void calculateRotatedExtents(Extents& extents, const glm::quat& rotation) { - glm::vec3 bottomLeftNear(extents.minimum.x, extents.minimum.y, extents.minimum.z); - glm::vec3 bottomRightNear(extents.maximum.x, extents.minimum.y, extents.minimum.z); - glm::vec3 bottomLeftFar(extents.minimum.x, extents.minimum.y, extents.maximum.z); - glm::vec3 bottomRightFar(extents.maximum.x, extents.minimum.y, extents.maximum.z); - glm::vec3 topLeftNear(extents.minimum.x, extents.maximum.y, extents.minimum.z); - glm::vec3 topRightNear(extents.maximum.x, extents.maximum.y, extents.minimum.z); - glm::vec3 topLeftFar(extents.minimum.x, extents.maximum.y, extents.maximum.z); - glm::vec3 topRightFar(extents.maximum.x, extents.maximum.y, extents.maximum.z); - - glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear; - glm::vec3 bottomRightNearRotated = rotation * bottomRightNear; - glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar; - glm::vec3 bottomRightFarRotated = rotation * bottomRightFar; - glm::vec3 topLeftNearRotated = rotation * topLeftNear; - glm::vec3 topRightNearRotated = rotation * topRightNear; - glm::vec3 topLeftFarRotated = rotation * topLeftFar; - glm::vec3 topRightFarRotated = rotation * topRightFar; - - extents.minimum = glm::min(bottomLeftNearRotated, - glm::min(bottomRightNearRotated, - glm::min(bottomLeftFarRotated, - glm::min(bottomRightFarRotated, - glm::min(topLeftNearRotated, - glm::min(topRightNearRotated, - glm::min(topLeftFarRotated,topRightFarRotated))))))); - - extents.maximum = glm::max(bottomLeftNearRotated, - glm::max(bottomRightNearRotated, - glm::max(bottomLeftFarRotated, - glm::max(bottomRightFarRotated, - glm::max(topLeftNearRotated, - glm::max(topRightNearRotated, - glm::max(topLeftFarRotated,topRightFarRotated))))))); -} - diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index e54e218a5b..48ac4fc81f 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -231,6 +231,4 @@ FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping); /// Reads SVO geometry from the supplied model data. FBXGeometry readSVO(const QByteArray& model); -void calculateRotatedExtents(Extents& extents, const glm::quat& rotation); - #endif // hifi_FBXReader_h From 9f4d1994404de895d253f8d1c931907a6a5d5c2c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 15:36:13 -0700 Subject: [PATCH 25/38] move bound proxy rendering to EntityTreeRedering, added helper functions for various bounding boxes --- interface/src/entities/EntityTreeRenderer.cpp | 80 +++++++++++++++++++ interface/src/entities/EntityTreeRenderer.h | 1 + .../src/entities/RenderableBoxEntityItem.cpp | 16 ++-- .../entities/RenderableModelEntityItem.cpp | 46 ----------- libraries/entities/src/EntityItem.cpp | 72 +++++++++++++++++ libraries/entities/src/EntityItem.h | 5 +- libraries/shared/src/Extents.h | 4 + 7 files changed, 171 insertions(+), 53 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 4d8d20f4e0..83b122939a 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -192,6 +192,83 @@ bool EntityTreeRenderer::shouldRenderEntity(float largestDimension, float distan return (distanceToCamera <= visibleDistanceAtScale); } +void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* args) { + bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE; + bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds); + if (!isShadowMode && displayModelBounds) { + PerformanceTimer perfTimer("renderProxies"); + + AACube maxCube = entity->getMaximumAACube(); + AACube minCube = entity->getMinimumAACube(); + AABox entityBox = entity->getAABox(); + + maxCube.scale((float)TREE_SCALE); + minCube.scale((float)TREE_SCALE); + entityBox.scale((float)TREE_SCALE); + + glm::vec3 maxCenter = maxCube.calcCenter(); + glm::vec3 minCenter = minCube.calcCenter(); + glm::vec3 entityBoxCenter = entityBox.calcCenter(); + glm::vec3 entityBoxScale = entityBox.getScale(); + + // draw the max bounding cube + glColor4f(1.0f, 1.0f, 0.0f, 1.0f); + glPushMatrix(); + glTranslatef(maxCenter.x, maxCenter.y, maxCenter.z); + glutWireCube(maxCube.getScale()); + glPopMatrix(); + + // draw the min bounding cube + glColor4f(0.0f, 1.0f, 0.0f, 1.0f); + glPushMatrix(); + glTranslatef(minCenter.x, minCenter.y, minCenter.z); + glutWireCube(minCube.getScale()); + glPopMatrix(); + + // draw the entityBox bounding box + glColor4f(0.0f, 0.0f, 1.0f, 1.0f); + glPushMatrix(); + glTranslatef(entityBoxCenter.x, entityBoxCenter.y, entityBoxCenter.z); + glScalef(entityBoxScale.x, entityBoxScale.y, entityBoxScale.z); + glutWireCube(1.0f); + glPopMatrix(); + + + glm::vec3 position = entity->getPosition() * (float)TREE_SCALE; + glm::vec3 center = entity->getCenter() * (float)TREE_SCALE; + glm::vec3 dimensions = entity->getDimensions() * (float)TREE_SCALE; + glm::quat rotation = entity->getRotation(); + + glColor4f(1.0f, 0.0f, 1.0f, 1.0f); + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + glScalef(dimensions.x, dimensions.y, dimensions.z); + glutWireCube(1.0f); + glPopMatrix(); + glPopMatrix(); + + /* + glPushMatrix(); + // draw the model relative bounding box + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z); + glColor3f(0.0f, 1.0f, 0.0f); + glutWireCube(1.0); + + glPopMatrix(); + */ + + } +} + void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) { args->_elementsTouched++; // actually render it here... @@ -226,6 +303,9 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) float distance = distanceToCamera(entityCube.calcCenter(), *args->_viewFrustum); if (shouldRenderEntity(entityCube.getLargestDimension(), distance) && args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) { + + + renderProxies(entityItem, args); Glower* glower = NULL; if (entityItem->getGlowLevel() > 0.0f) { diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index f6a5c41a39..9e0368b61b 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -79,6 +79,7 @@ private: float distanceToCamera(const glm::vec3& center, const ViewFrustum& viewFrustum) const; bool shouldRenderEntity(float largestDimension, float distanceToCamera) const; + void renderProxies(const EntityItem* entity, RenderArgs* args); }; diff --git a/interface/src/entities/RenderableBoxEntityItem.cpp b/interface/src/entities/RenderableBoxEntityItem.cpp index 1397bf8e34..f90bc6cccc 100644 --- a/interface/src/entities/RenderableBoxEntityItem.cpp +++ b/interface/src/entities/RenderableBoxEntityItem.cpp @@ -38,20 +38,24 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glm::vec3 halfDimensions = dimensions / 2.0f; glm::quat rotation = getRotation(); - - const bool useGlutCube = false; + const bool useGlutCube = true; if (useGlutCube) { glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]); glPushMatrix(); - glTranslatef(center.x, center.y, center.z); + glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glScalef(dimensions.x, dimensions.y, dimensions.z); - glutSolidCube(1.0f); + + + glPushMatrix(); + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + glScalef(dimensions.x, dimensions.y, dimensions.z); + glutSolidCube(1.0f); + glPopMatrix(); glPopMatrix(); } else { - static GLfloat vertices[] = { 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0,v1,v2,v3 (front) 1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0,v3,v4,v5 (right) 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0,v5,v6,v1 (top) diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 6944120552..4347087287 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -128,52 +128,6 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glutWireCube(size); glPopMatrix(); } - - bool isShadowMode = args->_renderMode == OctreeRenderer::SHADOW_RENDER_MODE; - bool displayModelBounds = Menu::getInstance()->isOptionChecked(MenuOption::DisplayModelBounds); - - if (!isShadowMode && displayModelBounds) { - PerformanceTimer perfTimer("displayModelBounds"); - - glm::vec3 unRotatedMinimum = _model->getUnscaledMeshExtents().minimum; - glm::vec3 unRotatedMaximum = _model->getUnscaledMeshExtents().maximum; - glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum; - - float width = unRotatedExtents.x; - float height = unRotatedExtents.y; - float depth = unRotatedExtents.z; - - Extents rotatedExtents = _model->getUnscaledMeshExtents(); - rotatedExtents.rotate(rotation); - - glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum; - - const glm::vec3& modelScale = _model->getScale(); - - glPushMatrix(); - glTranslatef(position.x, position.y, position.z); - - // draw the orignal bounding cube - glColor4f(1.0f, 1.0f, 0.0f, 1.0f); - glutWireCube(size); - - // draw the rotated bounding cube - glColor4f(0.0f, 0.0f, 1.0f, 1.0f); - glPushMatrix(); - glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z); - glutWireCube(1.0); - glPopMatrix(); - - // draw the model relative bounding box - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z); - glColor3f(0.0f, 1.0f, 0.0f); - glutWireCube(1.0); - - glPopMatrix(); - - } } else { // if we couldn't get a model, then just draw a cube glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d84b11284f..bcf8543c16 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -715,6 +715,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc return somethingChanged; } + +// TODO: is this really correct? how do we use size, does it need to handle rotation? float EntityItem::getSize() const { return glm::length(_dimensions); } @@ -738,10 +740,80 @@ glm::vec3 EntityItem::getMaximumPoint() const { return _position + (_dimensions * registrationRemainder); } +// TODO: doesn't this need to handle rotation? glm::vec3 EntityItem::getCenter() const { return _position + (_dimensions * (glm::vec3(0.5f,0.5f,0.5f) - _registrationPoint)); } +/// The maximum bounding cube for the entity, independent of it's rotation. +/// This accounts for the registration point (upon which rotation occurs around). +/// +AACube EntityItem::getMaximumAACube() const { + // * we know that the position is the center of rotation + glm::vec3 centerOfRotation = _position; // also where _registration point is + + // * we know that the registration point is the center of rotation + // * we can calculate the length of the furthest extent from the registration point + // as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint) + glm::vec3 registrationPoint = (_dimensions * _registrationPoint); + glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint)); + glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder); + + // * we know that if you rotate in any direction you would create a sphere + // that has a radius of the length of furthest extent from registration point + float radius = glm::length(furthestExtentFromRegistration); + + // * we know that the minimum bounding cube of this maximum possible sphere is + // (center - radius) to (center + radius) + glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius); + + AACube boundingCube(minimumCorner, radius * 2.0f); + return boundingCube; +} + +/// The minimum bounding cube for the entity accounting for it's rotation. +/// This accounts for the registration point (upon which rotation occurs around). +/// +AACube EntityItem::getMinimumAACube() const { + // _position represents the position of the registration point. + glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + + glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint); + glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); + + // shift the extents to be relative to the position/registration point + rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); + + // the cube that best encompasses extents is... + AABox box(rotatedExtentsRelativeToRegistrationPoint); + glm::vec3 centerOfBox = box.calcCenter(); + float longestSide = box.getLargestDimension(); + float halfLongestSide = longestSide / 2.0f; + glm::vec3 cornerOfCube = centerOfBox - glm::vec3(halfLongestSide, halfLongestSide, halfLongestSide); + + + // old implementation... not correct!!! + return AACube(cornerOfCube, longestSide); +} + +AABox EntityItem::getAABox() const { + + // _position represents the position of the registration point. + glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; + + glm::vec3 unrotatedMinRelativeToEntity = glm::vec3(0.0f, 0.0f, 0.0f) - (_dimensions * _registrationPoint); + glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); + + // shift the extents to be relative to the position/registration point + rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); + + return AABox(rotatedExtentsRelativeToRegistrationPoint); +} + // NOTE: This should only be used in cases of old bitstreams which only contain radius data // 0,0,0 --> maxDimension,maxDimension,maxDimension diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 08d44fc553..c921f3f074 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -198,7 +198,10 @@ public: float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0) glm::vec3 getMinimumPoint() const; glm::vec3 getMaximumPoint() const; - AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0) + AACube getMaximumAACube() const; + AACube getMinimumAACube() const; + AACube getAACube() const { return getMaximumAACube(); } /// axis aligned bounding cube in domain scale units (0.0 - 1.0) + AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0) static const QString DEFAULT_SCRIPT; const QString& getScript() const { return _script; } diff --git a/libraries/shared/src/Extents.h b/libraries/shared/src/Extents.h index c0e68bd2b1..2da3042467 100644 --- a/libraries/shared/src/Extents.h +++ b/libraries/shared/src/Extents.h @@ -35,6 +35,10 @@ public: /// \return whether or not the extents are empty bool isEmpty() const { return minimum == maximum; } bool isValid() const { return !((minimum == glm::vec3(FLT_MAX)) && (maximum == glm::vec3(-FLT_MAX))); } + + /// \param vec3 for delta amount to shift the extents by + /// \return true if point is within current limits + void shiftBy(const glm::vec3& delta) { minimum += delta; maximum += delta; } /// rotate the extents around orign by rotation void rotate(const glm::quat& rotation); From 2148baae217c12e3e2c6b9a1502d487b160d66ce Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 16:40:32 -0700 Subject: [PATCH 26/38] add boxInFrustum --- libraries/octree/src/ViewFrustum.cpp | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/libraries/octree/src/ViewFrustum.cpp b/libraries/octree/src/ViewFrustum.cpp index 9552129e29..1e8dc41cdd 100644 --- a/libraries/octree/src/ViewFrustum.cpp +++ b/libraries/octree/src/ViewFrustum.cpp @@ -392,6 +392,41 @@ ViewFrustum::location ViewFrustum::cubeInFrustum(const AACube& cube) const { return regularResult; } +ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const { + + ViewFrustum::location regularResult = INSIDE; + ViewFrustum::location keyholeResult = OUTSIDE; + + // If we have a keyholeRadius, check that first, since it's cheaper + if (_keyholeRadius >= 0.0f) { + keyholeResult = boxInKeyhole(box); + } + if (keyholeResult == INSIDE) { + return keyholeResult; + } + + // TODO: These calculations are expensive, taking up 80% of our time in this function. + // This appears to be expensive because we have to test the distance to each plane. + // One suggested optimization is to first check against the approximated cone. We might + // also be able to test against the cone to the bounding sphere of the box. + for(int i=0; i < 6; i++) { + const glm::vec3& normal = _planes[i].getNormal(); + const glm::vec3& boxVertexP = box.getVertexP(normal); + float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP); + + const glm::vec3& boxVertexN = box.getVertexN(normal); + float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN); + + if (planeToBoxVertexPDistance < 0) { + // This is outside the regular frustum, so just return the value from checking the keyhole + return keyholeResult; + } else if (planeToBoxVertexNDistance < 0) { + regularResult = INTERSECT; + } + } + return regularResult; +} + bool testMatches(glm::quat lhs, glm::quat rhs, float epsilon = EPSILON) { return (fabs(lhs.x - rhs.x) <= epsilon && fabs(lhs.y - rhs.y) <= epsilon && fabs(lhs.z - rhs.z) <= epsilon && fabs(lhs.w - rhs.w) <= epsilon); From 695569b64b1c1bdaec31ca383fd18620066f03ce Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 16:43:53 -0700 Subject: [PATCH 27/38] reconcile use of getAACube() and handle rotations properly --- interface/src/entities/EntityTreeRenderer.cpp | 10 +- libraries/entities/src/AddEntityOperator.cpp | 7 +- libraries/entities/src/EntityItem.cpp | 11 +- libraries/entities/src/EntityItem.h | 1 - .../entities/src/EntityItemProperties.cpp | 39 ++++-- libraries/entities/src/EntityItemProperties.h | 12 +- libraries/entities/src/EntityTree.cpp | 4 +- libraries/entities/src/EntityTreeElement.cpp | 115 +++++++----------- .../entities/src/UpdateEntityOperator.cpp | 8 +- 9 files changed, 100 insertions(+), 107 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 83b122939a..56b23a9df9 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -294,15 +294,15 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (entityItem->isVisible()) { // render entityItem - AACube entityCube = entityItem->getAACube(); + AABox entityBox = entityItem->getAABox(); - entityCube.scale(TREE_SCALE); + entityBox.scale(TREE_SCALE); // TODO: some entity types (like lights) might want to be rendered even // when they are outside of the view frustum... - float distance = distanceToCamera(entityCube.calcCenter(), *args->_viewFrustum); - if (shouldRenderEntity(entityCube.getLargestDimension(), distance) && - args->_viewFrustum->cubeInFrustum(entityCube) != ViewFrustum::OUTSIDE) { + float distance = distanceToCamera(entityBox.calcCenter(), *args->_viewFrustum); + if (shouldRenderEntity(entityBox.getLargestDimension(), distance) && + args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE) { renderProxies(entityItem, args); diff --git a/libraries/entities/src/AddEntityOperator.cpp b/libraries/entities/src/AddEntityOperator.cpp index 5a7be69dbf..d70aad1e1d 100644 --- a/libraries/entities/src/AddEntityOperator.cpp +++ b/libraries/entities/src/AddEntityOperator.cpp @@ -26,7 +26,12 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree, // caller must have verified existence of newEntity assert(_newEntity); - _newEntityBox = _newEntity->getAACube().clamp(0.0f, 1.0f); + + // Here we have a choice to make, do we want to "tight fit" the actual minimum for the + // entity into the the element, or do we want to use the entities "relaxed" bounds + // which can handle all potential rotations? + // the getMaximumAACube is the relaxed form. + _newEntityBox = _newEntity->getMaximumAACube().clamp(0.0f, 1.0f); } bool AddEntityOperator::preRecursion(OctreeElement* element) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index bcf8543c16..494be2ebbc 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -559,7 +559,7 @@ void EntityItem::update(const quint64& updateTime) { if (wantDebug) { qDebug() << "EntityItem::update()...."; qDebug() << " timeElapsed:" << timeElapsed; - qDebug() << " old AACube:" << getAACube(); + qDebug() << " old AACube:" << getMaximumAACube(); qDebug() << " old position:" << position; qDebug() << " old velocity:" << velocity; qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity(); @@ -618,7 +618,7 @@ void EntityItem::update(const quint64& updateTime) { setPosition(position); setVelocity(velocity); if (wantDebug) { - qDebug() << " new AACube:" << getAACube(); + qDebug() << " new AACube:" << getMaximumAACube(); } } } @@ -721,11 +721,10 @@ float EntityItem::getSize() const { return glm::length(_dimensions); } -// TODO: fix this to correctly handle rotation... since _dimensions is in entity space, -// if the entity has been rotated, then the distance to world.y=0 is not the same -// as the dimensions.y float EntityItem::getDistanceToBottomOfEntity() const { - glm::vec3 minimumPoint = getMinimumPoint(); + // the AABox from getAABox() is the true minimum bounding box for the entity + // so it's minimum y is indeed the distance to the bottom of the entity + glm::vec3 minimumPoint = getAABox().getMinimumPoint(); return minimumPoint.y; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c921f3f074..677e4e7824 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -200,7 +200,6 @@ public: glm::vec3 getMaximumPoint() const; AACube getMaximumAACube() const; AACube getMinimumAACube() const; - AACube getAACube() const { return getMaximumAACube(); } /// axis aligned bounding cube in domain scale units (0.0 - 1.0) AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0) static const QString DEFAULT_SCRIPT; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8223cb5e34..2ef307517f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -592,17 +592,34 @@ void EntityItemProperties::markAllChanged() { _glowLevelChanged = true; } - -// TODO: Add support for registration point -glm::vec3 EntityItemProperties::getMinimumPointMeters() const { - // This assumes the registration point is in the center, we need to update this when we really support - // registration point - return _position - (_dimensions / 2.0f); +AACube EntityItemProperties::getMaximumAACubeInTreeUnits() const { + AACube maxCube = getMaximumAACubeInMeters(); + maxCube.scale(1 / (float)TREE_SCALE); + return maxCube; } -// TODO: Add support for registration point -glm::vec3 EntityItemProperties::getMaximumPointMeters() const { - // This assumes the registration point is in the center, we need to update this when we really support - // registration point - return _position + (_dimensions / 2.0f); +/// The maximum bounding cube for the entity, independent of it's rotation. +/// This accounts for the registration point (upon which rotation occurs around). +/// +AACube EntityItemProperties::getMaximumAACubeInMeters() const { + // * we know that the position is the center of rotation + glm::vec3 centerOfRotation = _position; // also where _registration point is + + // * we know that the registration point is the center of rotation + // * we can calculate the length of the furthest extent from the registration point + // as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint) + glm::vec3 registrationPoint = (_dimensions * _registrationPoint); + glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint)); + glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder); + + // * we know that if you rotate in any direction you would create a sphere + // that has a radius of the length of furthest extent from registration point + float radius = glm::length(furthestExtentFromRegistration); + + // * we know that the minimum bounding cube of this maximum possible sphere is + // (center - radius) to (center + radius) + glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius); + float diameter = radius * 2.0f; + + return AACube(minimumCorner, diameter); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index c8ad2fe471..a52a75e071 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -95,16 +95,8 @@ public: /// used by EntityScriptingInterface to return EntityItemProperties for unknown models void setIsUnknownID() { _id = UNKNOWN_ENTITY_ID; _idSet = true; } - glm::vec3 getMinimumPointMeters() const; - glm::vec3 getMaximumPointMeters() const; - AACube getAACubeMeters() const { return AACube(getMinimumPointMeters(), getMaxDimension()); } /// AACube in meter units - - glm::vec3 getMinimumPointTreeUnits() const { return getMinimumPointMeters() / (float)TREE_SCALE; } - glm::vec3 getMaximumPointTreeUnits() const { return getMaximumPointMeters() / (float)TREE_SCALE; } - /// AACube in domain scale units (0.0 - 1.0) - AACube getAACubeTreeUnits() const { - return AACube(getMinimumPointMeters() / (float)TREE_SCALE, getMaxDimension() / (float)TREE_SCALE); - } + AACube getMaximumAACubeInTreeUnits() const; + AACube getMaximumAACubeInMeters() const; void debugDump() const; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 4380171df2..e2a22bfec3 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -652,9 +652,9 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT entitiesToDelete << thisEntity->getEntityItemID(); entitiesBecomingStatic << thisEntity; } else { - AACube oldCube = thisEntity->getAACube(); + AACube oldCube = thisEntity->getMaximumAACube(); thisEntity->update(now); - AACube newCube = thisEntity->getAACube(); + AACube newCube = thisEntity->getMaximumAACube(); // check to see if this movement has sent the entity outside of the domain. AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index e5987bbbc2..6c54dbe9b1 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -296,7 +296,12 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } if (includeThisEntity && params.viewFrustum) { - AACube entityCube = entity->getAACube(); + + // we want to use the maximum possible box for this, so that we don't have to worry about the nuance of + // simulation changing what's visible. consider the case where the entity contains an angular velocity + // the entity may not be in view and then in view a frame later, let the client side handle it's view + // frustum culling on rendering. + AACube entityCube = entity->getMaximumAACube(); entityCube.scale(TREE_SCALE); if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) { includeThisEntity = false; // out of view, don't include it @@ -405,19 +410,31 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } bool EntityTreeElement::containsEntityBounds(const EntityItem* entity) const { - return containsBounds(entity->getMinimumPoint(), entity->getMaximumPoint()); + // Here we have a choice to make, do we want to "tight fit" the actual minimum for the + // entity into the the element, or do we want to use the entities "relaxed" bounds + // which can handle all potential rotations? + // the getMaximumAACube is the relaxed form. + return containsBounds(entity->getMaximumAACube()); } bool EntityTreeElement::bestFitEntityBounds(const EntityItem* entity) const { - return bestFitBounds(entity->getMinimumPoint(), entity->getMaximumPoint()); + // Here we have a choice to make, do we want to "tight fit" the actual minimum for the + // entity into the the element, or do we want to use the entities "relaxed" bounds + // which can handle all potential rotations? + // the getMaximumAACube is the relaxed form. + return bestFitBounds(entity->getMaximumAACube()); } bool EntityTreeElement::containsBounds(const EntityItemProperties& properties) const { - return containsBounds(properties.getMinimumPointTreeUnits(), properties.getMaximumPointTreeUnits()); + // TODO: this needs to be updated to have the similar behavior support for registration point and rotation + // as EntityItem does + return containsBounds(properties.getMaximumAACubeInTreeUnits()); } bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) const { - return bestFitBounds(properties.getMinimumPointTreeUnits(), properties.getMaximumPointTreeUnits()); + // TODO: this needs to be updated to have the similar behavior support for registration point and rotation + // as EntityItem does + return bestFitBounds(properties.getMaximumAACubeInTreeUnits()); } bool EntityTreeElement::containsBounds(const AACube& bounds) const { @@ -477,76 +494,36 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con while(entityItr != entityEnd) { EntityItem* entity = (*entityItr); - AACube entityCube = entity->getAACube(); + AABox entityBox = entity->getAABox(); float localDistance; BoxFace localFace; // if the ray doesn't intersect with our cube, we can stop searching! - if (entityCube.findRayIntersection(origin, direction, localDistance, localFace)) { - const FBXGeometry* fbxGeometry = _myTree->getGeometryForEntity(entity); - if (fbxGeometry && fbxGeometry->meshExtents.isValid()) { - Extents extents = fbxGeometry->meshExtents; + if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) { - // NOTE: If the entity has a bad mesh, then extents will be 0,0,0 & 0,0,0 - if (extents.minimum == extents.maximum && extents.minimum == glm::vec3(0,0,0)) { - extents.maximum = glm::vec3(1.0f,1.0f,1.0f); // in this case we will simulate the unit cube + + // extents is the entity relative, scaled, centered extents of the entity + glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 dimensions = entity->getDimensions(); + + AABox entityFrameBox(glm::vec3(0.0f,0.0f,0.0f), dimensions); + + glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); + glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); + + // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame + // and testing intersection there. + if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { + if (localDistance < distance) { + distance = localDistance; + face = localFace; + *intersectedObject = (void*)entity; + somethingIntersected = true; } - - // NOTE: these extents are entity space, so we need to scale and center them accordingly - // size is our "target size in world space" - // we need to set our entity scale so that the extents of the mesh, fit in a cube that size... - float maxDimension = glm::distance(extents.maximum, extents.minimum); - float scale = entity->getSize() / maxDimension; - - glm::vec3 halfDimensions = (extents.maximum - extents.minimum) * 0.5f; - glm::vec3 offset = -extents.minimum - halfDimensions; - - extents.minimum += offset; - extents.maximum += offset; - - extents.minimum *= scale; - extents.maximum *= scale; - - Extents rotatedExtents = extents; - - rotatedExtents.rotate(entity->getRotation()); - - rotatedExtents.minimum += entity->getPosition(); - rotatedExtents.maximum += entity->getPosition(); - - - AABox rotatedExtentsBox(rotatedExtents.minimum, (rotatedExtents.maximum - rotatedExtents.minimum)); - - // if it's in our AABOX for our rotated extents, then check to see if it's in our non-AABox - if (rotatedExtentsBox.findRayIntersection(origin, direction, localDistance, localFace)) { - - // extents is the entity relative, scaled, centered extents of the entity - glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); - glm::mat4 translation = glm::translate(entity->getPosition()); - glm::mat4 entityToWorldMatrix = translation * rotation; - glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); - - AABox entityFrameBox(extents.minimum, (extents.maximum - extents.minimum)); - - glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); - glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); - - // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame - // and testing intersection there. - if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { - if (localDistance < distance) { - distance = localDistance; - face = localFace; - *intersectedObject = (void*)entity; - somethingIntersected = true; - } - } - } - } else if (localDistance < distance) { - distance = localDistance; - face = localFace; - *intersectedObject = (void*)entity; - somethingIntersected = true; } } diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 28fa8f4040..aa56c1f68d 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -36,7 +36,11 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, // caller must have verified existence of containingElement and oldEntity assert(_containingElement && _existingEntity); - _oldEntityCube = _existingEntity->getAACube(); + // Here we have a choice to make, do we want to "tight fit" the actual minimum for the + // entity into the the element, or do we want to use the entities "relaxed" bounds + // which can handle all potential rotations? + // the getMaximumAACube is the relaxed form. + _oldEntityCube = _existingEntity->getMaximumAACube(); _oldEntityBox = _oldEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds // If the new properties has position OR dimension changes, but not both, we need to @@ -71,7 +75,7 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, _newEntityCube = _oldEntityCube; _dontMove = true; } else { - _newEntityCube = _properties.getAACubeTreeUnits(); + _newEntityCube = _properties.getMaximumAACubeInTreeUnits(); _removeOld = true; // our properties are going to move us, so remember this for later processing } From 77dff698058f4b7a621c0d1ea4c209306caa3c43 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 11 Sep 2014 17:03:01 -0700 Subject: [PATCH 28/38] fix ray picking to work with registation points --- libraries/entities/src/EntityTreeElement.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 6c54dbe9b1..681d615f44 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -501,7 +501,6 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // if the ray doesn't intersect with our cube, we can stop searching! if (entityBox.findRayIntersection(origin, direction, localDistance, localFace)) { - // extents is the entity relative, scaled, centered extents of the entity glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); glm::mat4 translation = glm::translate(entity->getPosition()); @@ -509,8 +508,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); glm::vec3 dimensions = entity->getDimensions(); + glm::vec3 registrationPoint = entity->getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint); - AABox entityFrameBox(glm::vec3(0.0f,0.0f,0.0f), dimensions); + AABox entityFrameBox(corner, dimensions); glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f)); glm::vec3 entityFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)); From 54ef5d4698f6043e7c408cee5e2b962e80d32da3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 07:45:33 -0700 Subject: [PATCH 29/38] fixed bugs in MovingEntitiesOperator, improved getDistanceToBottomOfEntity, isRestingOnSurface --- libraries/entities/src/EntityItem.cpp | 70 +++++++---- libraries/entities/src/EntityItem.h | 2 - libraries/entities/src/EntityTree.cpp | 1 + libraries/entities/src/EntityTreeElement.cpp | 12 -- .../entities/src/MovingEntitiesOperator.cpp | 114 ++++++++++++++++-- .../entities/src/MovingEntitiesOperator.h | 5 +- .../entities/src/UpdateEntityOperator.cpp | 16 ++- libraries/entities/src/UpdateEntityOperator.h | 2 + 8 files changed, 176 insertions(+), 46 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 494be2ebbc..dc5b563b8a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -29,7 +29,7 @@ const float EntityItem::DEFAULT_MASS = 1.0f; const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL; const float EntityItem::DEFAULT_DAMPING = 0.5f; const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0); -const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 10000.0f) / (float)TREE_SCALE; // really small +const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second const glm::vec3 EntityItem::DEFAULT_VELOCITY = EntityItem::NO_VELOCITY; const glm::vec3 EntityItem::NO_GRAVITY = glm::vec3(0, 0, 0); const glm::vec3 EntityItem::REGULAR_GRAVITY = glm::vec3(0, (-9.8f / TREE_SCALE), 0); @@ -499,23 +499,57 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s } } +// TODO: we probably want to change this to make "down" be the direction of the entity's gravity vector +// for now, this is always true DOWN even if entity has non-down gravity. +// TODO: the old code had "&& _velocity.y >= -EPSILON && _velocity.y <= EPSILON" --- what was I thinking? bool EntityItem::isRestingOnSurface() const { - // TODO: change this to support registration point + glm::vec3 downwardVelocity = glm::vec3(0.0f, _velocity.y, 0.0f); + return _position.y <= getDistanceToBottomOfEntity() - && _velocity.y >= -EPSILON && _velocity.y <= EPSILON + && (glm::length(downwardVelocity) <= EPSILON_VELOCITY_LENGTH) && _gravity.y < 0.0f; } void EntityItem::update(const quint64& updateTime) { - bool wantDebug = false; + bool wantDebug = true; float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND); if (wantDebug) { qDebug() << "********** EntityItem::update()"; + qDebug() << " entity ID=" << getEntityItemID(); qDebug() << " updateTime=" << updateTime; qDebug() << " _lastUpdated=" << _lastUpdated; qDebug() << " timeElapsed=" << timeElapsed; + qDebug() << " hasVelocity=" << hasVelocity(); + qDebug() << " hasGravity=" << hasGravity(); + qDebug() << " isRestingOnSurface=" << isRestingOnSurface(); + qDebug() << " hasAngularVelocity=" << hasAngularVelocity(); + qDebug() << " getAngularVelocity=" << getAngularVelocity(); + qDebug() << " isMortal=" << isMortal(); + qDebug() << " getAge()=" << getAge(); + qDebug() << " getLifetime()=" << getLifetime(); + + + if (hasVelocity() || (hasGravity() && !isRestingOnSurface())) { + qDebug() << " MOVING...="; + qDebug() << " hasVelocity=" << hasVelocity(); + qDebug() << " hasGravity=" << hasGravity(); + qDebug() << " isRestingOnSurface=" << isRestingOnSurface(); + qDebug() << " hasAngularVelocity=" << hasAngularVelocity(); + qDebug() << " getAngularVelocity=" << getAngularVelocity(); + } + if (hasAngularVelocity()) { + qDebug() << " CHANGING...="; + qDebug() << " hasAngularVelocity=" << hasAngularVelocity(); + qDebug() << " getAngularVelocity=" << getAngularVelocity(); + } + if (isMortal()) { + qDebug() << " MORTAL...="; + qDebug() << " isMortal=" << isMortal(); + qDebug() << " getAge()=" << getAge(); + qDebug() << " getLifetime()=" << getLifetime(); + } } _lastUpdated = updateTime; @@ -562,7 +596,8 @@ void EntityItem::update(const quint64& updateTime) { qDebug() << " old AACube:" << getMaximumAACube(); qDebug() << " old position:" << position; qDebug() << " old velocity:" << velocity; - qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity(); + qDebug() << " old getAABox:" << getAABox(); + qDebug() << " getDistanceToBottomOfEntity():" << getDistanceToBottomOfEntity() * (float)TREE_SCALE << " in meters"; qDebug() << " newPosition:" << newPosition; qDebug() << " glm::distance(newPosition, position):" << glm::distance(newPosition, position); } @@ -604,21 +639,23 @@ void EntityItem::update(const quint64& updateTime) { if (wantDebug) { qDebug() << " velocity AFTER dampingResistance:" << velocity; + qDebug() << " glm::length(velocity):" << glm::length(velocity); + qDebug() << " EPSILON_VELOCITY_LENGTH:" << EPSILON_VELOCITY_LENGTH; } // round velocity to zero if it's close enough... if (glm::length(velocity) <= EPSILON_VELOCITY_LENGTH) { velocity = NO_VELOCITY; } + + setPosition(position); + setVelocity(velocity); if (wantDebug) { qDebug() << " new position:" << position; qDebug() << " new velocity:" << velocity; - } - setPosition(position); - setVelocity(velocity); - if (wantDebug) { qDebug() << " new AACube:" << getMaximumAACube(); + qDebug() << " old getAABox:" << getAABox(); } } } @@ -722,21 +759,8 @@ float EntityItem::getSize() const { } float EntityItem::getDistanceToBottomOfEntity() const { - // the AABox from getAABox() is the true minimum bounding box for the entity - // so it's minimum y is indeed the distance to the bottom of the entity glm::vec3 minimumPoint = getAABox().getMinimumPoint(); - return minimumPoint.y; -} - -// TODO: doesn't this need to handle rotation? -glm::vec3 EntityItem::getMinimumPoint() const { - return _position - (_dimensions * _registrationPoint); -} - -// TODO: doesn't this need to handle rotation? -glm::vec3 EntityItem::getMaximumPoint() const { - glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; - return _position + (_dimensions * registrationRemainder); + return getPosition().y - minimumPoint.y; } // TODO: doesn't this need to handle rotation? diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 677e4e7824..d82b254e8a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -196,8 +196,6 @@ public: // position, size, and bounds related helpers float getSize() const; /// get maximum dimension in domain scale units (0.0 - 1.0) - glm::vec3 getMinimumPoint() const; - glm::vec3 getMaximumPoint() const; AACube getMaximumAACube() const; AACube getMinimumAACube() const; AABox getAABox() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index e2a22bfec3..8cec19eddd 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -659,6 +659,7 @@ void EntityTree::updateMovingEntities(quint64 now, QSet& entitiesT // check to see if this movement has sent the entity outside of the domain. AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f); if (!domainBounds.touches(newCube)) { + qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds."; entitiesToDelete << thisEntity->getEntityItemID(); entitiesBecomingStatic << thisEntity; } else { diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 681d615f44..a58dd9065f 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -410,30 +410,18 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData } bool EntityTreeElement::containsEntityBounds(const EntityItem* entity) const { - // Here we have a choice to make, do we want to "tight fit" the actual minimum for the - // entity into the the element, or do we want to use the entities "relaxed" bounds - // which can handle all potential rotations? - // the getMaximumAACube is the relaxed form. return containsBounds(entity->getMaximumAACube()); } bool EntityTreeElement::bestFitEntityBounds(const EntityItem* entity) const { - // Here we have a choice to make, do we want to "tight fit" the actual minimum for the - // entity into the the element, or do we want to use the entities "relaxed" bounds - // which can handle all potential rotations? - // the getMaximumAACube is the relaxed form. return bestFitBounds(entity->getMaximumAACube()); } bool EntityTreeElement::containsBounds(const EntityItemProperties& properties) const { - // TODO: this needs to be updated to have the similar behavior support for registration point and rotation - // as EntityItem does return containsBounds(properties.getMaximumAACubeInTreeUnits()); } bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) const { - // TODO: this needs to be updated to have the similar behavior support for registration point and rotation - // as EntityItem does return bestFitBounds(properties.getMaximumAACubeInTreeUnits()); } diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp index d6ccb1aad4..e6b48da232 100644 --- a/libraries/entities/src/MovingEntitiesOperator.cpp +++ b/libraries/entities/src/MovingEntitiesOperator.cpp @@ -20,21 +20,53 @@ MovingEntitiesOperator::MovingEntitiesOperator(EntityTree* tree) : _changeTime(usecTimestampNow()), _foundOldCount(0), _foundNewCount(0), - _lookingCount(0) + _lookingCount(0), + _wantDebug(false) { } MovingEntitiesOperator::~MovingEntitiesOperator() { + if (_wantDebug) { + bool stopExecution = false; + qDebug() << "MovingEntitiesOperator::~MovingEntitiesOperator() -----------------------------"; + qDebug() << " _lookingCount:" << _lookingCount; + qDebug() << " _foundOldCount:" << _foundOldCount; + qDebug() << " _foundNewCount:" << _foundNewCount; + if (_foundOldCount < _lookingCount) { + qDebug() << " FAILURE: **** _foundOldCount < _lookingCount ******"; + stopExecution = true; + } + if (_foundNewCount < _lookingCount) { + qDebug() << " FAILURE: **** _foundNewCount < _lookingCount ******"; + stopExecution = true; + } + qDebug() << "--------------------------------------------------------------------------"; + if(stopExecution) { + debug(); + assert(false); + } + } } void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube) { EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID()); - AABox newBox = newCube.clamp(0.0f, 1.0f); + AABox newCubeClamped = newCube.clamp(0.0f, 1.0f); + AABox oldCubeClamped = oldCube.clamp(0.0f, 1.0f); + + if (_wantDebug) { + qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------"; + qDebug() << " oldCube:" << oldCube; + qDebug() << " newCube:" << newCube; + qDebug() << " oldCubeClamped:" << oldCubeClamped; + qDebug() << " newCubeClamped:" << newCubeClamped; + qDebug() << " oldContainingElement:" << oldContainingElement->getAACube(); + qDebug() << " oldContainingElement->bestFitBounds(newCubeClamped):" << oldContainingElement->bestFitBounds(newCubeClamped); + } // If the original containing element is the best fit for the requested newCube locations then // we don't actually need to add the entity for moving and we can short circuit all this work - if (!oldContainingElement->bestFitBounds(newBox)) { + if (!oldContainingElement->bestFitBounds(newCubeClamped)) { // check our tree, to determine if this entity is known EntityToMoveDetails details; details.oldContainingElement = oldContainingElement; @@ -44,9 +76,29 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACub details.newFound = false; details.oldCube = oldCube; details.newCube = newCube; - details.newBox = newBox; + details.oldCubeClamped = oldCubeClamped; + details.newCubeClamped = newCubeClamped; _entitiesToMove << details; _lookingCount++; + + if (_wantDebug) { + qDebug() << "MovingEntitiesOperator::addEntityToMoveList() -----------------------------"; + qDebug() << " details.entity:" << details.entity->getEntityItemID(); + qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube; + qDebug() << " details.oldCube:" << details.oldCube; + qDebug() << " details.newCube:" << details.newCube; + qDebug() << " details.newCubeClamped:" << details.newCubeClamped; + qDebug() << " _lookingCount:" << _lookingCount; + qDebug() << "--------------------------------------------------------------------------"; + } + } else { + if (_wantDebug) { + qDebug() << " oldContainingElement->bestFitBounds(newCubeClamped) IS BEST FIT... NOTHING TO DO"; + } + } + + if (_wantDebug) { + qDebug() << "--------------------------------------------------------------------------"; } } @@ -58,11 +110,29 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) { // check the bounds if (_entitiesToMove.size() > 0) { AACube elementCube = element->getAACube(); + int detailIndex = 0; foreach(const EntityToMoveDetails& details, _entitiesToMove) { - if (elementCube.contains(details.oldCube) || elementCube.contains(details.newCube)) { + + if (_wantDebug) { + qDebug() << "MovingEntitiesOperator::shouldRecurseSubTree() details["<< detailIndex <<"]-----------------------------"; + qDebug() << " element:" << element->getAACube(); + qDebug() << " details.entity:" << details.entity->getEntityItemID(); + qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube; + qDebug() << " details.oldCube:" << details.oldCube; + qDebug() << " details.newCube:" << details.newCube; + qDebug() << " details.newCubeClamped:" << details.newCubeClamped; + qDebug() << " elementCube.contains(details.oldCube)" << elementCube.contains(details.oldCube); + qDebug() << " elementCube.contains(details.newCube)" << elementCube.contains(details.newCube); + qDebug() << " elementCube.contains(details.oldCubeClamped)" << elementCube.contains(details.oldCubeClamped); + qDebug() << " elementCube.contains(details.newCubeClamped)" << elementCube.contains(details.newCubeClamped); + qDebug() << "--------------------------------------------------------------------------"; + } + + if (elementCube.contains(details.oldCubeClamped) || elementCube.contains(details.newCubeClamped)) { containsEntity = true; break; // if it contains at least one, we're good to go } + detailIndex++; } } return containsEntity; @@ -87,13 +157,36 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { if (keepSearching && shouldRecurseSubTree(element)) { // check against each of our search entities + int detailIndex = 0; foreach(const EntityToMoveDetails& details, _entitiesToMove) { + + if (_wantDebug) { + qDebug() << "MovingEntitiesOperator::preRecursion() details["<< detailIndex <<"]-----------------------------"; + qDebug() << " entityTreeElement:" << entityTreeElement->getAACube(); + qDebug() << " entityTreeElement->bestFitBounds(details.newCube):" << entityTreeElement->bestFitBounds(details.newCube); + qDebug() << " details.entity:" << details.entity->getEntityItemID(); + qDebug() << " details.oldContainingElementCube:" << details.oldContainingElementCube; + qDebug() << " entityTreeElement:" << entityTreeElement; + qDebug() << " details.oldCube:" << details.oldCube; + qDebug() << " details.newCube:" << details.newCube; + qDebug() << " details.newCubeClamped:" << details.newCubeClamped; + qDebug() << " _lookingCount:" << _lookingCount; + qDebug() << " _foundOldCount:" << _foundOldCount; + qDebug() << "--------------------------------------------------------------------------"; + } + // If this is one of the old elements we're looking for, then ask it to remove the old entity if (!details.oldFound && entityTreeElement == details.oldContainingElement) { entityTreeElement->removeEntityItem(details.entity); _foundOldCount++; //details.oldFound = true; // TODO: would be nice to add this optimization + if (_wantDebug) { + qDebug() << "MovingEntitiesOperator::preRecursion() -----------------------------"; + qDebug() << " FOUND OLD - REMOVING"; + qDebug() << " entityTreeElement == details.oldContainingElement"; + qDebug() << "--------------------------------------------------------------------------"; + } } // If this element is the best fit for the new bounds of this entity then add the entity to the element @@ -103,7 +196,14 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { _tree->setContainingElement(entityItemID, entityTreeElement); _foundNewCount++; //details.newFound = true; // TODO: would be nice to add this optimization + if (_wantDebug) { + qDebug() << "MovingEntitiesOperator::preRecursion() -----------------------------"; + qDebug() << " FOUND NEW - ADDING"; + qDebug() << " entityTreeElement->bestFitBounds(details.newCube)"; + qDebug() << "--------------------------------------------------------------------------"; + } } + detailIndex++; } // if we haven't found all of our search for entities, then keep looking keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount); @@ -163,9 +263,9 @@ OctreeElement* MovingEntitiesOperator::possiblyCreateChildAt(OctreeElement* elem foreach(const EntityToMoveDetails& details, _entitiesToMove) { // if the scale of our desired cube is smaller than our children, then consider making a child - if (details.newBox.getLargestDimension() <= childElementScale) { + if (details.newCubeClamped.getLargestDimension() <= childElementScale) { - int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newBox); + int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newCubeClamped); // If the childIndex we were asked if we wanted to create contains this newCube, // then we will create this branch and continue. We can exit this loop immediately diff --git a/libraries/entities/src/MovingEntitiesOperator.h b/libraries/entities/src/MovingEntitiesOperator.h index 047cc0c52b..fbec898cec 100644 --- a/libraries/entities/src/MovingEntitiesOperator.h +++ b/libraries/entities/src/MovingEntitiesOperator.h @@ -17,7 +17,8 @@ public: EntityItem* entity; AACube oldCube; AACube newCube; - AABox newBox; + AABox oldCubeClamped; + AABox newCubeClamped; EntityTreeElement* oldContainingElement; AACube oldContainingElementCube; bool oldFound; @@ -50,6 +51,8 @@ private: int _foundNewCount; int _lookingCount; bool shouldRecurseSubTree(OctreeElement* element); + + bool _wantDebug; }; #endif // hifi_MovingEntitiesOperator_h diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index aa56c1f68d..284d8e9e24 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -31,7 +31,8 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, _dontMove(false), // assume we'll be moving _changeTime(usecTimestampNow()), _oldEntityCube(), - _newEntityCube() + _newEntityCube(), + _wantDebug(false) { // caller must have verified existence of containingElement and oldEntity assert(_containingElement && _existingEntity); @@ -80,6 +81,19 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, } _newEntityBox = _newEntityCube.clamp(0.0f, 1.0f); // clamp to domain bounds + + + if (_wantDebug) { + qDebug() << "UpdateEntityOperator::UpdateEntityOperator() -----------------------------"; + qDebug() << " _entityItemID:" << _entityItemID; + qDebug() << " _containingElementCube:" << _containingElementCube; + qDebug() << " _oldEntityCube:" << _oldEntityCube; + qDebug() << " _oldEntityBox:" << _oldEntityBox; + qDebug() << " _newEntityCube:" << _newEntityCube; + qDebug() << " _newEntityBox:" << _newEntityBox; + qDebug() << "--------------------------------------------------------------------------"; + } + } diff --git a/libraries/entities/src/UpdateEntityOperator.h b/libraries/entities/src/UpdateEntityOperator.h index 0aef5927b2..8d40ddfd57 100644 --- a/libraries/entities/src/UpdateEntityOperator.h +++ b/libraries/entities/src/UpdateEntityOperator.h @@ -42,6 +42,8 @@ private: bool subTreeContainsOldEntity(OctreeElement* element); bool subTreeContainsNewEntity(OctreeElement* element); + + bool _wantDebug; }; #endif // hifi_UpdateEntityOperator_h From 4bce7f8c0b5a4bc574706af71baeec0ff37cd782 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 08:14:28 -0700 Subject: [PATCH 30/38] removed debug --- 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 dc5b563b8a..ac405feebf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -511,7 +511,7 @@ bool EntityItem::isRestingOnSurface() const { } void EntityItem::update(const quint64& updateTime) { - bool wantDebug = true; + bool wantDebug = false; float timeElapsed = (float)(updateTime - _lastUpdated) / (float)(USECS_PER_SECOND); From 67f6f4c8525eeefcfc16f2cfaf775c0c268400fa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 08:19:46 -0700 Subject: [PATCH 31/38] removed dead code --- interface/src/entities/EntityTreeRenderer.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 56b23a9df9..86aa4b7622 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -253,19 +253,6 @@ void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* arg glutWireCube(1.0f); glPopMatrix(); glPopMatrix(); - - /* - glPushMatrix(); - // draw the model relative bounding box - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z); - glColor3f(0.0f, 1.0f, 0.0f); - glutWireCube(1.0); - - glPopMatrix(); - */ - } } From bc29848476cc4e855d6380909a699542f4984600 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 08:21:03 -0700 Subject: [PATCH 32/38] removed extra lines --- interface/src/entities/RenderableBoxEntityItem.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/entities/RenderableBoxEntityItem.cpp b/interface/src/entities/RenderableBoxEntityItem.cpp index f90bc6cccc..17cfbdcdaf 100644 --- a/interface/src/entities/RenderableBoxEntityItem.cpp +++ b/interface/src/entities/RenderableBoxEntityItem.cpp @@ -46,8 +46,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - glPushMatrix(); glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); @@ -92,8 +90,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - glPushMatrix(); glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); From baaf01683e110a99a2dd98e9fcc8feeadc693f4f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 08:23:13 -0700 Subject: [PATCH 33/38] removed some verbose comments --- libraries/entities/src/AddEntityOperator.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libraries/entities/src/AddEntityOperator.cpp b/libraries/entities/src/AddEntityOperator.cpp index d70aad1e1d..34ccc75030 100644 --- a/libraries/entities/src/AddEntityOperator.cpp +++ b/libraries/entities/src/AddEntityOperator.cpp @@ -25,12 +25,6 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree, { // caller must have verified existence of newEntity assert(_newEntity); - - - // Here we have a choice to make, do we want to "tight fit" the actual minimum for the - // entity into the the element, or do we want to use the entities "relaxed" bounds - // which can handle all potential rotations? - // the getMaximumAACube is the relaxed form. _newEntityBox = _newEntity->getMaximumAACube().clamp(0.0f, 1.0f); } From 16f9d60df791c92014cf9c8500e5eca6dbb102ae Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 08:34:02 -0700 Subject: [PATCH 34/38] upgrade butterflies to use dimensions --- examples/butterflies.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/butterflies.js b/examples/butterflies.js index 1f612ed4bf..6b15680fa0 100644 --- a/examples/butterflies.js +++ b/examples/butterflies.js @@ -37,6 +37,7 @@ function vInterpolate(a, b, fraction) { var startTimeInSeconds = new Date().getTime() / 1000; +var NATURAL_SIZE_OF_BUTTERFLY = { x: 9.512, y: 4.427, z: 1.169 }; var lifeTime = 600; // lifetime of the butterflies in seconds var range = 1.0; // Over what distance in meters do you want the flock to fly around var frame = 0; @@ -78,7 +79,13 @@ function addButterfly() { var color = { red: 100, green: 100, blue: 100 }; var size = 0; + var minSize = 0.06; + var randomSize = 0.2; + var maxSize = minSize + randomSize; + size = 0.06 + Math.random() * 0.2; + + var dimensions = Vec3.multiply(NATURAL_SIZE_OF_BUTTERFLY, (size / maxSize)); flockPosition = Vec3.sum(MyAvatar.position,Vec3.sum( Vec3.multiply(Quat.getFront(MyAvatar.orientation), DISTANCE_ABOVE_ME), @@ -91,7 +98,7 @@ function addButterfly() { velocity: { x: 0, y: 0.0, z: 0 }, gravity: { x: 0, y: 1.0, z: 0 }, damping: 0.1, - radius : size, + dimensions: dimensions, color: color, rotation: rotation, animationURL: "http://business.ozblog.me/objects/butterfly/newButterfly2.fbx", @@ -203,7 +210,8 @@ function updateButterflies(deltaTime) { // If we are near the target, we should get a new target - if (Vec3.length(Vec3.subtract(properties.position, butterflies[i].targetPosition)) < (properties.radius / 1.0)) { + var halfLargestDimension = Vec3.length(properties.dimensions) / 2.0; + if (Vec3.length(Vec3.subtract(properties.position, butterflies[i].targetPosition)) < (halfLargestDimension)) { butterflies[i].moving = false; } @@ -214,7 +222,7 @@ function updateButterflies(deltaTime) { } // Use a cosine wave offset to make it look like its flapping. - var offset = Math.cos(nowTimeInSeconds * BUTTERFLY_FLAP_SPEED) * (properties.radius); + var offset = Math.cos(nowTimeInSeconds * BUTTERFLY_FLAP_SPEED) * (halfLargestDimension); properties.position.y = properties.position.y + (offset - butterflies[i].previousFlapOffset); // Change position relative to previous offset. butterflies[i].previousFlapOffset = offset; From 25d051090a8d514d62bf32d9b9d7ec2c60472940 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 08:48:40 -0700 Subject: [PATCH 35/38] swap order of local vs server changes in entity scripting to improve potential conflicts --- .../entities/src/EntityScriptingInterface.cpp | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 3c34a6f6c7..8113168655 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -31,9 +31,6 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro EntityItemID id(NEW_ENTITY, creatorTokenID, false ); - // queue the packet - queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties); - // If we have a local entity tree set, then also update it. if (_entityTree) { _entityTree->lockForWrite(); @@ -41,6 +38,9 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro _entityTree->unlock(); } + // queue the packet + queueEntityMessage(PacketTypeEntityAddOrEdit, id, properties); + return id; } @@ -97,13 +97,10 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E // if the entity is unknown, attempt to look it up if (!entityID.isKnownID) { actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID); - } - - // if at this point, we know the id, send the update to the entity server - if (actualID.id != UNKNOWN_ENTITY_ID) { - entityID.id = actualID.id; - entityID.isKnownID = true; - queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties); + if (actualID.id != UNKNOWN_ENTITY_ID) { + entityID.id = actualID.id; + entityID.isKnownID = true; + } } // If we have a local entity tree set, then also update it. We can do this even if we don't know @@ -113,6 +110,12 @@ EntityItemID EntityScriptingInterface::editEntity(EntityItemID entityID, const E _entityTree->updateEntity(entityID, properties); _entityTree->unlock(); } + + // if at this point, we know the id, send the update to the entity server + if (entityID.isKnownID) { + queueEntityMessage(PacketTypeEntityAddOrEdit, entityID, properties); + } + return entityID; } @@ -123,13 +126,10 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) { // if the entity is unknown, attempt to look it up if (!entityID.isKnownID) { actualID = EntityItemID::getIDfromCreatorTokenID(entityID.creatorTokenID); - } - - // if at this point, we know the id, send the update to the entity server - if (actualID.id != UNKNOWN_ENTITY_ID) { - entityID.id = actualID.id; - entityID.isKnownID = true; - getEntityPacketSender()->queueEraseEntityMessage(entityID); + if (actualID.id != UNKNOWN_ENTITY_ID) { + entityID.id = actualID.id; + entityID.isKnownID = true; + } } // If we have a local entity tree set, then also update it. @@ -138,6 +138,11 @@ void EntityScriptingInterface::deleteEntity(EntityItemID entityID) { _entityTree->deleteEntity(entityID); _entityTree->unlock(); } + + // if at this point, we know the id, send the update to the entity server + if (entityID.isKnownID) { + getEntityPacketSender()->queueEraseEntityMessage(entityID); + } } EntityItemID EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float radius) const { From e8c1cb7db80507b14d95718fd440765b4f2b7443 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 09:38:35 -0700 Subject: [PATCH 36/38] read old format files correctly --- interface/src/entities/EntityTreeRenderer.cpp | 19 +++++++++-- libraries/entities/src/EntityItem.cpp | 34 ++++++++++++++++++- libraries/entities/src/EntityItem.h | 5 --- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 86aa4b7622..095277d960 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -244,8 +244,6 @@ void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* arg glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); - - glPushMatrix(); glm::vec3 positionToCenter = center - position; glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); @@ -257,6 +255,8 @@ void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* arg } void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) { + bool wantDebug = false; + args->_elementsTouched++; // actually render it here... // we need to iterate the actual entityItems of the element @@ -288,6 +288,21 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) // TODO: some entity types (like lights) might want to be rendered even // when they are outside of the view frustum... float distance = distanceToCamera(entityBox.calcCenter(), *args->_viewFrustum); + + if (wantDebug) { + qDebug() << "------- renderElement() ----------"; + qDebug() << " type:" << EntityTypes::getEntityTypeName(entityItem->getType()); + if (entityItem->getType() == EntityTypes::Model) { + ModelEntityItem* modelEntity = static_cast(entityItem); + qDebug() << " url:" << modelEntity->getModelURL(); + } + qDebug() << " entityBox:" << entityBox; + qDebug() << " dimensions:" << entityItem->getDimensionsInMeters() << "in meters"; + qDebug() << " largestDimension:" << entityBox.getLargestDimension() << "in meters"; + qDebug() << " shouldRender:" << shouldRenderEntity(entityBox.getLargestDimension(), distance); + qDebug() << " in frustum:" << (args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE); + } + if (shouldRenderEntity(entityBox.getLargestDimension(), distance) && args->_viewFrustum->boxInFrustum(entityBox) != ViewFrustum::OUTSIDE) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ac405feebf..1406239f23 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -206,6 +206,11 @@ 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_MASS, appendValue, getMass()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, appendValue, getVelocity()); @@ -447,12 +452,25 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef dataAt += sizeof(fromBuffer); bytesRead += sizeof(fromBuffer); if (overwriteLocalData) { - setRadiusInMeters(fromBuffer); + setRadius(fromBuffer); } + + if (wantDebug) { + qDebug() << " readEntityDataFromBuffer() OLD FORMAT... found PROP_RADIUS"; + } + } } else { READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, _dimensions); + if (wantDebug) { + qDebug() << " readEntityDataFromBuffer() NEW FORMAT... look for PROP_DIMENSIONS"; + } } + + if (wantDebug) { + qDebug() << " readEntityDataFromBuffer() _dimensions:" << getDimensionsInMeters() << " in meters"; + } + READ_ENTITY_PROPERTY_QUAT(PROP_ROTATION, _rotation); READ_ENTITY_PROPERTY(PROP_MASS, float, _mass); READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, _velocity); @@ -465,6 +483,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, _angularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, _visible); + if (wantDebug) { + qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint; + qDebug() << " readEntityDataFromBuffer() _visible:" << _visible; + } + bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); } @@ -855,6 +878,15 @@ 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/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d82b254e8a..e689ec1b25 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -257,11 +257,6 @@ protected: /// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis void setRadius(float value); - /// set radius in meter units (0.0 - TREE_SCALE), this will also reset dimensions to be equal for each axis - void setRadiusInMeters(float value) { - float valueInTreeUnits = value / (float) TREE_SCALE; - setRadius(valueInTreeUnits); - } private: // TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends From 64e2033b30dfb69c3212f4e406a20e69e19271e4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 10:26:24 -0700 Subject: [PATCH 37/38] move getRadius to public for now --- libraries/entities/src/EntityItem.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e689ec1b25..0c5928ba93 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -224,6 +224,11 @@ public: bool isVisible() const { return _visible; } bool isInvisible() const { return !_visible; } + // TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends + // so they can be the only ones accessing this method. + float getRadius() const; + + protected: virtual void initFromEntityItemID(const EntityItemID& entityItemID); // maybe useful to allow subclasses to init @@ -258,12 +263,6 @@ protected: /// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis void setRadius(float value); -private: - // TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends - // so they can be the only ones accessing this method. - friend EntityTreeElement; - float getRadius() const; - }; From 45fc8423baf4f891c3b61a74e8bdbb15ace78291 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 12 Sep 2014 10:26:47 -0700 Subject: [PATCH 38/38] move getRadius to public for now --- libraries/entities/src/EntityItem.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0c5928ba93..a41d4523f9 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -224,8 +224,7 @@ public: bool isVisible() const { return _visible; } bool isInvisible() const { return !_visible; } - // TODO: We need to get rid of these users of getRadius()... but for now, we'll make them friends - // so they can be the only ones accessing this method. + // TODO: We need to get rid of these users of getRadius()... float getRadius() const;