From c449ba27a988bcbd3c230cb78fae07fb363d34d9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 3 Jul 2014 15:18:17 -0700 Subject: [PATCH] more virtual entity work --- libraries/entities/src/EntityItem.h | 5 +- libraries/entities/src/EntityTree.cpp | 74 ++++++++--------- libraries/entities/src/EntityTreeElement.cpp | 87 ++++++++++++++++---- libraries/entities/src/EntityTreeElement.h | 7 ++ libraries/shared/src/AABox.h | 5 ++ libraries/shared/src/AACube.h | 44 +++++----- 6 files changed, 148 insertions(+), 74 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index c4090eff2f..7a268e7754 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -124,14 +124,15 @@ public: glm::vec3 getMinimumPoint() const { return _position - glm::vec3(_radius, _radius, _radius); } glm::vec3 getMaximumPoint() const { return _position + glm::vec3(_radius, _radius, _radius); } - AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); } /// AACube in domain scale units (0.0 - 1.0) + AACube getAACube() const { return AACube(getMinimumPoint(), getMaxDimension()); } /// AACube in domain scale units (0.0 - 1.0) void debugDump() const; // properties of all entities EntityTypes::EntityType_t getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } float getRadius() const { return _radius; } - glm::vec3 getSize() const { return glm::vec3(_radius, _radius, _radius) * 2.0f; } + 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; } bool getShouldBeDeleted() const { return _shouldBeDeleted; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index eba6a06ca6..8ac0647b1d 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -242,20 +242,23 @@ EntityItem* EntityTree::getOrCreateEntityItem(const EntityItemID& entityID, cons class UpdateEntityOperator : public RecurseOctreeOperator { public: UpdateEntityOperator(EntityTree* tree, EntityTreeElement* containingElement, - EntityItem* oldEntity, const EntityItemProperties& properties); + EntityItem* existingEntity, const EntityItemProperties& properties); + virtual bool PreRecursion(OctreeElement* element); virtual bool PostRecursion(OctreeElement* element); virtual OctreeElement* PossiblyCreateChildAt(OctreeElement* element, int childIndex); private: EntityTree* _tree; - const EntityItem* _newEntity; - const EntityItem* _oldEntity; + const EntityItem* _existingEntity; EntityTreeElement* _containingElement; + EntityItemID _entityItemID; bool _foundOld; bool _foundNew; + bool _removeOld; quint64 _changeTime; - AABox _oldEntityCube; - AABox _newEntityCube; + + AACube _oldEntityCube; + AACube _newEntityCube; bool subTreeContainsOldEntity(OctreeElement* element); bool subTreeContainsNewEntity(OctreeElement* element); @@ -263,20 +266,21 @@ private: UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, EntityTreeElement* containingElement, - EntityItem* oldEntity, + EntityItem* existingEntity, const EntityItemProperties& properties) : _tree(tree), - _newEntity(NULL), - _oldEntity(oldEntity), + _existingEntity(existingEntity), _containingElement(containingElement), + _entityItemID(existingEntity->getEntityItemID()), _foundOld(false), _foundNew(false), + _removeOld(false), _changeTime(usecTimestampNow()) { // caller must have verified existence of containingElement and oldEntity - assert(_containingElement && _oldEntity); + assert(_containingElement && _existingEntity); - _oldEntityCube = _oldEntity->getAACube(); + _oldEntityCube = _existingEntity->getAACube(); // If our new properties don't have bounds details (no change to position, etc) or if this containing element would // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will @@ -285,34 +289,24 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, _foundOld = true; _newEntityCube = _oldEntityCube; } else { - _newEntityCube = _oldEntity->getAACube(); + _newEntityCube = properties.getAACube(); + _removeOld = true; // our properties are going to move us, so remember this for later processing } } // does this model tree element contain the old model bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) { - bool containsEntity = false; - - // If we don't have an old model, then we don't contain the model, otherwise - // check the bounds - if (_oldEntity) { - AACube elementCube = element->getAACube(); - AACube modelCube = _oldEntity->getAACube(); - containsEntity = elementCube.contains(modelCube); - } - return containsEntity; + return element->getAACube().contains(_oldEntityCube); } bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElement* element) { - AACube elementCube = element->getAACube(); - AACube modelCube = _newEntity.getAACube(); - return elementCube.contains(modelCube); + return element->getAACube().contains(_newEntityCube); } bool UpdateEntityOperator::PreRecursion(OctreeElement* element) { - EntityTreeElement* modelTreeElement = static_cast(element); + EntityTreeElement* entityTreeElement = static_cast(element); // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if @@ -331,19 +325,19 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) { // If this is the element we're looking for, then ask it to remove the old model // and we can stop searching. - if (modelTreeElement == _containingElement) { + if (entityTreeElement == _containingElement) { // If the containgElement IS NOT the best fit for the new model properties // then we need to remove it, and the updateEntity below will store it in the // correct element. - if (!_containingElement->bestFitEntityBounds(&_newEntity)) { - modelTreeElement->removeEntityWithEntityItemID(_newEntity.getEntityItemID()); + if (!_removeOld) { + entityTreeElement->removeEntityItem(_existingEntity); // NOTE: only removes the entity, doesn't delete it // If we haven't yet found the new location, then we need to // make sure to remove our model to element map, because for // now we're not in that map if (!_foundNew) { - _tree->setContainingElement(_newEntity.getEntityItemID(), NULL); + _tree->setContainingElement(_entityItemID, NULL); } } _foundOld = true; @@ -357,15 +351,19 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) { // model, then we need to keep searching. if (!_foundNew && subTreeContainsNewEntity(element)) { - // Note: updateEntity() will only operate on correctly found models and/or add them - // to the element if they SHOULD be stored there. - if (modelTreeElement->updateEntity(_newEntity)) { - //qDebug() << "UpdateEntityOperator::PreRecursion()... model was updated!"; - _foundNew = true; - // NOTE: don't change the keepSearching here, if it came in here - // false then we stay false, if it came in here true, then it - // means we're still searching for our old model and this branch - // contains our old model. In which case we want to keep searching. + // If this element is the best fit for the new entity properties, then add/or update it + if (entityTreeElement->bestFitBounds(_newEntityCube)) { + + if (entityTreeElement->addOrUpdateEntity(_existingEntity, properties)) { + + //qDebug() << "UpdateEntityOperator::PreRecursion()... model was updated!"; + _foundNew = true; + // NOTE: don't change the keepSearching here, if it came in here + // false then we stay false, if it came in here true, then it + // means we're still searching for our old model and this branch + // contains our old model. In which case we want to keep searching. + } + } } else { keepSearching = true; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 1acc5ddc33..f44609851c 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -190,6 +190,14 @@ bool EntityTreeElement::bestFitBounds(const EntityItemProperties& properties) co return bestFitBounds(properties.getMinimumPoint(), properties.getMaximumPoint()); } +bool EntityTreeElement::containsBounds(const AACube& bounds) const { + return containsBounds(bounds.getMinimumPoint(), bounds.getMaximumPoint()); +} + +bool EntityTreeElement::bestFitBounds(const AACube& bounds) const { + return bestFitBounds(bounds.getMinimumPoint(), bounds.getMaximumPoint()); +} + bool EntityTreeElement::containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const { glm::vec3 clampedMin = glm::clamp(minPoint, 0.0f, 1.0f); glm::vec3 clampedMax = glm::clamp(maxPoint, 0.0f, 1.0f); @@ -265,13 +273,13 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con while(entityItr != entityEnd) { EntityItem* entity = (*entityItr); - AACube entityCube = entity.getAACube(); + AACube entityCube = entity->getAACube(); 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); + const FBXGeometry* fbxGeometry = _myTree->getGeometryForEntity(*entity); if (fbxGeometry && fbxGeometry->meshExtents.isValid()) { Extents extents = fbxGeometry->meshExtents; @@ -284,7 +292,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // 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; + float scale = entity->getSize() / maxDimension; glm::vec3 halfDimensions = (extents.maximum - extents.minimum) * 0.5f; glm::vec3 offset = -extents.minimum - halfDimensions; @@ -297,10 +305,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con Extents rotatedExtents = extents; - calculateRotatedExtents(rotatedExtents, entity.getRotation()); + calculateRotatedExtents(rotatedExtents, entity->getRotation()); - rotatedExtents.minimum += entity.getPosition(); - rotatedExtents.maximum += entity.getPosition(); + rotatedExtents.minimum += entity->getPosition(); + rotatedExtents.maximum += entity->getPosition(); AABox rotatedExtentsBox(rotatedExtents.minimum, (rotatedExtents.maximum - rotatedExtents.minimum)); @@ -309,8 +317,8 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con 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 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 translation = glm::translate(entity->getPosition()); glm::mat4 entityToWorldMatrix = translation * rotation; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); @@ -348,9 +356,9 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad QList::iterator entityItr = _entityItems->begin(); QList::const_iterator entityEnd = _entityItems->end(); while(entityItr != entityEnd) { - EntityItem& entity = (*entityItr); - glm::vec3 entityCenter = entity.getPosition(); - float entityRadius = entity.getRadius(); + EntityItem* entity = (*entityItr); + glm::vec3 entityCenter = entity->getPosition(); + float entityRadius = entity->getRadius(); // don't penetrate yourself if (entityCenter == center && entityRadius == radius) { @@ -359,7 +367,7 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad if (findSphereSpherePenetration(center, radius, entityCenter, entityRadius, penetration)) { // return true on first valid entity penetration - *penetratedObject = (void*)(&entity); + *penetratedObject = (void*)(entity); return true; } ++entityItr; @@ -367,6 +375,41 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad return false; } + +// TODO... how do we handle older/newer with this interface? +bool EntityTreeElement::addOrUpdateEntity(EntityItem* entity, const EntityItemProperties& properties) { + const bool wantDebug = false; + if (wantDebug) { + EntityItemID entityItemID = entity->getEntityItemID(); + qDebug() << "EntityTreeElement::updateEntity(entity) entityID.id=" + << entityItemID.id << "creatorTokenID=" << entityItemID.creatorTokenID; + } + + // NOTE: this method must first lookup the entity by ID, hence it is O(N) + // and "entity is not found" is worst-case (full N) but maybe we don't care? + // (guaranteed that num entities per elemen is small?) + uint16_t numberOfEntities = _entityItems->size(); + for (uint16_t i = 0; i < numberOfEntities; i++) { + EntityItem* thisEntity = (*_entityItems)[i]; + if (thisEntity == entity) { + if (wantDebug) { + qDebug() << "found the entity"; + } + thisEntity->setProperties(properties); + markWithChangedTime(); + return true; + } + } + + // If we didn't find the entity here, then let's check to see if we should add it... + _entityItems->push_back(entity); + markWithChangedTime(); + // Since we're adding this item to this element, we need to let the tree know about it + _myTree->setContainingElement(entity->getEntityItemID(), this); + + return true; +} + // TODO: the old entity code has support for sittingPoints... need to determine how to handle this... // for local editors, the old updateModels(id, properties) had this code... // if (found) { @@ -375,6 +418,7 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad // thisModel.setSittingPoints(_myTree->getGeometryForModel(thisModel)->sittingPoints); // } // ... +#if 0 bool EntityTreeElement::updateEntity(const EntityItem& entity) { const bool wantDebug = false; if (wantDebug) { @@ -433,6 +477,7 @@ bool EntityTreeElement::updateEntity(const EntityItem& entity) { return false; } +#endif void EntityTreeElement::updateEntityItemID(FindAndUpdateEntityItemIDArgs* args) { bool wantDebug = false; @@ -483,7 +528,7 @@ const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const for (uint16_t i = 0; i < numberOfEntities; i++) { float distanceToEntity = glm::distance(position, (*_entityItems)[i]->getPosition()); if (distanceToEntity < closestEntityDistance) { - closestEntity = &(*_entityItems)[i]; + closestEntity = (*_entityItems)[i]; } } return closestEntity; @@ -492,7 +537,7 @@ const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const 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++) { - const EntityItem* entity = &(*_entityItems)[i]; + const EntityItem* entity = (*_entityItems)[i]; float distance = glm::length(entity->getPosition() - searchPosition); if (distance < searchRadius + entity->getRadius()) { foundEntities.push_back(entity); @@ -582,6 +627,20 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { return foundEntity; } +bool EntityTreeElement::removeEntityItem(const EntityItem* entity) { + bool foundEntity = false; + uint16_t numberOfEntities = _entityItems->size(); + for (uint16_t i = 0; i < numberOfEntities; i++) { + if ((*_entityItems)[i] == entity) { + foundEntity = true; + _entityItems->removeAt(i); + break; + } + } + return foundEntity; +} + + int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index bb9e0f1e36..ac65e912a4 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -121,6 +121,9 @@ public: void setTree(EntityTree* tree) { _myTree = tree; } bool updateEntity(const EntityItem& entity); + bool addOrUpdateEntity(EntityItem* entity, const EntityItemProperties& properties); + + void updateEntityItemID(FindAndUpdateEntityItemIDArgs* args); const EntityItem* getClosestEntity(glm::vec3 position) const; @@ -143,6 +146,7 @@ public: bool removeEntityWithID(uint32_t id); bool removeEntityWithEntityItemID(const EntityItemID& id); + bool removeEntityItem(const EntityItem* entity); bool containsEntityBounds(const EntityItem* entity) const; bool bestFitEntityBounds(const EntityItem* entity) const; @@ -150,6 +154,9 @@ public: bool containsBounds(const EntityItemProperties& properties) const; bool bestFitBounds(const EntityItemProperties& properties) const; + bool containsBounds(const AACube& bounds) const; + bool bestFitBounds(const AACube& bounds) const; + bool containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; bool bestFitBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 1568702965..8e9c34162b 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -42,6 +42,11 @@ public: glm::vec3 calcCenter() const; glm::vec3 calcTopFarLeft() const; glm::vec3 getVertex(BoxVertex vertex) const; + + const glm::vec3& getMinimumPoint() const { return _corner; } + glm::vec3 getMaximumPoint() const { return calcTopFarLeft(); } + + bool contains(const glm::vec3& point) const; bool contains(const AABox& otherBox) const; bool touches(const AABox& otherBox) const; diff --git a/libraries/shared/src/AACube.h b/libraries/shared/src/AACube.h index f805d4901e..c19bfa643f 100644 --- a/libraries/shared/src/AACube.h +++ b/libraries/shared/src/AACube.h @@ -28,27 +28,31 @@ public: AACube(); ~AACube() {}; - void setBox(const glm::vec3& corner, float scale); - glm::vec3 getVertexP(const glm::vec3& normal) const; - glm::vec3 getVertexN(const glm::vec3& normal) const; - void scale(float scale); - const glm::vec3& getCorner() const { return _corner; } - float getScale() const { return _scale; } - glm::vec3 getDimensions() const { return glm::vec3(_scale,_scale,_scale); } + void setBox(const glm::vec3& corner, float scale); + glm::vec3 getVertexP(const glm::vec3& normal) const; + glm::vec3 getVertexN(const glm::vec3& normal) const; + void scale(float scale); + const glm::vec3& getCorner() const { return _corner; } + float getScale() const { return _scale; } + glm::vec3 getDimensions() const { return glm::vec3(_scale,_scale,_scale); } - glm::vec3 calcCenter() const; - glm::vec3 calcTopFarLeft() const; - glm::vec3 getVertex(BoxVertex vertex) const; - bool contains(const glm::vec3& point) const; - bool contains(const AACube& otherCube) const; - bool touches(const AACube& otherCube) const; - bool contains(const AABox& otherBox) const; - bool touches(const AABox& otherBox) const; - bool expandedContains(const glm::vec3& point, float expansion) const; - bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; - bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; - bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; + glm::vec3 calcCenter() const; + glm::vec3 calcTopFarLeft() const; + glm::vec3 getVertex(BoxVertex vertex) const; + + const glm::vec3& getMinimumPoint() const { return _corner; } + glm::vec3 getMaximumPoint() const { return calcTopFarLeft(); } + + bool contains(const glm::vec3& point) const; + bool contains(const AACube& otherCube) const; + bool touches(const AACube& otherCube) const; + bool contains(const AABox& otherBox) const; + bool touches(const AABox& otherBox) const; + bool expandedContains(const glm::vec3& point, float expansion) const; + bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; + bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; private: glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;