mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 11:38:16 +02:00
more model to entity renaming, adding AABox:clamp() and AACube::clamp() fix AddEntity to support adding an entity that extends over bounds of universe
This commit is contained in:
parent
3c4f5f88d0
commit
780532bfd8
15 changed files with 365 additions and 209 deletions
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// EntityNodeData.h
|
||||
// assignment-client/src/models
|
||||
// assignment-client/src/entities
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 4/29/14
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -20,15 +20,15 @@ class EntityNodeData : public OctreeQueryNode {
|
|||
public:
|
||||
EntityNodeData() :
|
||||
OctreeQueryNode(),
|
||||
_lastDeletedEntitysSentAt(0) { };
|
||||
_lastDeletedEntitiesSentAt(0) { };
|
||||
|
||||
virtual PacketType getMyPacketType() const { return PacketTypeEntityData; }
|
||||
|
||||
quint64 getLastDeletedEntitysSentAt() const { return _lastDeletedEntitysSentAt; }
|
||||
void setLastDeletedEntitysSentAt(quint64 sentAt) { _lastDeletedEntitysSentAt = sentAt; }
|
||||
quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; }
|
||||
void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; }
|
||||
|
||||
private:
|
||||
quint64 _lastDeletedEntitysSentAt;
|
||||
quint64 _lastDeletedEntitiesSentAt;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityNodeData_h
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// EntityServer.cpp
|
||||
// assignment-client/src/models
|
||||
// assignment-client/src/entities
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 4/29/14
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -40,10 +40,10 @@ Octree* EntityServer::createTree() {
|
|||
}
|
||||
|
||||
void EntityServer::beforeRun() {
|
||||
QTimer* pruneDeletedEntitysTimer = new QTimer(this);
|
||||
connect(pruneDeletedEntitysTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntitys()));
|
||||
QTimer* pruneDeletedEntitiesTimer = new QTimer(this);
|
||||
connect(pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities()));
|
||||
const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second
|
||||
pruneDeletedEntitysTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS);
|
||||
pruneDeletedEntitiesTimer->start(PRUNE_DELETED_MODELS_INTERVAL_MSECS);
|
||||
}
|
||||
|
||||
void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) {
|
||||
|
@ -60,30 +60,30 @@ void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePo
|
|||
copyAt += sizeof(creatorTokenID);
|
||||
packetLength += sizeof(creatorTokenID);
|
||||
|
||||
// encode the model ID
|
||||
uint32_t modelID = newEntity.getID();
|
||||
memcpy(copyAt, &modelID, sizeof(modelID));
|
||||
copyAt += sizeof(modelID);
|
||||
packetLength += sizeof(modelID);
|
||||
// encode the entity ID
|
||||
uint32_t entityID = newEntity.getID();
|
||||
memcpy(copyAt, &entityID, sizeof(entityID));
|
||||
copyAt += sizeof(entityID);
|
||||
packetLength += sizeof(entityID);
|
||||
|
||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
||||
}
|
||||
|
||||
|
||||
// EntityServer will use the "special packets" to send list of recently deleted models
|
||||
// EntityServer will use the "special packets" to send list of recently deleted entities
|
||||
bool EntityServer::hasSpecialPacketToSend(const SharedNodePointer& node) {
|
||||
bool shouldSendDeletedEntitys = false;
|
||||
bool shouldSendDeletedEntities = false;
|
||||
|
||||
// check to see if any new models have been added since we last sent to this node...
|
||||
// check to see if any new entities have been added since we last sent to this node...
|
||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
quint64 deletedEntitysSentAt = nodeData->getLastDeletedEntitysSentAt();
|
||||
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||
|
||||
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
||||
shouldSendDeletedEntitys = tree->hasEntitysDeletedSince(deletedEntitysSentAt);
|
||||
shouldSendDeletedEntities = tree->hasEntitiesDeletedSince(deletedEntitiesSentAt);
|
||||
}
|
||||
|
||||
return shouldSendDeletedEntitys;
|
||||
return shouldSendDeletedEntities;
|
||||
}
|
||||
|
||||
int EntityServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) {
|
||||
|
@ -92,16 +92,16 @@ int EntityServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNo
|
|||
|
||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
quint64 deletedEntitysSentAt = nodeData->getLastDeletedEntitysSentAt();
|
||||
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||
quint64 deletePacketSentAt = usecTimestampNow();
|
||||
|
||||
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
||||
bool hasMoreToSend = true;
|
||||
|
||||
// TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 models?
|
||||
// TODO: is it possible to send too many of these packets? what if you deleted 1,000,000 entities?
|
||||
packetsSent = 0;
|
||||
while (hasMoreToSend) {
|
||||
hasMoreToSend = tree->encodeEntitysDeletedSince(queryNode->getSequenceNumber(), deletedEntitysSentAt,
|
||||
hasMoreToSend = tree->encodeEntitiesDeletedSince(queryNode->getSequenceNumber(), deletedEntitiesSentAt,
|
||||
outputBuffer, MAX_PACKET_SIZE, packetLength);
|
||||
|
||||
//qDebug() << "sending PacketType_MODEL_ERASE packetLength:" << packetLength;
|
||||
|
@ -111,30 +111,30 @@ int EntityServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNo
|
|||
packetsSent++;
|
||||
}
|
||||
|
||||
nodeData->setLastDeletedEntitysSentAt(deletePacketSentAt);
|
||||
nodeData->setLastDeletedEntitiesSentAt(deletePacketSentAt);
|
||||
}
|
||||
|
||||
// TODO: caller is expecting a packetLength, what if we send more than one packet??
|
||||
return packetLength;
|
||||
}
|
||||
|
||||
void EntityServer::pruneDeletedEntitys() {
|
||||
void EntityServer::pruneDeletedEntities() {
|
||||
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
||||
if (tree->hasAnyDeletedEntitys()) {
|
||||
if (tree->hasAnyDeletedEntities()) {
|
||||
|
||||
//qDebug() << "there are some deleted models to consider...";
|
||||
quint64 earliestLastDeletedEntitysSent = usecTimestampNow() + 1; // in the future
|
||||
//qDebug() << "there are some deleted entities to consider...";
|
||||
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
|
||||
foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
|
||||
if (otherNode->getLinkedData()) {
|
||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(otherNode->getLinkedData());
|
||||
quint64 nodeLastDeletedEntitysSentAt = nodeData->getLastDeletedEntitysSentAt();
|
||||
if (nodeLastDeletedEntitysSentAt < earliestLastDeletedEntitysSent) {
|
||||
earliestLastDeletedEntitysSent = nodeLastDeletedEntitysSentAt;
|
||||
quint64 nodeLastDeletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||
if (nodeLastDeletedEntitiesSentAt < earliestLastDeletedEntitiesSent) {
|
||||
earliestLastDeletedEntitiesSent = nodeLastDeletedEntitiesSentAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
//qDebug() << "earliestLastDeletedEntitysSent=" << earliestLastDeletedEntitysSent;
|
||||
tree->forgetEntitysDeletedBefore(earliestLastDeletedEntitysSent);
|
||||
//qDebug() << "earliestLastDeletedEntitiesSent=" << earliestLastDeletedEntitiesSent;
|
||||
tree->forgetEntitiesDeletedBefore(earliestLastDeletedEntitiesSent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// EntityServer.h
|
||||
// assignment-client/src/models
|
||||
// assignment-client/src/entities
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 4/29/14
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -18,7 +18,7 @@
|
|||
#include "EntityServerConsts.h"
|
||||
#include "EntityTree.h"
|
||||
|
||||
/// Handles assignments of type EntityServer - sending models to various clients.
|
||||
/// Handles assignments of type EntityServer - sending entities to various clients.
|
||||
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -43,7 +43,7 @@ public:
|
|||
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode);
|
||||
|
||||
public slots:
|
||||
void pruneDeletedEntitys();
|
||||
void pruneDeletedEntities();
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
|
@ -44,15 +44,15 @@ var originalProperties = {
|
|||
var positionDelta = { x: 0, y: 0, z: 0 };
|
||||
|
||||
|
||||
var modelID = Models.addModel(originalProperties);
|
||||
var entityID = Entities.addEntity(originalProperties);
|
||||
|
||||
function moveModel(deltaTime) {
|
||||
function moveEntity(deltaTime) {
|
||||
if (count >= moveUntil) {
|
||||
|
||||
// delete it...
|
||||
if (count == moveUntil) {
|
||||
print("calling Models.deleteModel()");
|
||||
Models.deleteModel(modelID);
|
||||
print("calling Entities.deleteEntity()");
|
||||
Entities.deleteEntity(entityID);
|
||||
}
|
||||
|
||||
// stop it...
|
||||
|
@ -68,7 +68,7 @@ function moveModel(deltaTime) {
|
|||
//print("count =" + count);
|
||||
count++;
|
||||
|
||||
//print("modelID.creatorTokenID = " + modelID.creatorTokenID);
|
||||
//print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
||||
|
||||
var newProperties = {
|
||||
position: {
|
||||
|
@ -81,13 +81,13 @@ function moveModel(deltaTime) {
|
|||
};
|
||||
|
||||
|
||||
//print("modelID = " + modelID);
|
||||
//print("entityID = " + entityID);
|
||||
//print("newProperties.position = " + newProperties.position.x + "," + newProperties.position.y+ "," + newProperties.position.z);
|
||||
|
||||
Models.editModel(modelID, newProperties);
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(moveModel);
|
||||
Script.update.connect(moveEntity);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// EntityTree.cpp
|
||||
// libraries/models/src
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -22,7 +22,7 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) {
|
|||
}
|
||||
|
||||
void EntityTree::eraseAllOctreeElements() {
|
||||
_modelToElementMap.clear();
|
||||
_entityToElementMap.clear();
|
||||
Octree::eraseAllOctreeElements();
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ private:
|
|||
bool _foundNew;
|
||||
quint64 _changeTime;
|
||||
|
||||
AACube _newEntityCube;
|
||||
AABox _newEntityBox;
|
||||
};
|
||||
|
||||
AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
||||
|
@ -81,16 +81,22 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
|||
_newEntity(newEntity),
|
||||
_foundNew(false),
|
||||
_changeTime(usecTimestampNow()),
|
||||
_newEntityCube()
|
||||
_newEntityBox()
|
||||
{
|
||||
// caller must have verified existence of newEntity
|
||||
assert(_newEntity);
|
||||
|
||||
_newEntityCube = _newEntity->getAACube();
|
||||
_newEntityBox = _newEntity->getAACube().clamp(0.0f, 1.0f);
|
||||
|
||||
qDebug() << "AddEntityOperator::AddEntityOperator() newEntity=" << newEntity;
|
||||
qDebug() << " _newEntityBox=" << _newEntityBox;
|
||||
}
|
||||
|
||||
bool AddEntityOperator::PreRecursion(OctreeElement* element) {
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
|
||||
qDebug() << "AddEntityOperator::PreRecursion() entityTreeElement=" << entityTreeElement;
|
||||
entityTreeElement->debugDump();
|
||||
|
||||
// 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
|
||||
|
@ -99,14 +105,25 @@ bool AddEntityOperator::PreRecursion(OctreeElement* element) {
|
|||
|
||||
bool keepSearching = false; // assume we don't need to search any more
|
||||
|
||||
// If we haven't yet found the new model, and this subTreeContains our new
|
||||
// model, then we need to keep searching.
|
||||
if (!_foundNew && element->getAACube().contains(_newEntityCube)) {
|
||||
// If we haven't yet found the new entity, and this subTreeContains our new
|
||||
// entity, then we need to keep searching.
|
||||
if (!_foundNew && element->getAACube().contains(_newEntityBox)) {
|
||||
|
||||
qDebug() << "this element contains the _newEntityBox..." << _newEntityBox;
|
||||
|
||||
// If this element is the best fit for the new entity properties, then add/or update it
|
||||
if (entityTreeElement->bestFitBounds(_newEntityCube)) {
|
||||
if (entityTreeElement->bestFitBounds(_newEntityBox)) {
|
||||
|
||||
qDebug() << "this element is the best fit for _newEntityBox..." << _newEntityBox;
|
||||
|
||||
|
||||
qDebug() << "calling entityTreeElement->addEntityItem(_newEntity);";
|
||||
entityTreeElement->addEntityItem(_newEntity);
|
||||
qDebug() << "calling setContainingElement();";
|
||||
_tree->setContainingElement(_newEntity->getEntityItemID(), entityTreeElement);
|
||||
qDebug() << "AddEntityOperator calling setContainingElement... new entityID=" << _newEntity->getEntityItemID();
|
||||
_tree->debugDumpMap();
|
||||
|
||||
_foundNew = true;
|
||||
keepSearching = false;
|
||||
} else {
|
||||
|
@ -120,12 +137,12 @@ bool AddEntityOperator::PreRecursion(OctreeElement* element) {
|
|||
bool AddEntityOperator::PostRecursion(OctreeElement* element) {
|
||||
// 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.
|
||||
// We might have two paths, one for the old model and one for the new model.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
bool keepSearching = !_foundNew;
|
||||
|
||||
// As we unwind, if we're in either of these two paths, we mark our element
|
||||
// as dirty.
|
||||
if ((_foundNew && element->getAACube().contains(_newEntityCube))) {
|
||||
if ((_foundNew && element->getAACube().contains(_newEntityBox))) {
|
||||
element->markWithChangedTime();
|
||||
}
|
||||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
|
@ -133,10 +150,10 @@ bool AddEntityOperator::PostRecursion(OctreeElement* element) {
|
|||
|
||||
OctreeElement* AddEntityOperator::PossiblyCreateChildAt(OctreeElement* 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 model location.
|
||||
// We only care if this happens while still searching for the new entity location.
|
||||
// Check to see if
|
||||
if (!_foundNew) {
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityCube);
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityBox);
|
||||
|
||||
if (childIndex == indexOfChildContainingNewEntity) {
|
||||
return element->addChildAtIndex(childIndex);
|
||||
|
@ -153,9 +170,12 @@ void EntityTree::addEntityItem(EntityItem* entityItem) {
|
|||
assert(containingElement == NULL); // don't call addEntityItem() on existing entity items
|
||||
|
||||
// Recurse the tree and store the entity in the correct tree element
|
||||
qDebug() << "about to call recurseTreeWithOperator(AddEntityOperator)...";
|
||||
AddEntityOperator theOperator(this, entityItem);
|
||||
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
qDebug() << "AFTER... about to call recurseTreeWithOperator(AddEntityOperator)...";
|
||||
debugDumpMap();
|
||||
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
|
@ -220,7 +240,7 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
|
|||
|
||||
}
|
||||
|
||||
// does this model tree element contain the old model
|
||||
// does this entity tree element contain the old entity
|
||||
bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) {
|
||||
return element->getAACube().contains(_oldEntityCube);
|
||||
}
|
||||
|
@ -236,33 +256,35 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* 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:
|
||||
// * We have not yet found the old model, and this branch contains our old model
|
||||
// * We have not yet found the new model, and this branch contains our new model
|
||||
// * We have not yet found the old entity, and this branch contains our old entity
|
||||
// * We have not yet found the new entity, and this branch contains our new entity
|
||||
//
|
||||
// Note: it's often the case that the branch in question contains both the old model
|
||||
// and the new model.
|
||||
// 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
|
||||
|
||||
// If we haven't yet found the old model, and this subTreeContains our old
|
||||
// model, then we need to keep searching.
|
||||
// If we haven't yet found the old entity, and this subTreeContains our old
|
||||
// entity, then we need to keep searching.
|
||||
if (!_foundOld && subTreeContainsOldEntity(element)) {
|
||||
|
||||
// If this is the element we're looking for, then ask it to remove the old model
|
||||
// If this is the element we're looking for, then ask it to remove the old entity
|
||||
// and we can stop searching.
|
||||
if (entityTreeElement == _containingElement) {
|
||||
|
||||
// If the containgElement IS NOT the best fit for the new model properties
|
||||
// If the containgElement IS NOT the best fit for the new entity properties
|
||||
// then we need to remove it, and the updateEntity below will store it in the
|
||||
// correct element.
|
||||
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
|
||||
// make sure to remove our entity to element map, because for
|
||||
// now we're not in that map
|
||||
if (!_foundNew) {
|
||||
_tree->setContainingElement(_entityItemID, NULL);
|
||||
qDebug() << "UpdateEntityOperator calling setContainingElement(NULL)... entityID=" << _entityItemID;
|
||||
_tree->debugDumpMap();
|
||||
}
|
||||
}
|
||||
_foundOld = true;
|
||||
|
@ -272,20 +294,20 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
|
|||
}
|
||||
}
|
||||
|
||||
// If we haven't yet found the new model, and this subTreeContains our new
|
||||
// model, then we need to keep searching.
|
||||
// If we haven't yet found the new entity, and this subTreeContains our new
|
||||
// entity, then we need to keep searching.
|
||||
if (!_foundNew && subTreeContainsNewEntity(element)) {
|
||||
|
||||
// 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!";
|
||||
//qDebug() << "UpdateEntityOperator::PreRecursion()... entity 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.
|
||||
// means we're still searching for our old entity and this branch
|
||||
// contains our old entity. In which case we want to keep searching.
|
||||
}
|
||||
} else {
|
||||
keepSearching = true;
|
||||
|
@ -298,7 +320,7 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
|
|||
bool UpdateEntityOperator::PostRecursion(OctreeElement* element) {
|
||||
// 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.
|
||||
// We might have two paths, one for the old model and one for the new model.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
bool keepSearching = !_foundOld || !_foundNew;
|
||||
|
||||
// As we unwind, if we're in either of these two paths, we mark our element
|
||||
|
@ -312,7 +334,7 @@ bool UpdateEntityOperator::PostRecursion(OctreeElement* element) {
|
|||
|
||||
OctreeElement* UpdateEntityOperator::PossiblyCreateChildAt(OctreeElement* 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 model location.
|
||||
// We only care if this happens while still searching for the new entity location.
|
||||
// Check to see if
|
||||
if (!_foundNew) {
|
||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityCube);
|
||||
|
@ -375,17 +397,17 @@ qDebug() << "EntityTree::addEntity()... result = EntityTypes::constructEntityIte
|
|||
|
||||
class EntityToDeleteDetails {
|
||||
public:
|
||||
const EntityItem* model;
|
||||
const EntityItem* entity;
|
||||
AACube cube;
|
||||
EntityTreeElement* containingElement;
|
||||
};
|
||||
|
||||
inline uint qHash(const EntityToDeleteDetails& a, uint seed) {
|
||||
return qHash(a.model->getEntityItemID(), seed);
|
||||
return qHash(a.entity->getEntityItemID(), seed);
|
||||
}
|
||||
|
||||
inline bool operator==(const EntityToDeleteDetails& a, const EntityToDeleteDetails& b) {
|
||||
return a.model->getEntityItemID() == b.model->getEntityItemID();
|
||||
return a.entity->getEntityItemID() == b.entity->getEntityItemID();
|
||||
}
|
||||
|
||||
class DeleteEntityOperator : public RecurseOctreeOperator {
|
||||
|
@ -397,11 +419,11 @@ public:
|
|||
virtual bool PostRecursion(OctreeElement* element);
|
||||
private:
|
||||
EntityTree* _tree;
|
||||
QSet<EntityToDeleteDetails> _modelsToDelete;
|
||||
QSet<EntityToDeleteDetails> _entitiesToDelete;
|
||||
quint64 _changeTime;
|
||||
int _foundCount;
|
||||
int _lookingCount;
|
||||
bool subTreeContainsSomeEntitysToDelete(OctreeElement* element);
|
||||
bool subTreeContainsSomeEntitiesToDelete(OctreeElement* element);
|
||||
};
|
||||
|
||||
DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID) :
|
||||
|
@ -422,33 +444,33 @@ DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree) :
|
|||
}
|
||||
|
||||
void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEntityID) {
|
||||
// check our tree, to determine if this model is known
|
||||
// check our tree, to determine if this entity is known
|
||||
EntityToDeleteDetails details;
|
||||
details.containingElement = _tree->getContainingElement(searchEntityID);
|
||||
|
||||
if (details.containingElement) {
|
||||
details.model = details.containingElement->getEntityWithEntityItemID(searchEntityID);
|
||||
if (!details.model) {
|
||||
details.entity = details.containingElement->getEntityWithEntityItemID(searchEntityID);
|
||||
if (!details.entity) {
|
||||
//assert(false);
|
||||
qDebug() << "that's UNEXPECTED, we got a _containingElement, but couldn't find the oldEntity!";
|
||||
} else {
|
||||
details.cube = details.model->getAACube();
|
||||
_modelsToDelete << details;
|
||||
details.cube = details.entity->getAACube();
|
||||
_entitiesToDelete << details;
|
||||
_lookingCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// does this model tree element contain the old model
|
||||
bool DeleteEntityOperator::subTreeContainsSomeEntitysToDelete(OctreeElement* element) {
|
||||
// does this entity tree element contain the old entity
|
||||
bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElement* element) {
|
||||
bool containsEntity = false;
|
||||
|
||||
// If we don't have an old model, then we don't contain the model, otherwise
|
||||
// If we don't have an old entity, then we don't contain the entity, otherwise
|
||||
// check the bounds
|
||||
if (_modelsToDelete.size() > 0) {
|
||||
if (_entitiesToDelete.size() > 0) {
|
||||
AACube elementCube = element->getAACube();
|
||||
foreach(const EntityToDeleteDetails& details, _modelsToDelete) {
|
||||
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
|
||||
if (elementCube.contains(details.cube)) {
|
||||
containsEntity = true;
|
||||
break; // if it contains at least one, we're good to go
|
||||
|
@ -459,39 +481,43 @@ bool DeleteEntityOperator::subTreeContainsSomeEntitysToDelete(OctreeElement* ele
|
|||
}
|
||||
|
||||
bool DeleteEntityOperator::PreRecursion(OctreeElement* element) {
|
||||
EntityTreeElement* modelTreeElement = 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
|
||||
// path of the tree. For this operation, we want to recurse the branch of the tree if
|
||||
// and of the following are true:
|
||||
// * We have not yet found the old model, and this branch contains our old model
|
||||
// * We have not yet found the new model, and this branch contains our new model
|
||||
// * We have not yet found the old entity, and this branch contains our old entity
|
||||
// * We have not yet found the new entity, and this branch contains our new entity
|
||||
//
|
||||
// Note: it's often the case that the branch in question contains both the old model
|
||||
// and the new model.
|
||||
// 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
|
||||
|
||||
// If we haven't yet found all the models, and this sub tree contains at least one of our
|
||||
// models, then we need to keep searching.
|
||||
if ((_foundCount < _lookingCount) && subTreeContainsSomeEntitysToDelete(element)) {
|
||||
// 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.
|
||||
if ((_foundCount < _lookingCount) && subTreeContainsSomeEntitiesToDelete(element)) {
|
||||
|
||||
// check against each of our search models
|
||||
foreach(const EntityToDeleteDetails& details, _modelsToDelete) {
|
||||
// check against each of our search entities
|
||||
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
|
||||
|
||||
// If this is the element we're looking for, then ask it to remove the old model
|
||||
// If this is the element we're looking for, then ask it to remove the old entity
|
||||
// and we can stop searching.
|
||||
if (modelTreeElement == details.containingElement) {
|
||||
if (entityTreeElement == details.containingElement) {
|
||||
|
||||
// This is a good place to delete it!!!
|
||||
EntityItemID entityItemID = details.model->getEntityItemID();
|
||||
modelTreeElement->removeEntityWithEntityItemID(entityItemID);
|
||||
EntityItemID entityItemID = details.entity->getEntityItemID();
|
||||
entityTreeElement->removeEntityWithEntityItemID(entityItemID);
|
||||
_tree->setContainingElement(entityItemID, NULL);
|
||||
|
||||
qDebug() << "DeleteEntityOperator calling setContainingElement(NULL)... entityID=" << entityItemID;
|
||||
_tree->debugDumpMap();
|
||||
|
||||
_foundCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't found all of our search for models, then keep looking
|
||||
// if we haven't found all of our search for entities, then keep looking
|
||||
keepSearching = (_foundCount < _lookingCount);
|
||||
}
|
||||
|
||||
|
@ -501,12 +527,12 @@ bool DeleteEntityOperator::PreRecursion(OctreeElement* element) {
|
|||
bool DeleteEntityOperator::PostRecursion(OctreeElement* element) {
|
||||
// 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.
|
||||
// We might have two paths, one for the old model and one for the new model.
|
||||
// We might have two paths, one for the old entity and one for the new entity.
|
||||
bool keepSearching = (_foundCount < _lookingCount);
|
||||
|
||||
// As we unwind, if we're in either of these two paths, we mark our element
|
||||
// as dirty.
|
||||
if ((subTreeContainsSomeEntitysToDelete(element))) {
|
||||
if ((subTreeContainsSomeEntitiesToDelete(element))) {
|
||||
element->markWithChangedTime();
|
||||
}
|
||||
return keepSearching; // if we haven't yet found it, keep looking
|
||||
|
@ -515,7 +541,7 @@ bool DeleteEntityOperator::PostRecursion(OctreeElement* element) {
|
|||
void EntityTree::deleteEntity(const EntityItemID& entityID) {
|
||||
// NOTE: callers must lock the tree before using this method
|
||||
|
||||
// First, look for the existing model in the tree..
|
||||
// First, look for the existing entity in the tree..
|
||||
DeleteEntityOperator theOperator(this, entityID);
|
||||
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
|
@ -528,12 +554,12 @@ void EntityTree::deleteEntity(const EntityItemID& entityID) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTree::deleteEntitys(QSet<EntityItemID> modelIDs) {
|
||||
void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs) {
|
||||
// NOTE: callers must lock the tree before using this method
|
||||
|
||||
DeleteEntityOperator theOperator(this);
|
||||
foreach(const EntityItemID& entityID, modelIDs) {
|
||||
// First, look for the existing model in the tree..
|
||||
foreach(const EntityItemID& entityID, entityIDs) {
|
||||
// First, look for the existing entity in the tree..
|
||||
theOperator.addEntityIDToDeleteList(entityID);
|
||||
}
|
||||
|
||||
|
@ -542,25 +568,25 @@ void EntityTree::deleteEntitys(QSet<EntityItemID> modelIDs) {
|
|||
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
foreach(const EntityItemID& entityID, modelIDs) {
|
||||
foreach(const EntityItemID& entityID, entityIDs) {
|
||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||
qDebug() << "EntityTree::storeEntity().... after store... containingElement=" << containingElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scans the tree and handles mapping locally created models to know IDs.
|
||||
// scans the tree and handles mapping locally created entities to know IDs.
|
||||
// in the event that this tree is also viewing the scene, then we need to also
|
||||
// search the tree to make sure we don't have a duplicate model from the viewing
|
||||
// search the tree to make sure we don't have a duplicate entity from the viewing
|
||||
// operation.
|
||||
bool EntityTree::findAndUpdateEntityItemIDOperation(OctreeElement* element, void* extraData) {
|
||||
bool keepSearching = true;
|
||||
|
||||
FindAndUpdateEntityItemIDArgs* args = static_cast<FindAndUpdateEntityItemIDArgs*>(extraData);
|
||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
|
||||
// Note: updateEntityItemID() will only operate on correctly found models
|
||||
modelTreeElement->updateEntityItemID(args);
|
||||
// Note: updateEntityItemID() will only operate on correctly found entities
|
||||
entityTreeElement->updateEntityItemID(args);
|
||||
|
||||
// if we've found and replaced both the creatorTokenID and the viewedEntity, then we
|
||||
// can stop looking, otherwise we will keep looking
|
||||
|
@ -595,8 +621,8 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) {
|
|||
qDebug() << " entityID=" << entityID;
|
||||
}
|
||||
|
||||
// update models in our tree
|
||||
bool assumeEntityFound = !getIsViewing(); // if we're not a viewing tree, then we don't have to find the actual model
|
||||
// update entities in our tree
|
||||
bool assumeEntityFound = !getIsViewing(); // if we're not a viewing tree, then we don't have to find the actual entity
|
||||
FindAndUpdateEntityItemIDArgs args = {
|
||||
entityID,
|
||||
creatorTokenID,
|
||||
|
@ -610,7 +636,7 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) {
|
|||
<< " getIsViewing()=" << getIsViewing();
|
||||
}
|
||||
lockForWrite();
|
||||
// TODO: Switch this to use list of known model IDs....
|
||||
// TODO: Switch this to use list of known entity IDs....
|
||||
recurseTreeWithOperation(findAndUpdateEntityItemIDOperation, &args);
|
||||
unlock();
|
||||
}
|
||||
|
@ -628,20 +654,20 @@ public:
|
|||
|
||||
bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData) {
|
||||
FindNearPointArgs* args = static_cast<FindNearPointArgs*>(extraData);
|
||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
|
||||
glm::vec3 penetration;
|
||||
bool sphereIntersection = modelTreeElement->getAACube().findSpherePenetration(args->position,
|
||||
bool sphereIntersection = entityTreeElement->getAACube().findSpherePenetration(args->position,
|
||||
args->targetRadius, penetration);
|
||||
|
||||
// If this modelTreeElement contains the point, then search it...
|
||||
// If this entityTreeElement contains the point, then search it...
|
||||
if (sphereIntersection) {
|
||||
const EntityItem* thisClosestEntity = modelTreeElement->getClosestEntity(args->position);
|
||||
const EntityItem* thisClosestEntity = entityTreeElement->getClosestEntity(args->position);
|
||||
|
||||
// we may have gotten NULL back, meaning no model was available
|
||||
// we may have gotten NULL back, meaning no entity was available
|
||||
if (thisClosestEntity) {
|
||||
glm::vec3 modelPosition = thisClosestEntity->getPosition();
|
||||
float distanceFromPointToEntity = glm::distance(modelPosition, args->position);
|
||||
glm::vec3 entityPosition = thisClosestEntity->getPosition();
|
||||
float distanceFromPointToEntity = glm::distance(entityPosition, args->position);
|
||||
|
||||
// If we're within our target radius
|
||||
if (distanceFromPointToEntity <= args->targetRadius) {
|
||||
|
@ -655,7 +681,7 @@ bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData)
|
|||
}
|
||||
|
||||
// we should be able to optimize this...
|
||||
return true; // keep searching in case children have closer models
|
||||
return true; // keep searching in case children have closer entities
|
||||
}
|
||||
|
||||
// if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
|
||||
|
@ -675,7 +701,7 @@ class FindAllNearPointArgs {
|
|||
public:
|
||||
glm::vec3 position;
|
||||
float targetRadius;
|
||||
QVector<const EntityItem*> models;
|
||||
QVector<const EntityItem*> entities;
|
||||
};
|
||||
|
||||
|
||||
|
@ -687,9 +713,9 @@ bool EntityTree::findInSphereOperation(OctreeElement* element, void* extraData)
|
|||
|
||||
// If this element contains the point, then search it...
|
||||
if (sphereIntersection) {
|
||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
modelTreeElement->getEntities(args->position, args->targetRadius, args->models);
|
||||
return true; // keep searching in case children have closer models
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
entityTreeElement->getEntities(args->position, args->targetRadius, args->entities);
|
||||
return true; // keep searching in case children have closer entities
|
||||
}
|
||||
|
||||
// if this element doesn't contain the point, then none of it's children can contain the point, so stop searching
|
||||
|
@ -697,46 +723,46 @@ bool EntityTree::findInSphereOperation(OctreeElement* element, void* extraData)
|
|||
}
|
||||
|
||||
// NOTE: assumes caller has handled locking
|
||||
void EntityTree::findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntitys) {
|
||||
void EntityTree::findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntities) {
|
||||
FindAllNearPointArgs args = { center, radius };
|
||||
// NOTE: This should use recursion, since this is a spatial operation
|
||||
recurseTreeWithOperation(findInSphereOperation, &args);
|
||||
|
||||
// swap the two lists of model pointers instead of copy
|
||||
foundEntitys.swap(args.models);
|
||||
// swap the two lists of entity pointers instead of copy
|
||||
foundEntities.swap(args.entities);
|
||||
}
|
||||
|
||||
class FindEntitysInCubeArgs {
|
||||
class FindEntitiesInCubeArgs {
|
||||
public:
|
||||
FindEntitysInCubeArgs(const AACube& cube)
|
||||
: _cube(cube), _foundEntitys() {
|
||||
FindEntitiesInCubeArgs(const AACube& cube)
|
||||
: _cube(cube), _foundEntities() {
|
||||
}
|
||||
|
||||
AACube _cube;
|
||||
QVector<EntityItem*> _foundEntitys;
|
||||
QVector<EntityItem*> _foundEntities;
|
||||
};
|
||||
|
||||
bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) {
|
||||
FindEntitysInCubeArgs* args = static_cast< FindEntitysInCubeArgs*>(extraData);
|
||||
FindEntitiesInCubeArgs* args = static_cast<FindEntitiesInCubeArgs*>(extraData);
|
||||
const AACube& elementCube = element->getAACube();
|
||||
if (elementCube.touches(args->_cube)) {
|
||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
modelTreeElement->getEntities(args->_cube, args->_foundEntitys);
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
entityTreeElement->getEntities(args->_cube, args->_foundEntities);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: assumes caller has handled locking
|
||||
void EntityTree::findEntities(const AACube& cube, QVector<EntityItem*> foundEntitys) {
|
||||
FindEntitysInCubeArgs args(cube);
|
||||
void EntityTree::findEntities(const AACube& cube, QVector<EntityItem*> foundEntities) {
|
||||
FindEntitiesInCubeArgs args(cube);
|
||||
// NOTE: This should use recursion, since this is a spatial operation
|
||||
recurseTreeWithOperation(findInCubeOperation, &args);
|
||||
// swap the two lists of model pointers instead of copy
|
||||
foundEntitys.swap(args._foundEntitys);
|
||||
// swap the two lists of entity pointers instead of copy
|
||||
foundEntities.swap(args._foundEntities);
|
||||
}
|
||||
|
||||
EntityItem* EntityTree::findEntityByID(uint32_t id, bool alreadyLocked) const {
|
||||
EntityItem* EntityTree::findEntityByID(uint32_t id, bool alreadyLocked) /*const*/ {
|
||||
EntityItemID entityID(id);
|
||||
|
||||
bool wantDebug = false;
|
||||
|
@ -744,13 +770,13 @@ EntityItem* EntityTree::findEntityByID(uint32_t id, bool alreadyLocked) const {
|
|||
qDebug() << "EntityTree::findEntityByID()...";
|
||||
qDebug() << " id=" << id;
|
||||
qDebug() << " entityID=" << entityID;
|
||||
qDebug() << "_modelToElementMap=" << _modelToElementMap;
|
||||
qDebug() << "_entityToElementMap=" << _entityToElementMap;
|
||||
}
|
||||
|
||||
return findEntityByEntityItemID(entityID);
|
||||
}
|
||||
|
||||
EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) const {
|
||||
EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /*const*/ {
|
||||
EntityItem* foundEntity = NULL;
|
||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||
if (containingElement) {
|
||||
|
@ -841,17 +867,17 @@ void EntityTree::removeNewlyCreatedHook(NewlyCreatedEntityHook* hook) {
|
|||
|
||||
bool EntityTree::updateOperation(OctreeElement* element, void* extraData) {
|
||||
EntityTreeUpdateArgs* args = static_cast<EntityTreeUpdateArgs*>(extraData);
|
||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
modelTreeElement->update(*args);
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
entityTreeElement->update(*args);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityTree::pruneOperation(OctreeElement* element, void* extraData) {
|
||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
EntityTreeElement* childAt = modelTreeElement->getChildAtIndex(i);
|
||||
EntityTreeElement* childAt = entityTreeElement->getChildAtIndex(i);
|
||||
if (childAt && childAt->isLeaf() && !childAt->hasEntities()) {
|
||||
modelTreeElement->deleteChildAtIndex(i);
|
||||
entityTreeElement->deleteChildAtIndex(i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -861,14 +887,14 @@ void EntityTree::update() {
|
|||
lockForWrite();
|
||||
_isDirty = true;
|
||||
|
||||
// TODO: could we manage this by iterating the known models map/hash? Would that be faster?
|
||||
// TODO: could we manage this by iterating the known entities map/hash? Would that be faster?
|
||||
EntityTreeUpdateArgs args;
|
||||
recurseTreeWithOperation(updateOperation, &args);
|
||||
|
||||
// now add back any of the particles that moved elements....
|
||||
int movingEntitys = args._movingEntities.size();
|
||||
int movingEntities = args._movingEntities.size();
|
||||
|
||||
for (int i = 0; i < movingEntitys; i++) {
|
||||
for (int i = 0; i < movingEntities; i++) {
|
||||
|
||||
// XXXBHG: replace storeEntity with new API!!
|
||||
qDebug() << "EntityTree::update().... NOT YET IMPLEMENTED!!!";
|
||||
|
@ -883,9 +909,9 @@ void EntityTree::update() {
|
|||
} else {
|
||||
uint32_t entityItemID = args._movingEntities[i]->getID();
|
||||
quint64 deletedAt = usecTimestampNow();
|
||||
_recentlyDeletedEntitysLock.lockForWrite();
|
||||
_recentlyDeletedEntitiesLock.lockForWrite();
|
||||
_recentlyDeletedEntityItemIDs.insert(deletedAt, entityItemID);
|
||||
_recentlyDeletedEntitysLock.unlock();
|
||||
_recentlyDeletedEntitiesLock.unlock();
|
||||
}
|
||||
#endif // 0 //////////////////////////////////////////////////////
|
||||
}
|
||||
|
@ -896,11 +922,11 @@ void EntityTree::update() {
|
|||
}
|
||||
|
||||
|
||||
bool EntityTree::hasEntitysDeletedSince(quint64 sinceTime) {
|
||||
bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) {
|
||||
// we can probably leverage the ordered nature of QMultiMap to do this quickly...
|
||||
bool hasSomethingNewer = false;
|
||||
|
||||
_recentlyDeletedEntitysLock.lockForRead();
|
||||
_recentlyDeletedEntitiesLock.lockForRead();
|
||||
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
||||
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||
//qDebug() << "considering... time/key:" << iterator.key();
|
||||
|
@ -910,12 +936,12 @@ bool EntityTree::hasEntitysDeletedSince(quint64 sinceTime) {
|
|||
}
|
||||
++iterator;
|
||||
}
|
||||
_recentlyDeletedEntitysLock.unlock();
|
||||
_recentlyDeletedEntitiesLock.unlock();
|
||||
return hasSomethingNewer;
|
||||
}
|
||||
|
||||
// sinceTime is an in/out parameter - it will be side effected with the last time sent out
|
||||
bool EntityTree::encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* outputBuffer,
|
||||
bool EntityTree::encodeEntitiesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime, unsigned char* outputBuffer,
|
||||
size_t maxLength, size_t& outputLength) {
|
||||
|
||||
bool hasMoreToSend = true;
|
||||
|
@ -951,9 +977,9 @@ bool EntityTree::encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber
|
|||
copyAt += sizeof(numberOfIds);
|
||||
outputLength += sizeof(numberOfIds);
|
||||
|
||||
// we keep a multi map of model IDs to timestamps, we only want to include the model IDs that have been
|
||||
// we keep a multi map of entity IDs to timestamps, we only want to include the entity IDs that have been
|
||||
// deleted since we last sent to this node
|
||||
_recentlyDeletedEntitysLock.lockForRead();
|
||||
_recentlyDeletedEntitiesLock.lockForRead();
|
||||
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
||||
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||
QList<uint32_t> values = _recentlyDeletedEntityItemIDs.values(iterator.key());
|
||||
|
@ -988,7 +1014,7 @@ bool EntityTree::encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber
|
|||
if (iterator == _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||
hasMoreToSend = false;
|
||||
}
|
||||
_recentlyDeletedEntitysLock.unlock();
|
||||
_recentlyDeletedEntitiesLock.unlock();
|
||||
|
||||
// replace the correct count for ids included
|
||||
memcpy(numberOfIDsAt, &numberOfIds, sizeof(numberOfIds));
|
||||
|
@ -997,11 +1023,11 @@ bool EntityTree::encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber
|
|||
|
||||
// called by the server when it knows all nodes have been sent deleted packets
|
||||
|
||||
void EntityTree::forgetEntitysDeletedBefore(quint64 sinceTime) {
|
||||
//qDebug() << "forgetEntitysDeletedBefore()";
|
||||
void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
|
||||
//qDebug() << "forgetEntitiesDeletedBefore()";
|
||||
QSet<quint64> keysToRemove;
|
||||
|
||||
_recentlyDeletedEntitysLock.lockForWrite();
|
||||
_recentlyDeletedEntitiesLock.lockForWrite();
|
||||
QMultiMap<quint64, uint32_t>::iterator iterator = _recentlyDeletedEntityItemIDs.begin();
|
||||
|
||||
// First find all the keys in the map that are older and need to be deleted
|
||||
|
@ -1018,7 +1044,7 @@ void EntityTree::forgetEntitysDeletedBefore(quint64 sinceTime) {
|
|||
_recentlyDeletedEntityItemIDs.remove(value);
|
||||
}
|
||||
|
||||
_recentlyDeletedEntitysLock.unlock();
|
||||
_recentlyDeletedEntitiesLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1041,7 +1067,7 @@ void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Shar
|
|||
processedBytes += sizeof(numberOfIds);
|
||||
|
||||
if (numberOfIds > 0) {
|
||||
QSet<EntityItemID> modelItemIDsToDelete;
|
||||
QSet<EntityItemID> entityItemIDsToDelete;
|
||||
|
||||
for (size_t i = 0; i < numberOfIds; i++) {
|
||||
if (processedBytes + sizeof(uint32_t) > packetLength) {
|
||||
|
@ -1054,19 +1080,22 @@ void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Shar
|
|||
processedBytes += sizeof(entityID);
|
||||
|
||||
EntityItemID entityItemID(entityID);
|
||||
modelItemIDsToDelete << entityItemID;
|
||||
entityItemIDsToDelete << entityItemID;
|
||||
}
|
||||
deleteEntitys(modelItemIDsToDelete);
|
||||
deleteEntities(entityItemIDsToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) const {
|
||||
//qDebug() << "_modelToElementMap=" << _modelToElementMap;
|
||||
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ {
|
||||
//qDebug() << "_entityToElementMap=" << _entityToElementMap;
|
||||
|
||||
qDebug() << "EntityTree::getContainingElement() entityItemID=" << entityItemID;
|
||||
debugDumpMap();
|
||||
|
||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
||||
if (_modelToElementMap.contains(entityItemID)) {
|
||||
return _modelToElementMap.value(entityItemID);
|
||||
if (_entityToElementMap.contains(entityItemID)) {
|
||||
return _entityToElementMap.value(entityItemID);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1074,21 +1103,23 @@ EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityIt
|
|||
void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
|
||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
||||
if (element) {
|
||||
_modelToElementMap[entityItemID] = element;
|
||||
_entityToElementMap[entityItemID] = element;
|
||||
} else {
|
||||
_modelToElementMap.remove(entityItemID);
|
||||
_entityToElementMap.remove(entityItemID);
|
||||
}
|
||||
|
||||
//qDebug() << "setContainingElement() entityItemID=" << entityItemID << "element=" << element;
|
||||
//qDebug() << "AFTER _modelToElementMap=" << _modelToElementMap;
|
||||
//qDebug() << "AFTER _entityToElementMap=" << _entityToElementMap;
|
||||
}
|
||||
|
||||
void EntityTree::debugDumpMap() {
|
||||
QHashIterator<EntityItemID, EntityTreeElement*> i(_modelToElementMap);
|
||||
qDebug() << "EntityTree::debugDumpMap() --------------------------";
|
||||
QHashIterator<EntityItemID, EntityTreeElement*> i(_entityToElementMap);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
qDebug() << i.key() << ": " << i.value();
|
||||
}
|
||||
qDebug() << "-----------------------------------------------------";
|
||||
}
|
||||
|
||||
class DebugOperator : public RecurseOctreeOperator {
|
||||
|
@ -1105,7 +1136,7 @@ bool DebugOperator::PreRecursion(OctreeElement* element) {
|
|||
}
|
||||
|
||||
void EntityTree::dumpTree() {
|
||||
// First, look for the existing model in the tree..
|
||||
// First, look for the existing entity in the tree..
|
||||
DebugOperator theOperator;
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// EntityTree.h
|
||||
// libraries/models/src
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -22,7 +22,7 @@ public:
|
|||
|
||||
class EntityItemFBXService {
|
||||
public:
|
||||
virtual const FBXGeometry* getGeometryForEntity(const EntityItem& modelItem) = 0;
|
||||
virtual const FBXGeometry* getGeometryForEntity(const EntityItem& entityItem) = 0;
|
||||
};
|
||||
|
||||
class EntityTree : public Octree {
|
||||
|
@ -54,49 +54,49 @@ public:
|
|||
EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
void addEntityItem(EntityItem* entityItem);
|
||||
EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
bool updateEntity(const EntityItemID& modelID, const EntityItemProperties& properties);
|
||||
bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
||||
// the old API
|
||||
void storeEntity(const EntityItem& model, const SharedNodePointer& senderNode = SharedNodePointer());
|
||||
//void updateEntity(const EntityItemID& modelID, const EntityItemProperties& properties);
|
||||
void deleteEntity(const EntityItemID& modelID);
|
||||
void deleteEntitys(QSet<EntityItemID> modelIDs);
|
||||
void storeEntity(const EntityItem& entity, const SharedNodePointer& senderNode = SharedNodePointer());
|
||||
//void updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
void deleteEntity(const EntityItemID& entityID);
|
||||
void deleteEntities(QSet<EntityItemID> entityIDs);
|
||||
const EntityItem* findClosestEntity(glm::vec3 position, float targetRadius);
|
||||
EntityItem* findEntityByID(uint32_t id, bool alreadyLocked = false) const;
|
||||
EntityItem* findEntityByEntityItemID(const EntityItemID& modelID) const;
|
||||
EntityItem* findEntityByID(uint32_t id, bool alreadyLocked = false) /*const*/;
|
||||
EntityItem* findEntityByEntityItemID(const EntityItemID& entityID) /*const*/;
|
||||
|
||||
/// finds all models that touch a sphere
|
||||
/// finds all entities that touch a sphere
|
||||
/// \param center the center of the sphere
|
||||
/// \param radius the radius of the sphere
|
||||
/// \param foundEntitys[out] vector of const EntityItem*
|
||||
/// \remark Side effect: any initial contents in foundEntitys will be lost
|
||||
void findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntitys);
|
||||
/// \param foundEntities[out] vector of const EntityItem*
|
||||
/// \remark Side effect: any initial contents in foundEntities will be lost
|
||||
void findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntities);
|
||||
|
||||
/// finds all models that touch a cube
|
||||
/// finds all entities that touch a cube
|
||||
/// \param cube the query cube
|
||||
/// \param foundEntitys[out] vector of non-const EntityItem*
|
||||
/// \remark Side effect: any initial contents in models will be lost
|
||||
void findEntities(const AACube& cube, QVector<EntityItem*> foundEntitys);
|
||||
/// \param foundEntities[out] vector of non-const EntityItem*
|
||||
/// \remark Side effect: any initial contents in entities will be lost
|
||||
void findEntities(const AACube& cube, QVector<EntityItem*> foundEntities);
|
||||
|
||||
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||
|
||||
bool hasAnyDeletedEntitys() const { return _recentlyDeletedEntityItemIDs.size() > 0; }
|
||||
bool hasEntitysDeletedSince(quint64 sinceTime);
|
||||
bool encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime,
|
||||
bool hasAnyDeletedEntities() const { return _recentlyDeletedEntityItemIDs.size() > 0; }
|
||||
bool hasEntitiesDeletedSince(quint64 sinceTime);
|
||||
bool encodeEntitiesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime,
|
||||
unsigned char* packetData, size_t maxLength, size_t& outputLength);
|
||||
void forgetEntitysDeletedBefore(quint64 sinceTime);
|
||||
void forgetEntitiesDeletedBefore(quint64 sinceTime);
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
void handleAddEntityResponse(const QByteArray& packet);
|
||||
|
||||
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
||||
const FBXGeometry* getGeometryForEntity(const EntityItem& modelItem) {
|
||||
return _fbxService ? _fbxService->getGeometryForEntity(modelItem) : NULL;
|
||||
const FBXGeometry* getGeometryForEntity(const EntityItem& entityItem) {
|
||||
return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL;
|
||||
}
|
||||
|
||||
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) const;
|
||||
EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/;
|
||||
void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||
void debugDumpMap();
|
||||
void dumpTree();
|
||||
|
@ -123,11 +123,11 @@ private:
|
|||
QReadWriteLock _newlyCreatedHooksLock;
|
||||
QVector<NewlyCreatedEntityHook*> _newlyCreatedHooks;
|
||||
|
||||
QReadWriteLock _recentlyDeletedEntitysLock;
|
||||
QReadWriteLock _recentlyDeletedEntitiesLock;
|
||||
QMultiMap<quint64, uint32_t> _recentlyDeletedEntityItemIDs;
|
||||
EntityItemFBXService* _fbxService;
|
||||
|
||||
QHash<EntityItemID, EntityTreeElement*> _modelToElementMap;
|
||||
QHash<EntityItemID, EntityTreeElement*> _entityToElementMap;
|
||||
};
|
||||
|
||||
#endif // hifi_EntityTree_h
|
||||
|
|
|
@ -198,6 +198,14 @@ bool EntityTreeElement::bestFitBounds(const AACube& bounds) const {
|
|||
return bestFitBounds(bounds.getMinimumPoint(), bounds.getMaximumPoint());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::containsBounds(const AABox& bounds) const {
|
||||
return containsBounds(bounds.getMinimumPoint(), bounds.getMaximumPoint());
|
||||
}
|
||||
|
||||
bool EntityTreeElement::bestFitBounds(const AABox& 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);
|
||||
|
@ -683,6 +691,9 @@ bool EntityTreeElement::collapseChildren() {
|
|||
|
||||
|
||||
void EntityTreeElement::debugDump() {
|
||||
qDebug() << "EntityTreeElement...";
|
||||
qDebug() << "entity count:" << _entityItems->size();
|
||||
qDebug() << "cube:" << getAACube();
|
||||
for (uint16_t i = 0; i < _entityItems->size(); i++) {
|
||||
EntityItem* entity = (*_entityItems)[i];
|
||||
entity->debugDump();
|
||||
|
|
|
@ -158,6 +158,9 @@ public:
|
|||
bool containsBounds(const AACube& bounds) const; // NOTE: units in tree units
|
||||
bool bestFitBounds(const AACube& bounds) const; // NOTE: units in tree units
|
||||
|
||||
bool containsBounds(const AABox& bounds) const; // NOTE: units in tree units
|
||||
bool bestFitBounds(const AABox& bounds) const; // NOTE: units in tree units
|
||||
|
||||
bool containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; // NOTE: units in tree units
|
||||
bool bestFitBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const; // NOTE: units in tree units
|
||||
|
||||
|
|
|
@ -1458,6 +1458,32 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu
|
|||
return child->getOrCreateChildElementContaining(cube);
|
||||
}
|
||||
|
||||
OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) {
|
||||
OctreeElement* child = NULL;
|
||||
|
||||
int childIndex = getMyChildContaining(box);
|
||||
|
||||
// If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level
|
||||
// is the correct level for this cube
|
||||
if (childIndex == CHILD_UNKNOWN) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// Now, check if we have a child at that location
|
||||
child = getChildAtIndex(childIndex);
|
||||
if (!child) {
|
||||
child = addChildAtIndex(childIndex);
|
||||
}
|
||||
|
||||
// if we've made a really small child, then go ahead and use that one.
|
||||
if (child->getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
|
||||
return child;
|
||||
}
|
||||
|
||||
// Now that we have the child to recurse down, let it answer the original question...
|
||||
return child->getOrCreateChildElementContaining(box);
|
||||
}
|
||||
|
||||
int OctreeElement::getMyChildContaining(const AACube& cube) const {
|
||||
float ourScale = getScale();
|
||||
float cubeScale = cube.getScale();
|
||||
|
@ -1483,6 +1509,31 @@ int OctreeElement::getMyChildContaining(const AACube& cube) const {
|
|||
return childIndexCubeMinimum; // either would do, they are the same
|
||||
}
|
||||
|
||||
int OctreeElement::getMyChildContaining(const AABox& box) const {
|
||||
float ourScale = getScale();
|
||||
float boxLargestScale = box.getLargestDimension();
|
||||
|
||||
// TODO: consider changing this to assert()
|
||||
if(boxLargestScale > ourScale) {
|
||||
qDebug("UNEXPECTED -- OctreeElement::getMyChildContaining() "
|
||||
"boxLargestScale=[%f] > ourScale=[%f] ", boxLargestScale, ourScale);
|
||||
}
|
||||
|
||||
// Determine which of our children the minimum and maximum corners of the cube live in...
|
||||
glm::vec3 cubeCornerMinimum = box.getCorner();
|
||||
glm::vec3 cubeCornerMaximum = box.calcTopFarLeft();
|
||||
|
||||
int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum);
|
||||
int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum);
|
||||
|
||||
// If the minimum and maximum corners of the cube are in two different children's cubes, then we are the containing element
|
||||
if (childIndexCubeMinimum != childIndexCubeMaximum) {
|
||||
return CHILD_UNKNOWN;
|
||||
}
|
||||
|
||||
return childIndexCubeMinimum; // either would do, they are the same
|
||||
}
|
||||
|
||||
int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {
|
||||
glm::vec3 ourCenter = _cube.calcCenter();
|
||||
int childIndex = CHILD_UNKNOWN;
|
||||
|
|
|
@ -237,7 +237,9 @@ public:
|
|||
|
||||
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
||||
OctreeElement* getOrCreateChildElementContaining(const AACube& box);
|
||||
OctreeElement* getOrCreateChildElementContaining(const AABox& box);
|
||||
int getMyChildContaining(const AACube& cube) const;
|
||||
int getMyChildContaining(const AABox& box) const;
|
||||
int getMyChildContainingPoint(const glm::vec3& point) const;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
#include "GeometryUtil.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
|
||||
AABox::AABox(const AACube& other) :
|
||||
_corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) {
|
||||
}
|
||||
|
||||
AABox::AABox(const glm::vec3& corner, float size) :
|
||||
_corner(corner), _scale(size, size, size) {
|
||||
};
|
||||
|
@ -443,3 +448,19 @@ BoxFace AABox::getOppositeFace(BoxFace face) {
|
|||
case MAX_Z_FACE: return MIN_Z_FACE;
|
||||
}
|
||||
}
|
||||
|
||||
AABox AABox::clamp(const glm::vec3& min, const glm::vec3& max) const {
|
||||
glm::vec3 clampedCorner = glm::clamp(_corner, min, max);
|
||||
glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);
|
||||
glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;
|
||||
|
||||
return AABox(clampedCorner, clampedScale);
|
||||
}
|
||||
|
||||
AABox AABox::clamp(float min, float max) const {
|
||||
glm::vec3 clampedCorner = glm::clamp(_corner, min, max);
|
||||
glm::vec3 clampedTopFarLeft = glm::clamp(calcTopFarLeft(), min, max);
|
||||
glm::vec3 clampedScale = clampedTopFarLeft - clampedCorner;
|
||||
|
||||
return AABox(clampedCorner, clampedScale);
|
||||
}
|
||||
|
|
|
@ -17,13 +17,17 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "BoxBase.h"
|
||||
#include "StreamUtils.h"
|
||||
|
||||
class AACube;
|
||||
|
||||
class AABox {
|
||||
|
||||
public:
|
||||
AABox(const AACube& other);
|
||||
AABox(const glm::vec3& corner, float size);
|
||||
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
|
||||
AABox();
|
||||
|
@ -38,6 +42,7 @@ public:
|
|||
const glm::vec3& getCorner() const { return _corner; }
|
||||
const glm::vec3& getScale() const { return _scale; }
|
||||
const glm::vec3& getDimensions() const { return _scale; }
|
||||
float getLargestDimension() const { return glm::max(_scale.x, glm::max(_scale.y, _scale.z)); }
|
||||
|
||||
glm::vec3 calcCenter() const;
|
||||
glm::vec3 calcTopFarLeft() const;
|
||||
|
@ -62,6 +67,9 @@ public:
|
|||
|
||||
bool isNull() const { return _scale == glm::vec3(0.0f, 0.0f, 0.0f); }
|
||||
|
||||
AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
|
||||
AABox clamp(float min, float max) const;
|
||||
|
||||
private:
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
|
||||
|
@ -77,4 +85,10 @@ inline bool operator==(const AABox& a, const AABox& b) {
|
|||
return a.getCorner() == b.getCorner() && a.getDimensions() == b.getDimensions();
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const AABox& box) {
|
||||
debug << "AABox[ (" << box.getCorner().x << "," << box.getCorner().y << "," << box.getCorner().z << " ) to ("
|
||||
<< box.calcTopFarLeft().x << "," << box.calcTopFarLeft().y << "," << box.calcTopFarLeft().z << ")]";
|
||||
return debug;
|
||||
}
|
||||
|
||||
#endif // hifi_AABox_h
|
||||
|
|
|
@ -433,3 +433,14 @@ BoxFace AACube::getOppositeFace(BoxFace face) {
|
|||
case MAX_Z_FACE: return MIN_Z_FACE;
|
||||
}
|
||||
}
|
||||
|
||||
AABox AACube::clamp(const glm::vec3& min, const glm::vec3& max) const {
|
||||
AABox temp(*this);
|
||||
return temp.clamp(min, max);
|
||||
}
|
||||
|
||||
AABox AACube::clamp(float min, float max) const {
|
||||
AABox temp(*this);
|
||||
return temp.clamp(min, max);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "BoxBase.h"
|
||||
|
||||
class AABox;
|
||||
|
@ -54,6 +56,9 @@ public:
|
|||
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;
|
||||
|
||||
AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
|
||||
AABox clamp(float min, float max) const;
|
||||
|
||||
private:
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
|
||||
|
@ -69,4 +74,11 @@ inline bool operator==(const AACube& a, const AACube& b) {
|
|||
return a.getCorner() == b.getCorner() && a.getScale() == b.getScale();
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const AACube& cube) {
|
||||
debug << "AACube[ (" << cube.getCorner().x << "," << cube.getCorner().y << "," << cube.getCorner().z << " ) to ("
|
||||
<< cube.calcTopFarLeft().x << "," << cube.calcTopFarLeft().y << "," << cube.calcTopFarLeft().z << ")]";
|
||||
return debug;
|
||||
}
|
||||
|
||||
|
||||
#endif // hifi_AACube_h
|
||||
|
|
|
@ -451,7 +451,7 @@ void EntityTests::entityTreeTests(bool verbose) {
|
|||
}
|
||||
|
||||
quint64 startDelete = usecTimestampNow();
|
||||
tree.deleteEntitys(entitiesToDelete);
|
||||
tree.deleteEntities(entitiesToDelete);
|
||||
quint64 endDelete = usecTimestampNow();
|
||||
totalElapsedDelete += (endDelete - startDelete);
|
||||
|
||||
|
|
Loading…
Reference in a new issue