when EntityTree::updateEntityWithElement is called on an entity, call it on all the children of that entity

This commit is contained in:
Seth Alves 2015-10-22 16:59:56 -07:00
parent d86d69aeba
commit 7b08d047b1
11 changed files with 213 additions and 105 deletions

View file

@ -37,7 +37,7 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_CORNER(-0.5f);
const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f);
AvatarData::AvatarData() :
_sessionUUID(),
SpatiallyNestable(NestableTypes::Avatar, QUuid()),
_handPosition(0.0f),
_targetScale(1.0f),
_handState(0),

View file

@ -172,7 +172,7 @@ public:
virtual bool isMyAvatar() const { return false; }
const QUuid& getSessionUUID() const { return _sessionUUID; }
const QUuid& getSessionUUID() const { return getID(); }
glm::vec3 getHandPosition() const;
void setHandPosition(const glm::vec3& handPosition);
@ -327,7 +327,7 @@ public slots:
void setBillboardFromNetworkReply();
void setJointMappingsFromNetworkReply();
void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; }
void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); }
bool isPlaying();
bool isPaused();
@ -353,7 +353,6 @@ public slots:
void stopPlaying();
protected:
QUuid _sessionUUID;
glm::vec3 _handPosition;
// Body scale

View file

@ -0,0 +1,83 @@
//
// BoundingBoxRelatedProperties.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-9-24
// Copyright 2013 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 "EntityItemProperties.h"
#include "BoundingBoxRelatedProperties.h"
#include "EntityTree.h"
BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity) :
position(entity->getPosition()),
rotation(entity->getRotation()),
registrationPoint(entity->getRegistrationPoint()),
dimensions(entity->getDimensions()),
parentID(entity->getParentID()) {
}
BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity,
const EntityItemProperties& propertiesWithUpdates) :
BoundingBoxRelatedProperties(entity) {
if (propertiesWithUpdates.parentIDChanged()) {
parentID = propertiesWithUpdates.getParentID();
}
bool parentFound = false;
if (parentID != UNKNOWN_ENTITY_ID) {
EntityTreePointer tree = entity->getTree();
EntityItemPointer parentZone = tree->findEntityByID(parentID);
if (parentZone) {
parentFound = true;
glm::vec3 localPosition = propertiesWithUpdates.containsPositionChange() ?
propertiesWithUpdates.getPosition() :
entity->getLocalPosition();
glm::quat localRotation = propertiesWithUpdates.rotationChanged() ?
propertiesWithUpdates.getRotation() :
entity->getLocalOrientation();
const Transform parentTransform = parentZone->getTransformToCenter();
Transform parentDescaled(parentTransform.getRotation(), glm::vec3(1.0f), parentTransform.getTranslation());
Transform localTransform(localRotation, glm::vec3(1.0f), localPosition);
Transform result;
Transform::mult(result, parentDescaled, localTransform);
position = result.getTranslation();
rotation = result.getRotation();
}
}
if (!parentFound) {
if (propertiesWithUpdates.containsPositionChange()) {
position = propertiesWithUpdates.getPosition();
}
if (propertiesWithUpdates.rotationChanged()) {
rotation = propertiesWithUpdates.getRotation();
}
}
if (propertiesWithUpdates.registrationPointChanged()) {
registrationPoint = propertiesWithUpdates.getRegistrationPoint();
}
if (propertiesWithUpdates.dimensionsChanged()) {
dimensions = propertiesWithUpdates.getDimensions();
}
}
AACube BoundingBoxRelatedProperties::getMaximumAACube() const {
// see EntityItem::getMaximumAACube for comments which explain the following.
glm::vec3 scaledRegistrationPoint = (dimensions * registrationPoint);
glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(scaledRegistrationPoint, registrationRemainder);
float radius = glm::length(furthestExtentFromRegistration);
glm::vec3 minimumCorner = position - glm::vec3(radius, radius, radius);
return AACube(minimumCorner, radius * 2.0f);
}

View file

@ -0,0 +1,30 @@
//
// BoundingBoxRelatedProperties.h
// libraries/entities/src
//
// Created by Seth Alves on 2015-9-24
// Copyright 2013 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 "EntityItem.h"
#ifndef hifi_BoundingBoxRelatedProperties_h
#define hifi_BoundingBoxRelatedProperties_h
class BoundingBoxRelatedProperties {
public:
BoundingBoxRelatedProperties(EntityItemPointer entity);
BoundingBoxRelatedProperties(EntityItemPointer entity, const EntityItemProperties& propertiesWithUpdates);
AACube getMaximumAACube() const;
glm::vec3 position;
glm::quat rotation;
glm::vec3 registrationPoint;
glm::vec3 dimensions;
EntityItemID parentID;
};
#endif // hifi_BoundingBoxRelatedProperties_h

