fixed some problems in UpdateEntityOperator in case where original containing element isn't best fit

This commit is contained in:
ZappoMan 2014-08-29 17:48:14 -07:00
parent f654fac851
commit 2fab662e8c
11 changed files with 532 additions and 124 deletions

View file

@ -66,8 +66,21 @@ void EntityTreeRenderer::update() {
} }
void EntityTreeRenderer::render(RenderMode renderMode) { void EntityTreeRenderer::render(RenderMode renderMode) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "------------ EntityTreeRenderer::render() -- BEFORE WE BEGIN: the tree[" << _tree << "] -------------";
static_cast<EntityTree*>(_tree)->dumpTree();
qDebug() << "------------ EntityTreeRenderer::render() -- END the tree-------------";
}
OctreeRenderer::render(renderMode); OctreeRenderer::render(renderMode);
deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup
if (wantDebug) {
qDebug() << "------------ DONE EntityTreeRenderer::render() -------------";
}
} }
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* entityItem) { const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* entityItem) {
@ -98,6 +111,14 @@ const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityI
} }
void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) { void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "EntityTreeRenderer::renderElement()...";
qDebug() << " element=" << element;
qDebug() << " element->getAACube()=" << element->getAACube();
}
//PerformanceTimer perfTimer("renderElement"); //PerformanceTimer perfTimer("renderElement");
args->_elementsTouched++; args->_elementsTouched++;
// actually render it here... // actually render it here...
@ -180,8 +201,6 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
for (uint16_t i = 0; i < numberOfEntities; i++) { for (uint16_t i = 0; i < numberOfEntities; i++) {
EntityItem* entityItem = entityItems[i]; EntityItem* entityItem = entityItems[i];
bool wantDebug = false;
if (wantDebug) { if (wantDebug) {
bool isBestFit = entityTreeElement->bestFitEntityBounds(entityItem); bool isBestFit = entityTreeElement->bestFitEntityBounds(entityItem);
qDebug() << "EntityTreeRenderer::renderElement() " qDebug() << "EntityTreeRenderer::renderElement() "
@ -202,6 +221,12 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
if (entityItem->getGlowLevel() > 0.0f) { if (entityItem->getGlowLevel() > 0.0f) {
glower = new Glower(entityItem->getGlowLevel()); glower = new Glower(entityItem->getGlowLevel());
} }
if (wantDebug) {
qDebug() << " EntityTreeRenderer about to render entity...";
qDebug() << " element=" << element;
qDebug() << " entityItem=" << entityItem;
qDebug() << " entityItem->getEntityItemID()=" << entityItem->getEntityItemID();
}
entityItem->render(args); entityItem->render(args);
if (glower) { if (glower) {
delete glower; delete glower;

View file

@ -21,36 +21,95 @@ DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree, const EntityItemID&
_foundCount(0), _foundCount(0),
_lookingCount(0) _lookingCount(0)
{ {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID).... ";
qDebug() << " tree=" << tree;
qDebug() << " _tree=" << tree;
qDebug() << "------------ DeleteEntityOperator -- BEFORE WE BEGIN: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ DeleteEntityOperator -- END the tree-------------";
}
addEntityIDToDeleteList(searchEntityID); addEntityIDToDeleteList(searchEntityID);
} }
DeleteEntityOperator::~DeleteEntityOperator() {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "~DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID).... ";
qDebug() << "------------ ~DeleteEntityOperator -- AFTER WE'RE DONE: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ ~DeleteEntityOperator -- END the tree-------------";
}
}
DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree) : DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree) :
_tree(tree), _tree(tree),
_changeTime(usecTimestampNow()), _changeTime(usecTimestampNow()),
_foundCount(0), _foundCount(0),
_lookingCount(0) _lookingCount(0)
{ {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "DeleteEntityOperator(EntityTree* tree).... ";
qDebug() << " tree=" << tree;
qDebug() << " _tree=" << _tree;
qDebug() << "------------ DeleteEntityOperator -- BEFORE WE BEGIN: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ DeleteEntityOperator -- END the tree-------------";
}
} }
void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEntityID) { void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEntityID) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEntityID).... ";
qDebug() << " _tree=" << _tree;
qDebug() << " searchEntityID=" << searchEntityID;
}
// check our tree, to determine if this entity is known // check our tree, to determine if this entity is known
EntityToDeleteDetails details; EntityToDeleteDetails details;
details.containingElement = _tree->getContainingElement(searchEntityID); details.containingElement = _tree->getContainingElement(searchEntityID);
if (wantDebug) {
qDebug() << " details.containingElement=" << details.containingElement;
}
if (details.containingElement) { if (details.containingElement) {
details.entity = details.containingElement->getEntityWithEntityItemID(searchEntityID); details.entity = details.containingElement->getEntityWithEntityItemID(searchEntityID);
if (wantDebug) {
qDebug() << " details.entity=" << details.entity;
}
if (!details.entity) { if (!details.entity) {
//assert(false); //assert(false);
qDebug() << "that's UNEXPECTED, we got a _containingElement, but couldn't find the oldEntity!"; qDebug() << "that's UNEXPECTED, we got a _containingElement, but couldn't find the oldEntity!";
} else { } else {
details.cube = details.containingElement->getAACube(); details.cube = details.containingElement->getAACube();
if (wantDebug) {
qDebug() << " details.cube=" << details.cube;
}
_entitiesToDelete << details; _entitiesToDelete << details;
_lookingCount++; _lookingCount++;
_tree->trackDeletedEntity(searchEntityID); _tree->trackDeletedEntity(searchEntityID);
// before deleting any entity make sure to remove it from our Mortal, Changing, and Moving lists // before deleting any entity make sure to remove it from our Mortal, Changing, and Moving lists
_tree->removeEntityFromSimulationLists(searchEntityID); _tree->removeEntityFromSimulationLists(searchEntityID);
} }
} }
if (wantDebug) {
qDebug() << " _entitiesToDelete.size():" << _entitiesToDelete.size();
}
} }
@ -73,6 +132,29 @@ bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElement* el
} }
bool DeleteEntityOperator::PreRecursion(OctreeElement* element) { bool DeleteEntityOperator::PreRecursion(OctreeElement* element) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "DeleteEntityOperator::PreRecursion().... ";
qDebug() << " element=" << element;
qDebug() << " element.AACube=" << element->getAACube();
qDebug() << " _lookingCount=" << _lookingCount;
qDebug() << " _foundCount=" << _foundCount;
qDebug() << " --------- list of deleting entities -----------";
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
qDebug() << " ENTITY TO DELETE";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " cube=" << details.cube;
qDebug() << " containingElement=" << details.containingElement;
qDebug() << " containingElement->getAACube()=" << details.containingElement->getAACube();
}
qDebug() << " --------- list of deleting entities -----------";
}
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element); EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
// In Pre-recursion, we're generally deciding whether or not we want to recurse this // In Pre-recursion, we're generally deciding whether or not we want to recurse this
@ -98,10 +180,20 @@ bool DeleteEntityOperator::PreRecursion(OctreeElement* element) {
if (entityTreeElement == details.containingElement) { if (entityTreeElement == details.containingElement) {
EntityItemID entityItemID = details.entity->getEntityItemID(); EntityItemID entityItemID = details.entity->getEntityItemID();
EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity
entityTreeElement->removeEntityItem(theEntity); // remove it from the element bool removed = entityTreeElement->removeEntityItem(theEntity); // remove it from the element
_tree->setContainingElement(entityItemID, NULL); // update or id to element lookup _tree->setContainingElement(entityItemID, NULL); // update or id to element lookup
delete theEntity; // now actually delete the entity! delete theEntity; // now actually delete the entity!
_foundCount++; _foundCount++;
if (wantDebug) {
qDebug() << "DeleteEntityOperator::PreRecursion().... deleting entity:" << entityItemID;
qDebug() << " details.entity=" << details.entity;
qDebug() << " theEntity=" << theEntity;
qDebug() << " called entityTreeElement->removeEntityItem(theEntity)";
qDebug() << " removed=" << removed;
qDebug() << " called _tree->setContainingElement(entityItemID, NULL)";
qDebug() << " called delete theEntity";
}
} }
} }
@ -113,6 +205,27 @@ bool DeleteEntityOperator::PreRecursion(OctreeElement* element) {
} }
bool DeleteEntityOperator::PostRecursion(OctreeElement* element) { bool DeleteEntityOperator::PostRecursion(OctreeElement* element) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "DeleteEntityOperator::PostRecursion().... ";
qDebug() << " element=" << element;
qDebug() << " element.AACube=" << element->getAACube();
qDebug() << " _lookingCount=" << _lookingCount;
qDebug() << " _foundCount=" << _foundCount;
qDebug() << " --------- list of deleting entities -----------";
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
qDebug() << " DELETING ENTITY";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " cube=" << details.cube;
qDebug() << " containingElement=" << details.containingElement;
}
qDebug() << " --------- list of deleting entities -----------";
}
// Post-recursion is the unwinding process. For this operation, while we // Post-recursion is the unwinding process. For this operation, while we
// unwind we want to mark the path as being dirty if we changed it below. // unwind we want to mark the path as being dirty if we changed it below.
// We might have two paths, one for the old entity and one for the new entity. // We might have two paths, one for the old entity and one for the new entity.
@ -124,9 +237,9 @@ bool DeleteEntityOperator::PostRecursion(OctreeElement* element) {
element->markWithChangedTime(); element->markWithChangedTime();
} }
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element); EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
bool somethingPruned = entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves bool somethingPruned = entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves
bool wantDebug = false;
if (somethingPruned && wantDebug) { if (somethingPruned && wantDebug) {
qDebug() << "DeleteEntityOperator::PostRecursion() something pruned!!!"; qDebug() << "DeleteEntityOperator::PostRecursion() something pruned!!!";
} }