View file

@ -37,7 +37,7 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(entityItemID),
SpatiallyNestable(NestableTypes::Entity, entityItemID),
_type(EntityTypes::Unknown),
_lastSimulated(0),
_lastUpdated(0),

View file

@ -143,8 +143,11 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
if (!wantsLocked) {
EntityItemProperties tempProperties;
tempProperties.setLocked(wantsLocked);
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, tempProperties);
BoundingBoxRelatedProperties newBBRelProperties(entity, tempProperties);
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties);
recurseTreeWithOperator(&theOperator);
entity->setProperties(tempProperties);
_isDirty = true;
}
}
@ -205,8 +208,34 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
quint64 entityScriptTimestampBefore = entity->getScriptTimestamp();
QString collisionSoundURLBefore = entity->getCollisionSoundURL();
uint32_t preFlags = entity->getDirtyFlags();
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, properties);
BoundingBoxRelatedProperties newBBRelProperties(entity, properties);
UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties);
recurseTreeWithOperator(&theOperator);
entity->setProperties(properties);
// if the entity has children, run UpdateEntityOperator on them. If the children have children, recurse
QQueue<SpatiallyNestablePointer> toProcess;
foreach (SpatiallyNestablePointer child, entity->getChildren()) {
if (child && child->getNestableType() == NestableTypes::Entity) {
toProcess.enqueue(child);
}
}
while (!toProcess.empty()) {
EntityItemPointer childEntity = std::static_pointer_cast<EntityItem>(toProcess.dequeue());
BoundingBoxRelatedProperties newChildBBRelProperties(childEntity);
UpdateEntityOperator theChildOperator(getThisPointer(),
childEntity->getElement(),
childEntity, newChildBBRelProperties);
recurseTreeWithOperator(&theChildOperator);
foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) {
if (childChild && childChild->getNestableType() == NestableTypes::Entity) {
toProcess.enqueue(childChild);
}
}
}
_isDirty = true;
uint32_t newFlags = entity->getDirtyFlags() & ~preFlags;

View file

@ -20,8 +20,8 @@
#include <OctreeRenderer.h> // for RenderArgs
class EntityItem;
typedef std::shared_ptr<EntityItem> EntityItemPointer;
typedef std::weak_ptr<EntityItem> EntityItemWeakPointer;
using EntityItemPointer = std::shared_ptr<EntityItem>;
using EntityItemWeakPointer = std::weak_ptr<EntityItem>;
inline uint qHash(const EntityItemPointer& a, uint seed) {
return qHash(a.get(), seed);

View file

@ -14,12 +14,12 @@
UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
EntityTreeElementPointer containingElement,
EntityItemPointer existingEntity,
const EntityItemProperties& properties) :
const BoundingBoxRelatedProperties& newProperties) :
_tree(tree),
_existingEntity(existingEntity),
_containingElement(containingElement),
_containingElementCube(containingElement->getAACube()),
_properties(properties),
_newProperties(newProperties),
_entityItemID(existingEntity->getEntityItemID()),
_foundOld(false),
_foundNew(false),
@ -44,83 +44,32 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree,
_oldEntityCube = _existingEntity->getMaximumAACube();
_oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
// If the old properties doesn't contain the properties required to calculate a bounding box,
// get them from the existing entity. Registration point is required to correctly calculate
// the bounding box.
if (!_properties.registrationPointChanged()) {
_properties.setRegistrationPoint(_existingEntity->getRegistrationPoint());
}
// 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.containsDimensionsChange()) {
glm::vec3 oldDimensions= _existingEntity->getDimensions();
_properties.setDimensions(oldDimensions);
if (_wantDebug) {
qCDebug(entities) << " ** setting properties dimensions - had position change, no dimension change **";
}
}
if (!_properties.containsPositionChange() && _properties.containsDimensionsChange()) {
glm::vec3 oldPosition= _existingEntity->getPosition();
_properties.setPosition(oldPosition);
if (_wantDebug) {
qCDebug(entities) << " ** setting properties position - had dimensions change, no position change **";
}
}
// 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
// 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
// be the same for both parts of the update
bool oldElementBestFit = _containingElement->bestFitBounds(_properties);
// if we don't have bounds properties, then use our old clamped box to determine best fit
if (!_properties.containsBoundsProperties()) {
oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox);
bool oldElementBestFit = _containingElement->bestFitBounds(newProperties.getMaximumAACube());
if (_wantDebug) {
qCDebug(entities) << " ** old Element best fit - no dimensions change, no position change **";
}
}
// For some reason we've seen a case where the original containing element isn't a best fit for the old properties
// in this case we want to move it, even if the properties haven't changed.
if (!_properties.containsBoundsProperties() && !oldElementBestFit) {
if (!oldElementBestFit) {
_newEntityCube = _oldEntityCube;
_removeOld = true; // our properties are going to move us, so remember this for later processing
if (_wantDebug) {
qCDebug(entities) << " **** UNUSUAL CASE **** no changes, but not best fit... consider it a move.... **";
}
} else if (!_properties.containsBoundsProperties() || oldElementBestFit) {
} else {
_foundOld = true;
_newEntityCube = _oldEntityCube;
_dontMove = true;
if (_wantDebug) {
qCDebug(entities) << " **** TYPICAL NO MOVE CASE ****";
qCDebug(entities) << " _properties.containsBoundsProperties():" << _properties.containsBoundsProperties();
qCDebug(entities) << " oldElementBestFit:" << oldElementBestFit;
}
} else {
_newEntityCube = _properties.getMaximumAACube();
_removeOld = true; // our properties are going to move us, so remember this for later processing
if (_wantDebug) {
qCDebug(entities) << " **** TYPICAL MOVE CASE ****";
qCDebug(entities) << " **** TYPICAL NO MOVE CASE **** oldElementBestFit:" << oldElementBestFit;
}
}
_newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds
if (_wantDebug) {
qCDebug(entities) << " _entityItemID:" << _entityItemID;
qCDebug(entities) << " _containingElementCube:" << _containingElementCube;
@ -176,7 +125,7 @@ bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElementPointer element
bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(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
// and of the following are true:
@ -185,7 +134,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
//
// Note: it's often the case that the branch in question contains both the old entity
// and the new entity.
bool keepSearching = false; // assume we don't need to search any more
bool subtreeContainsOld = subTreeContainsOldEntity(element);
@ -257,7 +206,8 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
qCDebug(entities) << " NEW TREE CASE....";
qCDebug(entities) << " entityTreeElement=" << entityTreeElement.get();
qCDebug(entities) << " _containingElement=" << _containingElement.get();
qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox);
qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)="
<< entityTreeElement->bestFitBounds(_newEntityBox);
}
// If this element is the best fit for the new entity properties, then add/or update it
@ -270,16 +220,9 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
EntityTreeElementPointer oldElement = _existingEntity->getElement();
// if we are the existing containing element, then we can just do the update of the entity properties
if (entityTreeElement == oldElement) {
if (_wantDebug) {
qCDebug(entities) << " *** This is the same OLD ELEMENT ***";
}
// set the entity properties and mark our element as changed.
_existingEntity->setProperties(_properties);
if (_wantDebug) {
qCDebug(entities) << " *** set properties ***";
}
} else {
// otherwise, this is an add case.
if (oldElement) {
@ -290,11 +233,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
}
entityTreeElement->addEntityItem(_existingEntity);
_tree->setContainingElement(_entityItemID, entityTreeElement);
_existingEntity->setProperties(_properties); // still need to update the properties!
if (_wantDebug) {
qCDebug(entities) << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***";
}
}
_foundNew = true; // we found the new element
_removeOld = false; // and it has already been removed from the old
@ -308,7 +246,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) {
qCDebug(entities) << "--------------------------------------------------";
}
return keepSearching; // if we haven't yet found it, keep looking
}
@ -329,9 +266,9 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) {
}
// It's not OK to prune if we have the potential of deleting the original containig element.
// because if we prune the containing element then new might end up reallocating the same memory later
// because if we prune the containing element then new might end up reallocating the same memory later
// and that will confuse our logic.
//
//
// it's ok to prune if:
// 1) we're not removing the old
// 2) we are removing the old, but this subtree doesn't contain the old
@ -340,17 +277,17 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves
}
return keepSearching; // if we haven't yet found it, keep looking
}
OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) {
OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) {
// If we're getting called, it's because there was no child element at this index while recursing.
// We only care if this happens while still searching for the new entity location.
// Check to see if
// Check to see if
if (!_foundNew) {
float childElementScale = element->getScale() / 2.0f; // all of our children will be half our scale
// Note: because the entity's bounds might have been clamped to the domain. We want to check if the
// bounds of the clamped box would fit in our child elements. It may be the case that the actual
// bounds of the element would hang outside of the child elements cells.
@ -365,5 +302,5 @@ OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPo
}
}
}
return NULL;
return NULL;
}

View file