View file

@ -31,6 +31,8 @@ class DeleteEntityOperator : public RecurseOctreeOperator {
public: public:
DeleteEntityOperator(EntityTree* tree); DeleteEntityOperator(EntityTree* tree);
DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID); DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID);
~DeleteEntityOperator();
void addEntityIDToDeleteList(const EntityItemID& searchEntityID); void addEntityIDToDeleteList(const EntityItemID& searchEntityID);
virtual bool PreRecursion(OctreeElement* element); virtual bool PreRecursion(OctreeElement* element);
virtual bool PostRecursion(OctreeElement* element); virtual bool PostRecursion(OctreeElement* element);

View file

@ -694,16 +694,23 @@ void EntityTree::changeEntityState(EntityItem* const entity,
void EntityTree::update() { void EntityTree::update() {
// our new strategy should be to segregate entities into three classes: // our new strategy should be to segregate entities into three classes:
// 1) stationary things that are not changing - most models // 1) stationary things that are not changing - most models
// 2) stationary things that are animating - they can be touched linearly and they don't change the tree // 2) mortal things - these are stationary but have a lifetime - then need to be checked,
// can be touched linearly, and won't change the tree
// 2) changing things - like things animating they can be touched linearly and they don't change the tree
// 3) moving things - these need to scan the tree and update accordingly // 3) moving things - these need to scan the tree and update accordingly
// finally - all things that need to be deleted, can be handled on a single delete pass.
//
// TODO: theoretically we could combine the move and delete tree passes...
lockForWrite(); lockForWrite();
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
QSet<EntityItemID> entitiesToDelete; QSet<EntityItemID> entitiesToDelete;
updateChangingEntities(now, entitiesToDelete); updateChangingEntities(now, entitiesToDelete);
updateMovingEntities(now, entitiesToDelete); updateMovingEntities(now, entitiesToDelete);
updateMortalEntities(now, entitiesToDelete); updateMortalEntities(now, entitiesToDelete);
deleteEntities(entitiesToDelete);
if (entitiesToDelete.size() > 0) {
deleteEntities(entitiesToDelete);
}
unlock(); unlock();
} }
@ -749,66 +756,76 @@ void EntityTree::updateChangingEntities(quint64 now, QSet<EntityItemID>& entitie
void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) { void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
bool wantDebug = false; bool wantDebug = false;
MovingEntitiesOperator moveOperator(this);
QSet<EntityItem*> entitiesBecomingStatic; if (_movingEntities.size() > 0) {
QSet<EntityItem*> entitiesBecomingMortal; MovingEntitiesOperator moveOperator(this);
QSet<EntityItem*> entitiesBecomingChanging;
// TODO: switch these to iterators so we can remove items that get deleted QSet<EntityItem*> entitiesBecomingStatic;
for (int i = 0; i < _movingEntities.size(); i++) { QSet<EntityItem*> entitiesBecomingMortal;
EntityItem* thisEntity = _movingEntities[i]; QSet<EntityItem*> entitiesBecomingChanging;
// always check to see if the lifetime has expired, for immortal entities this is always false // TODO: switch these to iterators so we can remove items that get deleted
if (thisEntity->lifetimeHasExpired()) { for (int i = 0; i < _movingEntities.size(); i++) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID(); EntityItem* thisEntity = _movingEntities[i];
entitiesToDelete << thisEntity->getEntityItemID();
entitiesBecomingStatic << thisEntity; // always check to see if the lifetime has expired, for immortal entities this is always false
} else { if (thisEntity->lifetimeHasExpired()) {
AACube oldCube = thisEntity->getAACube(); qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
thisEntity->update(now);
AACube newCube = thisEntity->getAACube();
// 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)) {
if (wantDebug) {
qDebug() << "The entity " << thisEntity->getEntityItemID() << " moved outside of the domain. Delete it.";
}
entitiesToDelete << thisEntity->getEntityItemID(); entitiesToDelete << thisEntity->getEntityItemID();
entitiesBecomingStatic << thisEntity; entitiesBecomingStatic << thisEntity;
} else { } else {
AACube oldCube = thisEntity->getAACube();
thisEntity->update(now);
AACube newCube = thisEntity->getAACube();
if (wantDebug) { if (wantDebug) {
qDebug() << "EntityTree::update() thisEntity=" << thisEntity; qDebug() << "MOVING entity " << thisEntity->getEntityItemID();
qDebug() << " oldCube=" << oldCube; qDebug() << " oldCube:" << oldCube;
qDebug() << " newCube=" << newCube; qDebug() << " newCube:" << newCube;
}
// 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)) {
if (wantDebug) {
qDebug() << "The entity moved outside of the domain. Delete it.";
qDebug() << " entity=" << thisEntity;
qDebug() << " entityID=" << thisEntity->getEntityItemID();
} }
entitiesToDelete << thisEntity->getEntityItemID();
moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube);
// check to see if this entity is no longer moving
EntityItem::SimulationState newState = thisEntity->getSimulationState();
if (newState == EntityItem::Changing) {
entitiesBecomingChanging << thisEntity;
} else if (newState == EntityItem::Mortal) {
entitiesBecomingMortal << thisEntity;
} else if (newState == EntityItem::Static) {
entitiesBecomingStatic << thisEntity; entitiesBecomingStatic << thisEntity;
} else {
if (wantDebug) {
qDebug() << " ACTUALLY MOVING IT";
}
moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube);
// check to see if this entity is no longer moving
EntityItem::SimulationState newState = thisEntity->getSimulationState();
if (newState == EntityItem::Changing) {
entitiesBecomingChanging << thisEntity;
} else if (newState == EntityItem::Mortal) {
entitiesBecomingMortal << thisEntity;
} else if (newState == EntityItem::Static) {
entitiesBecomingStatic << thisEntity;
}
} }
} }
} }
} if (moveOperator.hasMovingEntities()) {
recurseTreeWithOperator(&moveOperator); recurseTreeWithOperator(&moveOperator);
}
// change state for any entities that were moving but are now either static, mortal, or changing // change state for any entities that were moving but are now either static, mortal, or changing
foreach(EntityItem* entity, entitiesBecomingStatic) { foreach(EntityItem* entity, entitiesBecomingStatic) {
changeEntityState(entity, EntityItem::Moving, EntityItem::Static); changeEntityState(entity, EntityItem::Moving, EntityItem::Static);
} }
foreach(EntityItem* entity, entitiesBecomingMortal) { foreach(EntityItem* entity, entitiesBecomingMortal) {
changeEntityState(entity, EntityItem::Moving, EntityItem::Mortal); changeEntityState(entity, EntityItem::Moving, EntityItem::Mortal);
} }
foreach(EntityItem* entity, entitiesBecomingChanging) { foreach(EntityItem* entity, entitiesBecomingChanging) {
changeEntityState(entity, EntityItem::Moving, EntityItem::Changing); changeEntityState(entity, EntityItem::Moving, EntityItem::Changing);
}
} }
} }
@ -1196,6 +1213,7 @@ public:
bool DebugOperator::PreRecursion(OctreeElement* element) { bool DebugOperator::PreRecursion(OctreeElement* element) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element); EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
qDebug() << "EntityTreeElement [" << entityTreeElement << "]";
entityTreeElement->debugDump(); entityTreeElement->debugDump();
return true; return true;
} }

View file

@ -54,8 +54,6 @@ EntityTreeElement* EntityTreeElement::addChildAtIndex(int index) {
OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData, OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData* packetData,
EncodeBitstreamParams& params) const { EncodeBitstreamParams& params) const {
bool wantDebug = false; bool wantDebug = false;
if (wantDebug) { if (wantDebug) {
qDebug() << "EntityTreeElement::appendElementData()"; qDebug() << "EntityTreeElement::appendElementData()";
@ -600,17 +598,8 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) {
return foundEntity; return foundEntity;
} }
bool EntityTreeElement::removeEntityItem(const EntityItem* entity) { bool EntityTreeElement::removeEntityItem(EntityItem* entity) {
bool foundEntity = false; return _entityItems->removeAll(entity) > 0;
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;
} }
@ -666,7 +655,9 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
EntityItem::SimulationState oldState = entityItem->getSimulationState(); EntityItem::SimulationState oldState = entityItem->getSimulationState();
bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args);
EntityItem::SimulationState newState = entityItem->getSimulationState(); EntityItem::SimulationState newState = entityItem->getSimulationState();
_myTree->changeEntityState(entityItem, oldState, newState); if (oldState != newState) {
_myTree->changeEntityState(entityItem, oldState, newState);
}
bool bestFitAfter = bestFitEntityBounds(entityItem); bool bestFitAfter = bestFitEntityBounds(entityItem);
if (bestFitBefore != bestFitAfter) { if (bestFitBefore != bestFitAfter) {
@ -675,19 +666,20 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
// This is the case where the entity existed, and is in some element in our tree... // This is the case where the entity existed, and is in some element in our tree...
if (currentContainingElement != this) { if (currentContainingElement != this) {
currentContainingElement->removeEntityItem(entityItem); currentContainingElement->removeEntityItem(entityItem);
this->addEntityItem(entityItem); addEntityItem(entityItem);
_myTree->setContainingElement(entityItemID, this); _myTree->setContainingElement(entityItemID, this);
} }
} }
} }
} else { } else {
entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args); entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args);
if (entityItem) { if (entityItem) {
bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args);
addEntityItem(entityItem); // add this new entity to this elements entities addEntityItem(entityItem); // add this new entity to this elements entities
_myTree->setContainingElement(entityItem->getEntityItemID(), this); _myTree->setContainingElement(entityItemID, this);
newEntity = true; newEntity = true;
EntityItem::SimulationState newState = entityItem->getSimulationState();
_myTree->changeEntityState(entityItem, EntityItem::Static, newState);
} }
} }
// Move the buffer forward to read more entities // Move the buffer forward to read more entities

View file

@ -143,7 +143,7 @@ public:
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
bool removeEntityWithEntityItemID(const EntityItemID& id); bool removeEntityWithEntityItemID(const EntityItemID& id);
bool removeEntityItem(const EntityItem* entity); bool removeEntityItem(EntityItem* entity);
bool containsEntityBounds(const EntityItem* entity) const; bool containsEntityBounds(const EntityItem* entity) const;
bool bestFitEntityBounds(const EntityItem* entity) const; bool bestFitEntityBounds(const EntityItem* entity) const;

View file

@ -22,8 +22,31 @@ MovingEntitiesOperator::MovingEntitiesOperator(EntityTree* tree) :
_foundNewCount(0), _foundNewCount(0),
_lookingCount(0) _lookingCount(0)
{ {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "MovingEntitiesOperator..... *********** start here!";
qDebug() << " tree=" << tree;
qDebug() << " _tree=" << _tree;
qDebug() << "------------ MovingEntitiesOperator -- BEFORE WE BEGIN: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ MovingEntitiesOperator -- END the tree-------------";
}
} }
MovingEntitiesOperator::~MovingEntitiesOperator() {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "~MovingEntitiesOperator().... ";
qDebug() << "------------ ~MovingEntitiesOperator -- AFTER WE'RE DONE: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ ~MovingEntitiesOperator -- END the tree-------------";
}
}
void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube) { void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube) {
// check our tree, to determine if this entity is known // check our tree, to determine if this entity is known
EntityToMoveDetails details; EntityToMoveDetails details;
@ -33,6 +56,7 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACub
details.newFound = false; details.newFound = false;
details.oldCube = oldCube; details.oldCube = oldCube;
details.newCube = newCube; details.newCube = newCube;
details.newBox = newCube.clamp(0.0f, 1.0f);
_entitiesToMove << details; _entitiesToMove << details;
_lookingCount++; _lookingCount++;
} }
@ -56,6 +80,32 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) {
} }
bool MovingEntitiesOperator::PreRecursion(OctreeElement* element) { bool MovingEntitiesOperator::PreRecursion(OctreeElement* element) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "MovingEntitiesOperator::PreRecursion().... ";
qDebug() << " element=" << element;
qDebug() << " element.AACube=" << element->getAACube();
qDebug() << " _lookingCount=" << _lookingCount;
qDebug() << " _foundNewCount=" << _foundNewCount;
qDebug() << " _foundOldCount=" << _foundOldCount;
qDebug() << " --------- list of moving entities -----------";
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
qDebug() << " MOVING ENTITY";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " oldCube=" << details.oldCube;
qDebug() << " newCube=" << details.newCube;
qDebug() << " newBox=" << details.newBox;
qDebug() << " oldContainingElement=" << details.oldContainingElement;
qDebug() << " oldFound=" << details.oldFound;
qDebug() << " newFound=" << details.newFound;
}
qDebug() << " --------- list of moving entities -----------";
}
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element); EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
// In Pre-recursion, we're generally deciding whether or not we want to recurse this // In Pre-recursion, we're generally deciding whether or not we want to recurse this
@ -68,34 +118,97 @@ bool MovingEntitiesOperator::PreRecursion(OctreeElement* element) {
// and the new entity. // and the new entity.
bool keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount); bool keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount);
if (wantDebug) {
qDebug() << " keepSearching=" << keepSearching;
qDebug() << " shouldRecurseSubTree(element)=" << shouldRecurseSubTree(element);
}
// If we haven't yet found all the entities, and this sub tree contains at least one of our // If we haven't yet found all the entities, and this sub tree contains at least one of our
// entities, then we need to keep searching. // entities, then we need to keep searching.
if (keepSearching && shouldRecurseSubTree(element)) { if (keepSearching && shouldRecurseSubTree(element)) {
if (wantDebug) {
qDebug() << " PROCESSING MOVE ON THIS ELEMENT";
}
// check against each of our search entities // check against each of our search entities
qDebug() << " --------- PROCESSING list of moving entities -----------";
foreach(const EntityToMoveDetails& details, _entitiesToMove) { foreach(const EntityToMoveDetails& details, _entitiesToMove) {
qDebug() << " PROCESSING --- MOVING ENTITY";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " oldCube=" << details.oldCube;
qDebug() << " newCube=" << details.newCube;
qDebug() << " newBox=" << details.newBox;
qDebug() << " oldContainingElement=" << details.oldContainingElement;
qDebug() << " oldFound=" << details.oldFound;
qDebug() << " newFound=" << details.newFound;
if (!details.oldFound) {
qDebug() << " THIS ENTITY'S OLD LOCATION HAS NOT BEEN FOUND... ";
}
if (entityTreeElement == details.oldContainingElement) {
qDebug() << " THIS ELEMENT IS THE ENTITY'S OLD LOCATION... ";
}
// If this is one of the old elements we're looking for, then ask it to remove the old entity // 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) { if (!details.oldFound && entityTreeElement == details.oldContainingElement) {
EntityItemID entityItemID = details.entity->getEntityItemID();
entityTreeElement->removeEntityWithEntityItemID(entityItemID);
//qDebug() << "removing entityItem from element... entityItemID=" << entityItemID << "entityTreeElement=" << entityTreeElement; qDebug() << " PROCESSING REMOVE ENTITY FROM OLD ELEMENT <<<<<<<<<<<<<";
entityTreeElement->removeEntityItem(details.entity);
qDebug() << "removing entityItem from element... ";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " entityTreeElement=" << entityTreeElement;
qDebug() << " element=" << element;
qDebug() << " element->getAACube()=" << element->getAACube();
_foundOldCount++; _foundOldCount++;
//details.oldFound = true; // TODO: would be nice to add this optimization //details.oldFound = true; // TODO: would be nice to add this optimization
} }
// If this element is the best fit for the new bounds of this entity then add the entity to the element // If this element is the best fit for the new bounds of this entity then add the entity to the element
bool bestFitCube = entityTreeElement->bestFitBounds(details.newCube);
bool bestFitBox = entityTreeElement->bestFitBounds(details.newBox);
qDebug() << " bestFitCube=" << bestFitCube;
qDebug() << " bestFitBox=" << bestFitBox;
if (bestFitCube != bestFitBox) {
qDebug() << " WHOA!!!! bestFitCube != bestFitBox!!!!";
}
if (!details.newFound) {
qDebug() << " THIS ENTITY'S NEW LOCATION HAS NOT BEEN FOUND... ";
}
if (entityTreeElement->bestFitBounds(details.newCube)) {
qDebug() << " THIS ELEMENT IS THE ENTITY'S BEST FIT NEW LOCATION... ";
}
if (!details.newFound && entityTreeElement->bestFitBounds(details.newCube)) { if (!details.newFound && entityTreeElement->bestFitBounds(details.newCube)) {
qDebug() << " PROCESSING ADD ENTITY TO NEW ELEMENT <<<<<<<<<<<<<";
EntityItemID entityItemID = details.entity->getEntityItemID(); EntityItemID entityItemID = details.entity->getEntityItemID();
qDebug() << "adding entityItem to element...";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << entityItemID;
qDebug() << " entityTreeElement=" << entityTreeElement;
qDebug() << " element=" << element;
qDebug() << " element->getAACube()=" << element->getAACube();
entityTreeElement->addEntityItem(details.entity); entityTreeElement->addEntityItem(details.entity);
_tree->setContainingElement(entityItemID, entityTreeElement); _tree->setContainingElement(entityItemID, entityTreeElement);
//qDebug() << "adding entityItem to element... entityItemID=" << entityItemID << "entityTreeElement=" << entityTreeElement;
_foundNewCount++; _foundNewCount++;
//details.newFound = true; // TODO: would be nice to add this optimization //details.newFound = true; // TODO: would be nice to add this optimization
} }
} }
qDebug() << " --------- DONE PROCESSING list of moving entities -----------";
// if we haven't found all of our search for entities, then keep looking // if we haven't found all of our search for entities, then keep looking
keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount); keepSearching = (_foundOldCount < _lookingCount) || (_foundNewCount < _lookingCount);
@ -105,6 +218,33 @@ bool MovingEntitiesOperator::PreRecursion(OctreeElement* element) {
} }
bool MovingEntitiesOperator::PostRecursion(OctreeElement* element) { bool MovingEntitiesOperator::PostRecursion(OctreeElement* element) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "MovingEntitiesOperator::PostRecursion().... ";
qDebug() << " element=" << element;
qDebug() << " element.AACube=" << element->getAACube();
qDebug() << " _lookingCount=" << _lookingCount;
qDebug() << " _foundNewCount=" << _foundNewCount;
qDebug() << " _foundOldCount=" << _foundOldCount;
qDebug() << " --------- list of moving entities -----------";
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
qDebug() << " MOVING ENTITY";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " oldCube=" << details.oldCube;
qDebug() << " newCube=" << details.newCube;
qDebug() << " newBox=" << details.newBox;
qDebug() << " oldContainingElement=" << details.oldContainingElement;
qDebug() << " oldFound=" << details.oldFound;
qDebug() << " newFound=" << details.newFound;
}
qDebug() << " --------- list of moving entities -----------";
}
// Post-recursion is the unwinding process. For this operation, while we // Post-recursion is the unwinding process. For this operation, while we
// unwind we want to mark the path as being dirty if we changed it below. // unwind we want to mark the path as being dirty if we changed it below.
// We might have two paths, one for the old entity and one for the new entity. // We might have two paths, one for the old entity and one for the new entity.
@ -118,7 +258,6 @@ bool MovingEntitiesOperator::PostRecursion(OctreeElement* element) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element); EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
bool somethingPruned = entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves bool somethingPruned = entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves
bool wantDebug = false;
if (somethingPruned && wantDebug) { if (somethingPruned && wantDebug) {
qDebug() << "MovingEntitiesOperator::PostRecursion() something pruned!!!"; qDebug() << "MovingEntitiesOperator::PostRecursion() something pruned!!!";
} }
@ -131,8 +270,27 @@ OctreeElement* MovingEntitiesOperator::PossiblyCreateChildAt(OctreeElement* elem
if (wantDebug) { if (wantDebug) {
qDebug() << "MovingEntitiesOperator::PossiblyCreateChildAt().... "; qDebug() << "MovingEntitiesOperator::PossiblyCreateChildAt().... ";
qDebug() << " _foundNewCount=" << _foundNewCount; qDebug() << " element=" << element;
qDebug() << " element.AACube=" << element->getAACube();
qDebug() << " childIndex=" << childIndex;
qDebug() << " _lookingCount=" << _lookingCount; qDebug() << " _lookingCount=" << _lookingCount;
qDebug() << " _foundNewCount=" << _foundNewCount;
qDebug() << " _foundOldCount=" << _foundOldCount;
qDebug() << " --------- list of moving entities -----------";
foreach(const EntityToMoveDetails& details, _entitiesToMove) {
qDebug() << " MOVING ENTITY";
qDebug() << " entity=" << details.entity;
qDebug() << " entityItemID=" << details.entity->getEntityItemID();
qDebug() << " oldCube=" << details.oldCube;
qDebug() << " newCube=" << details.newCube;
qDebug() << " newBox=" << details.newBox;
qDebug() << " oldContainingElement=" << details.oldContainingElement;
qDebug() << " oldFound=" << details.oldFound;
qDebug() << " newFound=" << details.newFound;
}
qDebug() << " --------- list of moving entities -----------";
} }
// If we're getting called, it's because there was no child element at this index while recursing. // If we're getting called, it's because there was no child element at this index while recursing.
@ -145,25 +303,37 @@ OctreeElement* MovingEntitiesOperator::PossiblyCreateChildAt(OctreeElement* elem
foreach(const EntityToMoveDetails& details, _entitiesToMove) { foreach(const EntityToMoveDetails& details, _entitiesToMove) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element); EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
bool thisElementIsBestFit = entityTreeElement->bestFitBounds(details.newCube);
if (wantDebug) { if (wantDebug) {
qDebug() << " thisElementIsBestFit=" << thisElementIsBestFit; bool thisElementIsBestFitCube = entityTreeElement->bestFitBounds(details.newCube);
bool thisElementIsBestFitBox = entityTreeElement->bestFitBounds(details.newBox);
qDebug() << " thisElementIsBestFitCube=" << thisElementIsBestFitCube;
qDebug() << " thisElementIsBestFitBox=" << thisElementIsBestFitBox;
qDebug() << " details.newCube=" << details.newCube; qDebug() << " details.newCube=" << details.newCube;
qDebug() << " details.newBox=" << details.newBox;
qDebug() << " element=" << element;
qDebug() << " element->getAACube()=" << element->getAACube(); qDebug() << " element->getAACube()=" << element->getAACube();
} }
// if the scale of our desired cube is smaller than our children, then consider making a child // if the scale of our desired cube is smaller than our children, then consider making a child
if (details.newCube.getScale() <= childElementScale) { if (details.newBox.getLargestDimension() <= childElementScale) {
//qDebug() << " calling element->getMyChildContaining(details.newCube); ---------";
int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newCube); int indexOfChildContainingNewEntity = element->getMyChildContaining(details.newBox);
//qDebug() << " called element->getMyChildContaining(details.newCube); ---------"; if (wantDebug) {
qDebug() << " called element->getMyChildContaining(details.newBox); ---------";
qDebug() << " childIndex=" << childIndex;
qDebug() << " indexOfChildContainingNewEntity=" << indexOfChildContainingNewEntity;
}
// If the childIndex we were asked if we wanted to create contains this newCube, // 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 // then we will create this branch and continue. We can exit this loop immediately
// because if we need this branch for any one entity then it doesn't matter if it's // because if we need this branch for any one entity then it doesn't matter if it's
// needed for more entities. // needed for more entities.
if (childIndex == indexOfChildContainingNewEntity) { if (childIndex == indexOfChildContainingNewEntity) {
return element->addChildAtIndex(childIndex); OctreeElement* newChild = element->addChildAtIndex(childIndex);
if (wantDebug) {
qDebug() << " CREATING NEW CHILD --- childIndex=" << childIndex << "newChild=" << newChild;
}
return newChild;
} }
} }
} }

View file

@ -17,6 +17,7 @@ public:
EntityItem* entity; EntityItem* entity;
AACube oldCube; AACube oldCube;
AACube newCube; AACube newCube;
AABox newBox;
EntityTreeElement* oldContainingElement; EntityTreeElement* oldContainingElement;
bool oldFound; bool oldFound;
bool newFound; bool newFound;
@ -33,10 +34,13 @@ inline bool operator==(const EntityToMoveDetails& a, const EntityToMoveDetails&
class MovingEntitiesOperator : public RecurseOctreeOperator { class MovingEntitiesOperator : public RecurseOctreeOperator {
public: public:
MovingEntitiesOperator(EntityTree* tree); MovingEntitiesOperator(EntityTree* tree);
~MovingEntitiesOperator();
void addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube); void addEntityToMoveList(EntityItem* entity, const AACube& oldCube, const AACube& newCube);
virtual bool PreRecursion(OctreeElement* element); virtual bool PreRecursion(OctreeElement* element);
virtual bool PostRecursion(OctreeElement* element); virtual bool PostRecursion(OctreeElement* element);
virtual OctreeElement* PossiblyCreateChildAt(OctreeElement* element, int childIndex); virtual OctreeElement* PossiblyCreateChildAt(OctreeElement* element, int childIndex);
bool hasMovingEntities() const { return _entitiesToMove.size() > 0; }
private: private:
EntityTree* _tree; EntityTree* _tree;
QSet<EntityToMoveDetails> _entitiesToMove; QSet<EntityToMoveDetails> _entitiesToMove;

View file

@ -28,6 +28,7 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
_foundOld(false), _foundOld(false),
_foundNew(false), _foundNew(false),
_removeOld(false), _removeOld(false),
_dontMove(false), // assume we'll be moving
_changeTime(usecTimestampNow()), _changeTime(usecTimestampNow()),
_oldEntityCube(), _oldEntityCube(),
_newEntityCube() _newEntityCube()
@ -42,6 +43,10 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
if (wantDebug) { if (wantDebug) {
qDebug() << "UpdateEntityOperator...."; qDebug() << "UpdateEntityOperator....";
qDebug() << " _existingEntity=" << _existingEntity;
qDebug() << " _entityItemID=" << _entityItemID;
qDebug() << " _containingElement=" << _containingElement;
qDebug() << " _containingElement->getAACube()=" << _containingElement->getAACube();
qDebug() << " _oldEntityCube=" << _oldEntityCube; qDebug() << " _oldEntityCube=" << _oldEntityCube;
qDebug() << " _oldEntityBox=" << _oldEntityBox; qDebug() << " _oldEntityBox=" << _oldEntityBox;
qDebug() << " _existingEntity->getPosition()=" << _existingEntity->getPosition() * (float)TREE_SCALE << "in meters"; qDebug() << " _existingEntity->getPosition()=" << _existingEntity->getPosition() * (float)TREE_SCALE << "in meters";
@ -64,16 +69,30 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
// If our new properties don't have bounds details (no change to position, etc) or if this containing element would // 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 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 // be the same for both parts of the update
bool oldElementBestFit = _containingElement->bestFitBounds(_properties); 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);
}
if (wantDebug) { if (wantDebug) {
qDebug() << " _properties.containsBoundsProperties()=" << _properties.containsBoundsProperties();
qDebug() << " oldElementBestFit=" << oldElementBestFit; qDebug() << " oldElementBestFit=" << oldElementBestFit;
} }
if (!_properties.containsBoundsProperties() || oldElementBestFit) { // 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) {
_newEntityCube = _oldEntityCube;
_removeOld = true; // our properties are going to move us, so remember this for later processing
if (wantDebug) {
qDebug() << " old element is NOT the best element even though props not changing <<<<<";
}
} else if (!_properties.containsBoundsProperties() || oldElementBestFit) {
_foundOld = true; _foundOld = true;
_newEntityCube = _oldEntityCube; _newEntityCube = _oldEntityCube;
_dontMove = true;
if (wantDebug) { if (wantDebug) {
qDebug() << " old element is best element <<<<<"; qDebug() << " old element is best element <<<<<";
} }
@ -94,12 +113,37 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
qDebug() << " _newEntityCube=" << _newEntityCube; qDebug() << " _newEntityCube=" << _newEntityCube;
qDebug() << " _newEntityBox=" << _newEntityBox; qDebug() << " _newEntityBox=" << _newEntityBox;
qDebug() << " _removeOld=" << _removeOld; qDebug() << " _removeOld=" << _removeOld;
qDebug() << " _containingElement->bestFitBounds(_properties)=" << _containingElement->bestFitBounds(_properties);
qDebug() << " _containingElement->bestFitBounds(_oldEntityCube)=" << _containingElement->bestFitBounds(_oldEntityCube);
qDebug() << " _containingElement->bestFitBounds(_oldEntityBox)=" << _containingElement->bestFitBounds(_oldEntityBox);
qDebug() << " _containingElement->bestFitBounds(_newEntityCube)=" << _containingElement->bestFitBounds(_newEntityCube);
qDebug() << " _containingElement->bestFitBounds(_newEntityBox)=" << _containingElement->bestFitBounds(_newEntityBox);
qDebug() << "------------ UpdateEntityOperator -- BEFORE WE BEGIN: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ UpdateEntityOperator -- END the tree-------------";
} }
} }
UpdateEntityOperator::~UpdateEntityOperator() {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "~UpdateEntityOperator().... ";
qDebug() << "------------ ~UpdateEntityOperator -- AFTER WE'RE DONE: the tree[" << _tree << "] -------------";
_tree->dumpTree();
qDebug() << "------------ ~UpdateEntityOperator -- END the tree-------------";
}
}
// does this entity tree element contain the old entity // does this entity tree element contain the old entity
bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) { bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) {
bool elementContainsOldBox = element->getAACube().contains(_oldEntityBox);
// We've found cases where the old entity might be placed in an element that is not actually the best fit
// so when we're searching the tree for the old element, we use the known cube for the known containing element
bool elementContainsOldBox = element->getAACube().contains(_containingElementCube);
/* /*
bool elementContainsOldCube = element->getAACube().contains(_oldEntityCube); bool elementContainsOldCube = element->getAACube().contains(_oldEntityCube);
@ -177,6 +221,11 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
if (wantDebug) { if (wantDebug) {
qDebug() << " OLD BRANCH...."; qDebug() << " OLD BRANCH....";
qDebug() << " _dontMove=" << _dontMove;
qDebug() << " _removeOld=" << _removeOld;
qDebug() << " entityTreeElement == _containingElement=" << (entityTreeElement == _containingElement);
qDebug() << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox);
qDebug() << " _containingElement->bestFitBounds(_newEntityBox)=" << _containingElement->bestFitBounds(_newEntityBox);
} }
@ -223,6 +272,11 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
if (wantDebug) { if (wantDebug) {
qDebug() << " NEW BRANCH...."; qDebug() << " NEW BRANCH....";
qDebug() << " _dontMove=" << _dontMove;
qDebug() << " _removeOld=" << _removeOld;
qDebug() << " entityTreeElement == _containingElement=" << (entityTreeElement == _containingElement);
qDebug() << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox);
qDebug() << " _containingElement->bestFitBounds(_newEntityBox)=" << _containingElement->bestFitBounds(_newEntityBox);
} }
@ -231,9 +285,13 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
if (wantDebug) { if (wantDebug) {
qDebug() << " NEW BRANCH.... BEST FIT"; qDebug() << " NEW BRANCH.... BEST FIT";
qDebug() << " _dontMove=" << _dontMove;
qDebug() << " _removeOld=" << _removeOld;
qDebug() << " entityTreeElement == _containingElement=" << (entityTreeElement == _containingElement);
} }
// if we are the existing containing element, then we can just do the update of the entity properties // if we are the existing containing element, then we can just do the update of the entity properties
if (entityTreeElement == _containingElement) { if (entityTreeElement == _containingElement) {
assert(!_removeOld); // We shouldn't be in a remove old case and also be the new best fit assert(!_removeOld); // We shouldn't be in a remove old case and also be the new best fit
@ -246,6 +304,15 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
} else { } else {
// otherwise, this is an add case. // otherwise, this is an add case.
if (wantDebug) {
qDebug() << "UpdateEntityOperator()... UPDATING EXISTING ENTITY -- PLACE IN NEW ELEMENT";
qDebug() << " element=" << entityTreeElement;
qDebug() << " element cube=" << entityTreeElement->getAACube();
qDebug() << " existingEntity=" << _existingEntity;
qDebug() << " entityItemID=" << _entityItemID;
}
entityTreeElement->addEntityItem(_existingEntity); entityTreeElement->addEntityItem(_existingEntity);
_existingEntity->setProperties(_properties); // still need to update the properties! _existingEntity->setProperties(_properties); // still need to update the properties!
_tree->setContainingElement(_entityItemID, entityTreeElement); _tree->setContainingElement(_entityItemID, entityTreeElement);
@ -324,37 +391,38 @@ bool UpdateEntityOperator::PostRecursion(OctreeElement* element) {
} }
OctreeElement* UpdateEntityOperator::PossiblyCreateChildAt(OctreeElement* element, int childIndex) { OctreeElement* UpdateEntityOperator::PossiblyCreateChildAt(OctreeElement* element, int childIndex) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "UpdateEntityOperator::PossiblyCreateChildAt()...";
qDebug() << " element=" << element;
qDebug() << " element->getAACube()=" << element->getAACube();
qDebug() << " childIndex=" << childIndex;
bool subtreeContainsOld = subTreeContainsOldEntity(element);
bool subtreeContainsNew = subTreeContainsNewEntity(element);
qDebug() << " subtreeContainsOld=" << subtreeContainsOld;
qDebug() << " subtreeContainsNew=" << subtreeContainsNew;
qDebug() << " _foundOld=" << _foundOld;
qDebug() << " _foundNew=" << _foundNew;
qDebug() << " _removeOld=" << _removeOld;
qDebug() << " _containingElement=" << _containingElement;
qDebug() << " _containingElementCube=" << _containingElementCube;
qDebug() << " _properties.getPosition()=" << _properties.getPosition() << "in meters";
qDebug() << " _properties.getRadius()=" << _properties.getRadius() << "in meters";
qDebug() << " _newEntityCube=" << _newEntityCube;
qDebug() << " _newEntityBox=" << _newEntityBox;
}
// If we're getting called, it's because there was no child element at this index while recursing. // 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. // We only care if this happens while still searching for the new entity location.
// Check to see if // Check to see if
if (!_foundNew) { if (!_foundNew) {
bool wantDebug = false;
if (wantDebug) {
qDebug() << "UpdateEntityOperator::PossiblyCreateChildAt()...";
qDebug() << " element=" << element;
qDebug() << " element->getAACube()=" << element->getAACube();
qDebug() << " childIndex=" << childIndex;
bool subtreeContainsOld = subTreeContainsOldEntity(element);
bool subtreeContainsNew = subTreeContainsNewEntity(element);
qDebug() << " subtreeContainsOld=" << subtreeContainsOld;
qDebug() << " subtreeContainsNew=" << subtreeContainsNew;
qDebug() << " _foundOld=" << _foundOld;
qDebug() << " _foundNew=" << _foundNew;
qDebug() << " _removeOld=" << _removeOld;
qDebug() << " _containingElement=" << _containingElement;
qDebug() << " _containingElementCube=" << _containingElementCube;
qDebug() << " _properties.getPosition()=" << _properties.getPosition() << "in meters";
qDebug() << " _properties.getRadius()=" << _properties.getRadius() << "in meters";
qDebug() << " _newEntityCube=" << _newEntityCube;
qDebug() << " _newEntityBox=" << _newEntityBox;
}
float childElementScale = element->getScale() / 2.0f; // all of our children will be half our scale 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 // Note: because the entity's bounds might have been clamped to the domain. We want to check if the

View file

@ -16,6 +16,7 @@ class UpdateEntityOperator : public RecurseOctreeOperator {
public: public:
UpdateEntityOperator(EntityTree* tree, EntityTreeElement* containingElement, UpdateEntityOperator(EntityTree* tree, EntityTreeElement* containingElement,
EntityItem* existingEntity, const EntityItemProperties& properties); EntityItem* existingEntity, const EntityItemProperties& properties);
~UpdateEntityOperator();
virtual bool PreRecursion(OctreeElement* element); virtual bool PreRecursion(OctreeElement* element);
virtual bool PostRecursion(OctreeElement* element); virtual bool PostRecursion(OctreeElement* element);
@ -30,6 +31,7 @@ private:
bool _foundOld; bool _foundOld;
bool _foundNew; bool _foundNew;
bool _removeOld; bool _removeOld;
bool _dontMove;
quint64 _changeTime; quint64 _changeTime;
AACube _oldEntityCube; AACube _oldEntityCube;

View file

@ -1,7 +1,5 @@
// REQUIRED: // REQUIRED:
1) crash on rendering of element that flies off the domain???
2) Test file save load for case where two siblings have more than MTU amount of data. I wonder if the fact that file save 2) Test file save load for case where two siblings have more than MTU amount of data. I wonder if the fact that file save
doesn't include the extra exists bits will break something. doesn't include the extra exists bits will break something.
@ -9,15 +7,12 @@
4) test animation again... 4) test animation again...
5) PROP_VISIBLE
6) PROP_SCRIPT
7) some jutter with moving entities 7) some jutter with moving entities
-- I think this might only happen with lots of models in an element or in view -- I think this might only happen with lots of models in an element or in view
this may be related to issue 13 below this may be related to issue 13 below
8) Look into why non-changed octree cells are being resent when editing an entity 8) Look into why non-changed octree cells are being resent when editing an entity --
this is probably because we're marking the trees as dirty -- but we probably can not send entitys that haven't changed
9) Verify pruning logic... 9) Verify pruning logic...
The old code used the update loop to handle pruning elements from the tree - do we need this? The old code used the update loop to handle pruning elements from the tree - do we need this?
@ -27,11 +22,23 @@
11) quickly do some edits... then change domains... watch the entities continue to exist in new domain and move around. 11) quickly do some edits... then change domains... watch the entities continue to exist in new domain and move around.
-- verify this happens in old code, if so... move to "nice to have" -- verify this happens in old code, if so... move to "nice to have"
12) Double check operators for these problems:
MovingEntitiesOperator has these issues:
- does the same pruning/reallocating issue as the old UpdateEntityOperator
- doesn't used clamped boxes for best fit tests... so could be problematic
// NICE TO HAVE: // NICE TO HAVE:
why is _entityItems a pointer? why not just make it a member of EntityTreeElement....
1) EnterEntity/LeaveEntity JS messages 1) EnterEntity/LeaveEntity JS messages
2) PROP_VISIBLE
3) PROP_SCRIPT
2) update and verify all particle examples to use new entity features 2) update and verify all particle examples to use new entity features
3) implement support for requestedProperties in appendEntityData() that only include CHANGED properties for the viewer... 3) implement support for requestedProperties in appendEntityData() that only include CHANGED properties for the viewer...
@ -200,6 +207,13 @@
// -- 3) the containing element got pruned // -- 3) the containing element got pruned
// -- 4) the NEW branch is traversed and PossiblyCreateChildAt creates a new element -- THAT HAS SAME POINTER AS CONTAINING ELEMENT!!!! // -- 4) the NEW branch is traversed and PossiblyCreateChildAt creates a new element -- THAT HAS SAME POINTER AS CONTAINING ELEMENT!!!!
// -- 5) the logic for recursedelement == _containingElement gets confused // -- 5) the logic for recursedelement == _containingElement gets confused
// SOLVED -- 47) crash on rendering of element that flies off the domain
// -- root cause was an UpdateEntityOperator that left two copies of the entity in the tree
// this was caused by the original element that the entity was in (according to the server)
// was not actually the best fit. it's not clear how this happened, but we can protect
// against it in the update operator if it does happen again. This made update operator more robust.
// SOLVED -- 48) server and client definitley not adding entities to proper update lists on load... only on change...
---------------- properties ----------------- ---------------- properties -----------------
Base properties... Base properties...