@ -12,6 +12,7 @@
#ifndef hifi_UpdateEntityOperator_h
#define hifi_UpdateEntityOperator_h
#include "BoundingBoxRelatedProperties.h"
#include "EntitiesLogging.h"
#include "EntityItem.h"
#include "EntityItemProperties.h"
@ -21,7 +22,8 @@
class UpdateEntityOperator : public RecurseOctreeOperator {
public:
UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement,
EntityItemPointer existingEntity, const EntityItemProperties& properties);
EntityItemPointer existingEntity, const BoundingBoxRelatedProperties& newProperties);
~UpdateEntityOperator();
virtual bool preRecursion(OctreeElementPointer element);
@ -32,7 +34,7 @@ private:
EntityItemPointer _existingEntity;
EntityTreeElementPointer _containingElement;
AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element
EntityItemProperties _properties;
BoundingBoxRelatedProperties _newProperties;
EntityItemID _entityItemID;
bool _foundOld;
bool _foundNew;

View file

@ -32,10 +32,13 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
return nullptr;
}
SpatiallyNestableConstPointer constThisPointer = shared_from_this();
SpatiallyNestablePointer thisPointer = std::const_pointer_cast<SpatiallyNestable>(constThisPointer); // ermahgerd !!!
if (parent && parent->getID() == _parentID) {
// parent pointer is up-to-date
if (!_parentKnowsMe) {
parent->beParentOfChild(shared_from_this());
parent->beParentOfChild(thisPointer);
_parentKnowsMe = true;
}
return parent;
@ -43,7 +46,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
if (parent) {
// we have a parent pointer but our _parentID doesn't indicate this parent.
parent->forgetChild(shared_from_this());
parent->forgetChild(thisPointer);
_parentKnowsMe = false;
_parent.reset();
}
@ -53,17 +56,17 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const {
_parent = parentFinder->find(_parentID);
parent = _parent.lock();
if (parent) {
parent->beParentOfChild(shared_from_this());
parent->beParentOfChild(thisPointer);
_parentKnowsMe = true;
}
return parent;
}
void SpatiallyNestable::beParentOfChild(SpatiallyNestableConstPointer newChild) const {
void SpatiallyNestable::beParentOfChild(SpatiallyNestablePointer newChild) const {
_children[newChild->getID()] = newChild;
}
void SpatiallyNestable::forgetChild(SpatiallyNestableConstPointer newChild) const {
void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const {
_children.remove(newChild->getID());
}
@ -153,3 +156,14 @@ const glm::vec3& SpatiallyNestable::getLocalScale() const {
void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
_transform.setScale(scale);
}
QList<SpatiallyNestablePointer> SpatiallyNestable::getChildren() const {
QList<SpatiallyNestablePointer> children;
foreach (SpatiallyNestableWeakPointer childWP, _children.values()) {
SpatiallyNestablePointer child = childWP.lock();
if (child) {
children << child;
}
}
return children;
}

View file

@ -24,11 +24,21 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr<const SpatiallyNestable>
using SpatiallyNestablePointer = std::shared_ptr<SpatiallyNestable>;
using SpatiallyNestableConstPointer = std::shared_ptr<const SpatiallyNestable>;
class SpatiallyNestable : public std::enable_shared_from_this<SpatiallyNestable> {
class NestableTypes {
public:
SpatiallyNestable() : _transform() { } // XXX get rid of this one?
SpatiallyNestable(QUuid id) : _id(id), _transform() { }
using NestableType = enum NestableType_t {
Entity,
Avatar
};
};
class SpatiallyNestable : public std::enable_shared_from_this<SpatiallyNestable> {
public:
// SpatiallyNestable() : _transform() { } // XXX get rid of this one?
SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) :
_nestableType(nestableType),
_id(id),
_transform() { }
virtual ~SpatiallyNestable() { }
virtual const QUuid& getID() const { return _id; }
@ -68,16 +78,20 @@ public:
virtual const glm::vec3& getLocalScale() const;
virtual void setLocalScale(const glm::vec3& scale);
QList<SpatiallyNestablePointer> getChildren() const;
NestableTypes::NestableType getNestableType() const { return _nestableType; }
protected:
NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData
QUuid _id;
QUuid _parentID; // what is this thing's transform relative to?
quint16 _parentJointIndex; // which joint of the parent is this relative to?
SpatiallyNestablePointer getParentPointer() const;
mutable SpatiallyNestableWeakPointer _parent;
virtual void beParentOfChild(SpatiallyNestableConstPointer newChild) const;
virtual void forgetChild(SpatiallyNestableConstPointer newChild) const;
mutable QHash<QUuid, SpatiallyNestableWeakConstPointer> _children;
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const;
virtual void forgetChild(SpatiallyNestablePointer newChild) const;
mutable QHash<QUuid, SpatiallyNestableWeakPointer> _children;
private:
Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform.