mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:21: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
|
// EntityNodeData.h
|
||||||
// assignment-client/src/models
|
// assignment-client/src/entities
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 4/29/14
|
// Created by Brad Hefta-Gaub on 4/29/14
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
@ -20,15 +20,15 @@ class EntityNodeData : public OctreeQueryNode {
|
||||||
public:
|
public:
|
||||||
EntityNodeData() :
|
EntityNodeData() :
|
||||||
OctreeQueryNode(),
|
OctreeQueryNode(),
|
||||||
_lastDeletedEntitysSentAt(0) { };
|
_lastDeletedEntitiesSentAt(0) { };
|
||||||
|
|
||||||
virtual PacketType getMyPacketType() const { return PacketTypeEntityData; }
|
virtual PacketType getMyPacketType() const { return PacketTypeEntityData; }
|
||||||
|
|
||||||
quint64 getLastDeletedEntitysSentAt() const { return _lastDeletedEntitysSentAt; }
|
quint64 getLastDeletedEntitiesSentAt() const { return _lastDeletedEntitiesSentAt; }
|
||||||
void setLastDeletedEntitysSentAt(quint64 sentAt) { _lastDeletedEntitysSentAt = sentAt; }
|
void setLastDeletedEntitiesSentAt(quint64 sentAt) { _lastDeletedEntitiesSentAt = sentAt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint64 _lastDeletedEntitysSentAt;
|
quint64 _lastDeletedEntitiesSentAt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityNodeData_h
|
#endif // hifi_EntityNodeData_h
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// EntityServer.cpp
|
// EntityServer.cpp
|
||||||
// assignment-client/src/models
|
// assignment-client/src/entities
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 4/29/14
|
// Created by Brad Hefta-Gaub on 4/29/14
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
@ -40,10 +40,10 @@ Octree* EntityServer::createTree() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityServer::beforeRun() {
|
void EntityServer::beforeRun() {
|
||||||
QTimer* pruneDeletedEntitysTimer = new QTimer(this);
|
QTimer* pruneDeletedEntitiesTimer = new QTimer(this);
|
||||||
connect(pruneDeletedEntitysTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntitys()));
|
connect(pruneDeletedEntitiesTimer, SIGNAL(timeout()), this, SLOT(pruneDeletedEntities()));
|
||||||
const int PRUNE_DELETED_MODELS_INTERVAL_MSECS = 1 * 1000; // once every second
|
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) {
|
void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) {
|
||||||
|
@ -60,30 +60,30 @@ void EntityServer::entityCreated(const EntityItem& newEntity, const SharedNodePo
|
||||||
copyAt += sizeof(creatorTokenID);
|
copyAt += sizeof(creatorTokenID);
|
||||||
packetLength += sizeof(creatorTokenID);
|
packetLength += sizeof(creatorTokenID);
|
||||||
|
|
||||||
// encode the model ID
|
// encode the entity ID
|
||||||
uint32_t modelID = newEntity.getID();
|
uint32_t entityID = newEntity.getID();
|
||||||
memcpy(copyAt, &modelID, sizeof(modelID));
|
memcpy(copyAt, &entityID, sizeof(entityID));
|
||||||
copyAt += sizeof(modelID);
|
copyAt += sizeof(entityID);
|
||||||
packetLength += sizeof(modelID);
|
packetLength += sizeof(entityID);
|
||||||
|
|
||||||
NodeList::getInstance()->writeDatagram((char*) outputBuffer, packetLength, senderNode);
|
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 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());
|
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||||
if (nodeData) {
|
if (nodeData) {
|
||||||
quint64 deletedEntitysSentAt = nodeData->getLastDeletedEntitysSentAt();
|
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||||
|
|
||||||
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
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) {
|
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());
|
EntityNodeData* nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
|
||||||
if (nodeData) {
|
if (nodeData) {
|
||||||
quint64 deletedEntitysSentAt = nodeData->getLastDeletedEntitysSentAt();
|
quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||||
quint64 deletePacketSentAt = usecTimestampNow();
|
quint64 deletePacketSentAt = usecTimestampNow();
|
||||||
|
|
||||||
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
||||||
bool hasMoreToSend = true;
|
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;
|
packetsSent = 0;
|
||||||
while (hasMoreToSend) {
|
while (hasMoreToSend) {
|
||||||
hasMoreToSend = tree->encodeEntitysDeletedSince(queryNode->getSequenceNumber(), deletedEntitysSentAt,
|
hasMoreToSend = tree->encodeEntitiesDeletedSince(queryNode->getSequenceNumber(), deletedEntitiesSentAt,
|
||||||
outputBuffer, MAX_PACKET_SIZE, packetLength);
|
outputBuffer, MAX_PACKET_SIZE, packetLength);
|
||||||
|
|
||||||
//qDebug() << "sending PacketType_MODEL_ERASE packetLength:" << packetLength;
|
//qDebug() << "sending PacketType_MODEL_ERASE packetLength:" << packetLength;
|
||||||
|
@ -111,30 +111,30 @@ int EntityServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNo
|
||||||
packetsSent++;
|
packetsSent++;
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeData->setLastDeletedEntitysSentAt(deletePacketSentAt);
|
nodeData->setLastDeletedEntitiesSentAt(deletePacketSentAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: caller is expecting a packetLength, what if we send more than one packet??
|
// TODO: caller is expecting a packetLength, what if we send more than one packet??
|
||||||
return packetLength;
|
return packetLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityServer::pruneDeletedEntitys() {
|
void EntityServer::pruneDeletedEntities() {
|
||||||
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
EntityTree* tree = static_cast<EntityTree*>(_tree);
|
||||||
if (tree->hasAnyDeletedEntitys()) {
|
if (tree->hasAnyDeletedEntities()) {
|
||||||
|
|
||||||
//qDebug() << "there are some deleted models to consider...";
|
//qDebug() << "there are some deleted entities to consider...";
|
||||||
quint64 earliestLastDeletedEntitysSent = usecTimestampNow() + 1; // in the future
|
quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future
|
||||||
foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
|
foreach (const SharedNodePointer& otherNode, NodeList::getInstance()->getNodeHash()) {
|
||||||
if (otherNode->getLinkedData()) {
|
if (otherNode->getLinkedData()) {
|
||||||
EntityNodeData* nodeData = static_cast<EntityNodeData*>(otherNode->getLinkedData());
|
EntityNodeData* nodeData = static_cast<EntityNodeData*>(otherNode->getLinkedData());
|
||||||
quint64 nodeLastDeletedEntitysSentAt = nodeData->getLastDeletedEntitysSentAt();
|
quint64 nodeLastDeletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt();
|
||||||
if (nodeLastDeletedEntitysSentAt < earliestLastDeletedEntitysSent) {
|
if (nodeLastDeletedEntitiesSentAt < earliestLastDeletedEntitiesSent) {
|
||||||
earliestLastDeletedEntitysSent = nodeLastDeletedEntitysSentAt;
|
earliestLastDeletedEntitiesSent = nodeLastDeletedEntitiesSentAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//qDebug() << "earliestLastDeletedEntitysSent=" << earliestLastDeletedEntitysSent;
|
//qDebug() << "earliestLastDeletedEntitiesSent=" << earliestLastDeletedEntitiesSent;
|
||||||
tree->forgetEntitysDeletedBefore(earliestLastDeletedEntitysSent);
|
tree->forgetEntitiesDeletedBefore(earliestLastDeletedEntitiesSent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// EntityServer.h
|
// EntityServer.h
|
||||||
// assignment-client/src/models
|
// assignment-client/src/entities
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 4/29/14
|
// Created by Brad Hefta-Gaub on 4/29/14
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
#include "EntityServerConsts.h"
|
#include "EntityServerConsts.h"
|
||||||
#include "EntityTree.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 {
|
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -43,7 +43,7 @@ public:
|
||||||
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode);
|
virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void pruneDeletedEntitys();
|
void pruneDeletedEntities();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,15 +44,15 @@ var originalProperties = {
|
||||||
var positionDelta = { x: 0, y: 0, z: 0 };
|
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) {
|
if (count >= moveUntil) {
|
||||||
|
|
||||||
// delete it...
|
// delete it...
|
||||||
if (count == moveUntil) {
|
if (count == moveUntil) {
|
||||||
print("calling Models.deleteModel()");
|
print("calling Entities.deleteEntity()");
|
||||||
Models.deleteModel(modelID);
|
Entities.deleteEntity(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop it...
|
// stop it...
|
||||||
|
@ -68,7 +68,7 @@ function moveModel(deltaTime) {
|
||||||
//print("count =" + count);
|
//print("count =" + count);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
//print("modelID.creatorTokenID = " + modelID.creatorTokenID);
|
//print("entityID.creatorTokenID = " + entityID.creatorTokenID);
|
||||||
|
|
||||||
var newProperties = {
|
var newProperties = {
|
||||||
position: {
|
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);
|
//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
|
// 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
|
// EntityTree.cpp
|
||||||
// libraries/models/src
|
// libraries/entities/src
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
@ -22,7 +22,7 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::eraseAllOctreeElements() {
|
void EntityTree::eraseAllOctreeElements() {
|
||||||
_modelToElementMap.clear();
|
_entityToElementMap.clear();
|
||||||
Octree::eraseAllOctreeElements();
|
Octree::eraseAllOctreeElements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ private:
|
||||||
bool _foundNew;
|
bool _foundNew;
|
||||||
quint64 _changeTime;
|
quint64 _changeTime;
|
||||||
|
|
||||||
AACube _newEntityCube;
|
AABox _newEntityBox;
|
||||||
};
|
};
|
||||||
|
|
||||||
AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
||||||
|
@ -81,16 +81,22 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
||||||
_newEntity(newEntity),
|
_newEntity(newEntity),
|
||||||
_foundNew(false),
|
_foundNew(false),
|
||||||
_changeTime(usecTimestampNow()),
|
_changeTime(usecTimestampNow()),
|
||||||
_newEntityCube()
|
_newEntityBox()
|
||||||
{
|
{
|
||||||
// caller must have verified existence of newEntity
|
// caller must have verified existence of newEntity
|
||||||
assert(_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) {
|
bool AddEntityOperator::PreRecursion(OctreeElement* element) {
|
||||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(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
|
// 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
|
// 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
|
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
|
// If we haven't yet found the new entity, and this subTreeContains our new
|
||||||
// model, then we need to keep searching.
|
// entity, then we need to keep searching.
|
||||||
if (!_foundNew && element->getAACube().contains(_newEntityCube)) {
|
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 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);
|
entityTreeElement->addEntityItem(_newEntity);
|
||||||
|
qDebug() << "calling setContainingElement();";
|
||||||
_tree->setContainingElement(_newEntity->getEntityItemID(), entityTreeElement);
|
_tree->setContainingElement(_newEntity->getEntityItemID(), entityTreeElement);
|
||||||
|
qDebug() << "AddEntityOperator calling setContainingElement... new entityID=" << _newEntity->getEntityItemID();
|
||||||
|
_tree->debugDumpMap();
|
||||||
|
|
||||||
_foundNew = true;
|
_foundNew = true;
|
||||||
keepSearching = false;
|
keepSearching = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,12 +137,12 @@ bool AddEntityOperator::PreRecursion(OctreeElement* element) {
|
||||||
bool AddEntityOperator::PostRecursion(OctreeElement* element) {
|
bool AddEntityOperator::PostRecursion(OctreeElement* element) {
|
||||||
// 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 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;
|
bool keepSearching = !_foundNew;
|
||||||
|
|
||||||
// As we unwind, if we're in either of these two paths, we mark our element
|
// As we unwind, if we're in either of these two paths, we mark our element
|
||||||
// as dirty.
|
// as dirty.
|
||||||
if ((_foundNew && element->getAACube().contains(_newEntityCube))) {
|
if ((_foundNew && element->getAACube().contains(_newEntityBox))) {
|
||||||
element->markWithChangedTime();
|
element->markWithChangedTime();
|
||||||
}
|
}
|
||||||
return keepSearching; // if we haven't yet found it, keep looking
|
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) {
|
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.
|
// 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
|
// Check to see if
|
||||||
if (!_foundNew) {
|
if (!_foundNew) {
|
||||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityCube);
|
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityBox);
|
||||||
|
|
||||||
if (childIndex == indexOfChildContainingNewEntity) {
|
if (childIndex == indexOfChildContainingNewEntity) {
|
||||||
return element->addChildAtIndex(childIndex);
|
return element->addChildAtIndex(childIndex);
|
||||||
|
@ -153,9 +170,12 @@ void EntityTree::addEntityItem(EntityItem* entityItem) {
|
||||||
assert(containingElement == NULL); // don't call addEntityItem() on existing entity items
|
assert(containingElement == NULL); // don't call addEntityItem() on existing entity items
|
||||||
|
|
||||||
// Recurse the tree and store the entity in the correct tree element
|
// Recurse the tree and store the entity in the correct tree element
|
||||||
|
qDebug() << "about to call recurseTreeWithOperator(AddEntityOperator)...";
|
||||||
AddEntityOperator theOperator(this, entityItem);
|
AddEntityOperator theOperator(this, entityItem);
|
||||||
|
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
|
qDebug() << "AFTER... about to call recurseTreeWithOperator(AddEntityOperator)...";
|
||||||
|
debugDumpMap();
|
||||||
|
|
||||||
_isDirty = true;
|
_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) {
|
bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) {
|
||||||
return element->getAACube().contains(_oldEntityCube);
|
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
|
// 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
|
// path of the tree. For this operation, we want to recurse the branch of the tree if
|
||||||
// and of the following are true:
|
// 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 old entity, and this branch contains our old entity
|
||||||
// * We have not yet found the new model, and this branch contains our new model
|
// * 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
|
// Note: it's often the case that the branch in question contains both the old entity
|
||||||
// and the new model.
|
// and the new entity.
|
||||||
|
|
||||||
bool keepSearching = false; // assume we don't need to search any more
|
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
|
// If we haven't yet found the old entity, and this subTreeContains our old
|
||||||
// model, then we need to keep searching.
|
// entity, then we need to keep searching.
|
||||||
if (!_foundOld && subTreeContainsOldEntity(element)) {
|
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.
|
// and we can stop searching.
|
||||||
if (entityTreeElement == _containingElement) {
|
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
|
// then we need to remove it, and the updateEntity below will store it in the
|
||||||
// correct element.
|
// correct element.
|
||||||
if (_removeOld) {
|
if (_removeOld) {
|
||||||
entityTreeElement->removeEntityItem(_existingEntity); // NOTE: only removes the entity, doesn't delete it
|
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
|
// 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
|
// now we're not in that map
|
||||||
if (!_foundNew) {
|
if (!_foundNew) {
|
||||||
_tree->setContainingElement(_entityItemID, NULL);
|
_tree->setContainingElement(_entityItemID, NULL);
|
||||||
|
qDebug() << "UpdateEntityOperator calling setContainingElement(NULL)... entityID=" << _entityItemID;
|
||||||
|
_tree->debugDumpMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_foundOld = true;
|
_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
|
// If we haven't yet found the new entity, and this subTreeContains our new
|
||||||
// model, then we need to keep searching.
|
// entity, then we need to keep searching.
|
||||||
if (!_foundNew && subTreeContainsNewEntity(element)) {
|
if (!_foundNew && subTreeContainsNewEntity(element)) {
|
||||||
|
|
||||||
// If this element is the best fit for the new entity properties, then add/or update it
|
// If this element is the best fit for the new entity properties, then add/or update it
|
||||||
if (entityTreeElement->bestFitBounds(_newEntityCube)) {
|
if (entityTreeElement->bestFitBounds(_newEntityCube)) {
|
||||||
if (entityTreeElement->addOrUpdateEntity(_existingEntity, _properties)) {
|
if (entityTreeElement->addOrUpdateEntity(_existingEntity, _properties)) {
|
||||||
|
|
||||||
//qDebug() << "UpdateEntityOperator::PreRecursion()... model was updated!";
|
//qDebug() << "UpdateEntityOperator::PreRecursion()... entity was updated!";
|
||||||
_foundNew = true;
|
_foundNew = true;
|
||||||
// NOTE: don't change the keepSearching here, if it came in here
|
// 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
|
// 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
|
// means we're still searching for our old entity and this branch
|
||||||
// contains our old model. In which case we want to keep searching.
|
// contains our old entity. In which case we want to keep searching.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
keepSearching = true;
|
keepSearching = true;
|
||||||
|
@ -298,7 +320,7 @@ bool UpdateEntityOperator::PreRecursion(OctreeElement* element) {
|
||||||
bool UpdateEntityOperator::PostRecursion(OctreeElement* element) {
|
bool UpdateEntityOperator::PostRecursion(OctreeElement* element) {
|
||||||
// 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 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;
|
bool keepSearching = !_foundOld || !_foundNew;
|
||||||
|
|
||||||
// As we unwind, if we're in either of these two paths, we mark our element
|
// 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) {
|
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.
|
// 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
|
// Check to see if
|
||||||
if (!_foundNew) {
|
if (!_foundNew) {
|
||||||
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityCube);
|
int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityCube);
|
||||||
|
@ -375,17 +397,17 @@ qDebug() << "EntityTree::addEntity()... result = EntityTypes::constructEntityIte
|
||||||
|
|
||||||
class EntityToDeleteDetails {
|
class EntityToDeleteDetails {
|
||||||
public:
|
public:
|
||||||
const EntityItem* model;
|
const EntityItem* entity;
|
||||||
AACube cube;
|
AACube cube;
|
||||||
EntityTreeElement* containingElement;
|
EntityTreeElement* containingElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline uint qHash(const EntityToDeleteDetails& a, uint seed) {
|
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) {
|
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 {
|
class DeleteEntityOperator : public RecurseOctreeOperator {
|
||||||
|
@ -397,11 +419,11 @@ public:
|
||||||
virtual bool PostRecursion(OctreeElement* element);
|
virtual bool PostRecursion(OctreeElement* element);
|
||||||
private:
|
private:
|
||||||
EntityTree* _tree;
|
EntityTree* _tree;
|
||||||
QSet<EntityToDeleteDetails> _modelsToDelete;
|
QSet<EntityToDeleteDetails> _entitiesToDelete;
|
||||||
quint64 _changeTime;
|
quint64 _changeTime;
|
||||||
int _foundCount;
|
int _foundCount;
|
||||||
int _lookingCount;
|
int _lookingCount;
|
||||||
bool subTreeContainsSomeEntitysToDelete(OctreeElement* element);
|
bool subTreeContainsSomeEntitiesToDelete(OctreeElement* element);
|
||||||
};
|
};
|
||||||
|
|
||||||
DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID) :
|
DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID) :
|
||||||
|
@ -422,33 +444,33 @@ DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree) :
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEntityID) {
|
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;
|
EntityToDeleteDetails details;
|
||||||
details.containingElement = _tree->getContainingElement(searchEntityID);
|
details.containingElement = _tree->getContainingElement(searchEntityID);
|
||||||
|
|
||||||
if (details.containingElement) {
|
if (details.containingElement) {
|
||||||
details.model = details.containingElement->getEntityWithEntityItemID(searchEntityID);
|
details.entity = details.containingElement->getEntityWithEntityItemID(searchEntityID);
|
||||||
if (!details.model) {
|
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.model->getAACube();
|
details.cube = details.entity->getAACube();
|
||||||
_modelsToDelete << details;
|
_entitiesToDelete << details;
|
||||||
_lookingCount++;
|
_lookingCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// does this model tree element contain the old model
|
// does this entity tree element contain the old entity
|
||||||
bool DeleteEntityOperator::subTreeContainsSomeEntitysToDelete(OctreeElement* element) {
|
bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElement* element) {
|
||||||
bool containsEntity = false;
|
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
|
// check the bounds
|
||||||
if (_modelsToDelete.size() > 0) {
|
if (_entitiesToDelete.size() > 0) {
|
||||||
AACube elementCube = element->getAACube();
|
AACube elementCube = element->getAACube();
|
||||||
foreach(const EntityToDeleteDetails& details, _modelsToDelete) {
|
foreach(const EntityToDeleteDetails& details, _entitiesToDelete) {
|
||||||
if (elementCube.contains(details.cube)) {
|
if (elementCube.contains(details.cube)) {
|
||||||
containsEntity = true;
|
containsEntity = true;
|
||||||
break; // if it contains at least one, we're good to go
|
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) {
|
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
|
// 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
|
// path of the tree. For this operation, we want to recurse the branch of the tree if
|
||||||
// and of the following are true:
|
// 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 old entity, and this branch contains our old entity
|
||||||
// * We have not yet found the new model, and this branch contains our new model
|
// * 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
|
// Note: it's often the case that the branch in question contains both the old entity
|
||||||
// and the new model.
|
// and the new entity.
|
||||||
|
|
||||||
bool keepSearching = false; // assume we don't need to search any more
|
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
|
// If we haven't yet found all the entities, and this sub tree contains at least one of our
|
||||||
// models, then we need to keep searching.
|
// entities, then we need to keep searching.
|
||||||
if ((_foundCount < _lookingCount) && subTreeContainsSomeEntitysToDelete(element)) {
|
if ((_foundCount < _lookingCount) && subTreeContainsSomeEntitiesToDelete(element)) {
|
||||||
|
|
||||||
// check against each of our search models
|
// check against each of our search entities
|
||||||
foreach(const EntityToDeleteDetails& details, _modelsToDelete) {
|
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.
|
// and we can stop searching.
|
||||||
if (modelTreeElement == details.containingElement) {
|
if (entityTreeElement == details.containingElement) {
|
||||||
|
|
||||||
// This is a good place to delete it!!!
|
// This is a good place to delete it!!!
|
||||||
EntityItemID entityItemID = details.model->getEntityItemID();
|
EntityItemID entityItemID = details.entity->getEntityItemID();
|
||||||
modelTreeElement->removeEntityWithEntityItemID(entityItemID);
|
entityTreeElement->removeEntityWithEntityItemID(entityItemID);
|
||||||
_tree->setContainingElement(entityItemID, NULL);
|
_tree->setContainingElement(entityItemID, NULL);
|
||||||
|
|
||||||
|
qDebug() << "DeleteEntityOperator calling setContainingElement(NULL)... entityID=" << entityItemID;
|
||||||
|
_tree->debugDumpMap();
|
||||||
|
|
||||||
_foundCount++;
|
_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);
|
keepSearching = (_foundCount < _lookingCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,12 +527,12 @@ bool DeleteEntityOperator::PreRecursion(OctreeElement* element) {
|
||||||
bool DeleteEntityOperator::PostRecursion(OctreeElement* element) {
|
bool DeleteEntityOperator::PostRecursion(OctreeElement* element) {
|
||||||
// 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 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);
|
bool keepSearching = (_foundCount < _lookingCount);
|
||||||
|
|
||||||
// As we unwind, if we're in either of these two paths, we mark our element
|
// As we unwind, if we're in either of these two paths, we mark our element
|
||||||
// as dirty.
|
// as dirty.
|
||||||
if ((subTreeContainsSomeEntitysToDelete(element))) {
|
if ((subTreeContainsSomeEntitiesToDelete(element))) {
|
||||||
element->markWithChangedTime();
|
element->markWithChangedTime();
|
||||||
}
|
}
|
||||||
return keepSearching; // if we haven't yet found it, keep looking
|
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) {
|
void EntityTree::deleteEntity(const EntityItemID& entityID) {
|
||||||
// NOTE: callers must lock the tree before using this method
|
// 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);
|
DeleteEntityOperator theOperator(this, entityID);
|
||||||
|
|
||||||
recurseTreeWithOperator(&theOperator);
|
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
|
// NOTE: callers must lock the tree before using this method
|
||||||
|
|
||||||
DeleteEntityOperator theOperator(this);
|
DeleteEntityOperator theOperator(this);
|
||||||
foreach(const EntityItemID& entityID, modelIDs) {
|
foreach(const EntityItemID& entityID, entityIDs) {
|
||||||
// First, look for the existing model in the tree..
|
// First, look for the existing entity in the tree..
|
||||||
theOperator.addEntityIDToDeleteList(entityID);
|
theOperator.addEntityIDToDeleteList(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,25 +568,25 @@ void EntityTree::deleteEntitys(QSet<EntityItemID> modelIDs) {
|
||||||
|
|
||||||
bool wantDebug = false;
|
bool wantDebug = false;
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
foreach(const EntityItemID& entityID, modelIDs) {
|
foreach(const EntityItemID& entityID, entityIDs) {
|
||||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||||
qDebug() << "EntityTree::storeEntity().... after store... containingElement=" << containingElement;
|
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
|
// 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.
|
// operation.
|
||||||
bool EntityTree::findAndUpdateEntityItemIDOperation(OctreeElement* element, void* extraData) {
|
bool EntityTree::findAndUpdateEntityItemIDOperation(OctreeElement* element, void* extraData) {
|
||||||
bool keepSearching = true;
|
bool keepSearching = true;
|
||||||
|
|
||||||
FindAndUpdateEntityItemIDArgs* args = static_cast<FindAndUpdateEntityItemIDArgs*>(extraData);
|
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
|
// Note: updateEntityItemID() will only operate on correctly found entities
|
||||||
modelTreeElement->updateEntityItemID(args);
|
entityTreeElement->updateEntityItemID(args);
|
||||||
|
|
||||||
// if we've found and replaced both the creatorTokenID and the viewedEntity, then we
|
// if we've found and replaced both the creatorTokenID and the viewedEntity, then we
|
||||||
// can stop looking, otherwise we will keep looking
|
// can stop looking, otherwise we will keep looking
|
||||||
|
@ -595,8 +621,8 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) {
|
||||||
qDebug() << " entityID=" << entityID;
|
qDebug() << " entityID=" << entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update models in our tree
|
// update entities in our tree
|
||||||
bool assumeEntityFound = !getIsViewing(); // if we're not a viewing tree, then we don't have to find the actual model
|
bool assumeEntityFound = !getIsViewing(); // if we're not a viewing tree, then we don't have to find the actual entity
|
||||||
FindAndUpdateEntityItemIDArgs args = {
|
FindAndUpdateEntityItemIDArgs args = {
|
||||||
entityID,
|
entityID,
|
||||||
creatorTokenID,
|
creatorTokenID,
|
||||||
|
@ -610,7 +636,7 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) {
|
||||||
<< " getIsViewing()=" << getIsViewing();
|
<< " getIsViewing()=" << getIsViewing();
|
||||||
}
|
}
|
||||||
lockForWrite();
|
lockForWrite();
|
||||||
// TODO: Switch this to use list of known model IDs....
|
// TODO: Switch this to use list of known entity IDs....
|
||||||
recurseTreeWithOperation(findAndUpdateEntityItemIDOperation, &args);
|
recurseTreeWithOperation(findAndUpdateEntityItemIDOperation, &args);
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
@ -628,20 +654,20 @@ public:
|
||||||
|
|
||||||
bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData) {
|
bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData) {
|
||||||
FindNearPointArgs* args = static_cast<FindNearPointArgs*>(extraData);
|
FindNearPointArgs* args = static_cast<FindNearPointArgs*>(extraData);
|
||||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||||
|
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
bool sphereIntersection = modelTreeElement->getAACube().findSpherePenetration(args->position,
|
bool sphereIntersection = entityTreeElement->getAACube().findSpherePenetration(args->position,
|
||||||
args->targetRadius, penetration);
|
args->targetRadius, penetration);
|
||||||
|
|
||||||
// If this modelTreeElement contains the point, then search it...
|
// If this entityTreeElement contains the point, then search it...
|
||||||
if (sphereIntersection) {
|
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) {
|
if (thisClosestEntity) {
|
||||||
glm::vec3 modelPosition = thisClosestEntity->getPosition();
|
glm::vec3 entityPosition = thisClosestEntity->getPosition();
|
||||||
float distanceFromPointToEntity = glm::distance(modelPosition, args->position);
|
float distanceFromPointToEntity = glm::distance(entityPosition, args->position);
|
||||||
|
|
||||||
// If we're within our target radius
|
// If we're within our target radius
|
||||||
if (distanceFromPointToEntity <= args->targetRadius) {
|
if (distanceFromPointToEntity <= args->targetRadius) {
|
||||||
|
@ -655,7 +681,7 @@ bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we should be able to optimize this...
|
// 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
|
// 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:
|
public:
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
float targetRadius;
|
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 this element contains the point, then search it...
|
||||||
if (sphereIntersection) {
|
if (sphereIntersection) {
|
||||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||||
modelTreeElement->getEntities(args->position, args->targetRadius, args->models);
|
entityTreeElement->getEntities(args->position, args->targetRadius, args->entities);
|
||||||
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
|
// 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
|
// 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 };
|
FindAllNearPointArgs args = { center, radius };
|
||||||
// NOTE: This should use recursion, since this is a spatial operation
|
// NOTE: This should use recursion, since this is a spatial operation
|
||||||
recurseTreeWithOperation(findInSphereOperation, &args);
|
recurseTreeWithOperation(findInSphereOperation, &args);
|
||||||
|
|
||||||
// swap the two lists of model pointers instead of copy
|
// swap the two lists of entity pointers instead of copy
|
||||||
foundEntitys.swap(args.models);
|
foundEntities.swap(args.entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FindEntitysInCubeArgs {
|
class FindEntitiesInCubeArgs {
|
||||||
public:
|
public:
|
||||||
FindEntitysInCubeArgs(const AACube& cube)
|
FindEntitiesInCubeArgs(const AACube& cube)
|
||||||
: _cube(cube), _foundEntitys() {
|
: _cube(cube), _foundEntities() {
|
||||||
}
|
}
|
||||||
|
|
||||||
AACube _cube;
|
AACube _cube;
|
||||||
QVector<EntityItem*> _foundEntitys;
|
QVector<EntityItem*> _foundEntities;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) {
|
bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) {
|
||||||
FindEntitysInCubeArgs* args = static_cast< FindEntitysInCubeArgs*>(extraData);
|
FindEntitiesInCubeArgs* args = static_cast<FindEntitiesInCubeArgs*>(extraData);
|
||||||
const AACube& elementCube = element->getAACube();
|
const AACube& elementCube = element->getAACube();
|
||||||
if (elementCube.touches(args->_cube)) {
|
if (elementCube.touches(args->_cube)) {
|
||||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||||
modelTreeElement->getEntities(args->_cube, args->_foundEntitys);
|
entityTreeElement->getEntities(args->_cube, args->_foundEntities);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: assumes caller has handled locking
|
// NOTE: assumes caller has handled locking
|
||||||
void EntityTree::findEntities(const AACube& cube, QVector<EntityItem*> foundEntitys) {
|
void EntityTree::findEntities(const AACube& cube, QVector<EntityItem*> foundEntities) {
|
||||||
FindEntitysInCubeArgs args(cube);
|
FindEntitiesInCubeArgs args(cube);
|
||||||
// NOTE: This should use recursion, since this is a spatial operation
|
// NOTE: This should use recursion, since this is a spatial operation
|
||||||
recurseTreeWithOperation(findInCubeOperation, &args);
|
recurseTreeWithOperation(findInCubeOperation, &args);
|
||||||
// swap the two lists of model pointers instead of copy
|
// swap the two lists of entity pointers instead of copy
|
||||||
foundEntitys.swap(args._foundEntitys);
|
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);
|
EntityItemID entityID(id);
|
||||||
|
|
||||||
bool wantDebug = false;
|
bool wantDebug = false;
|
||||||
|
@ -744,13 +770,13 @@ EntityItem* EntityTree::findEntityByID(uint32_t id, bool alreadyLocked) const {
|
||||||
qDebug() << "EntityTree::findEntityByID()...";
|
qDebug() << "EntityTree::findEntityByID()...";
|
||||||
qDebug() << " id=" << id;
|
qDebug() << " id=" << id;
|
||||||
qDebug() << " entityID=" << entityID;
|
qDebug() << " entityID=" << entityID;
|
||||||
qDebug() << "_modelToElementMap=" << _modelToElementMap;
|
qDebug() << "_entityToElementMap=" << _entityToElementMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
return findEntityByEntityItemID(entityID);
|
return findEntityByEntityItemID(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) const {
|
EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /*const*/ {
|
||||||
EntityItem* foundEntity = NULL;
|
EntityItem* foundEntity = NULL;
|
||||||
EntityTreeElement* containingElement = getContainingElement(entityID);
|
EntityTreeElement* containingElement = getContainingElement(entityID);
|
||||||
if (containingElement) {
|
if (containingElement) {
|
||||||
|
@ -841,17 +867,17 @@ void EntityTree::removeNewlyCreatedHook(NewlyCreatedEntityHook* hook) {
|
||||||
|
|
||||||
bool EntityTree::updateOperation(OctreeElement* element, void* extraData) {
|
bool EntityTree::updateOperation(OctreeElement* element, void* extraData) {
|
||||||
EntityTreeUpdateArgs* args = static_cast<EntityTreeUpdateArgs*>(extraData);
|
EntityTreeUpdateArgs* args = static_cast<EntityTreeUpdateArgs*>(extraData);
|
||||||
EntityTreeElement* modelTreeElement = static_cast<EntityTreeElement*>(element);
|
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||||
modelTreeElement->update(*args);
|
entityTreeElement->update(*args);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityTree::pruneOperation(OctreeElement* element, void* extraData) {
|
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++) {
|
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()) {
|
if (childAt && childAt->isLeaf() && !childAt->hasEntities()) {
|
||||||
modelTreeElement->deleteChildAtIndex(i);
|
entityTreeElement->deleteChildAtIndex(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -861,14 +887,14 @@ void EntityTree::update() {
|
||||||
lockForWrite();
|
lockForWrite();
|
||||||
_isDirty = true;
|
_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;
|
EntityTreeUpdateArgs args;
|
||||||
recurseTreeWithOperation(updateOperation, &args);
|
recurseTreeWithOperation(updateOperation, &args);
|
||||||
|
|
||||||
// now add back any of the particles that moved elements....
|
// 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!!
|
// XXXBHG: replace storeEntity with new API!!
|
||||||
qDebug() << "EntityTree::update().... NOT YET IMPLEMENTED!!!";
|
qDebug() << "EntityTree::update().... NOT YET IMPLEMENTED!!!";
|
||||||
|
@ -883,9 +909,9 @@ void EntityTree::update() {
|
||||||
} else {
|
} else {
|
||||||
uint32_t entityItemID = args._movingEntities[i]->getID();
|
uint32_t entityItemID = args._movingEntities[i]->getID();
|
||||||
quint64 deletedAt = usecTimestampNow();
|
quint64 deletedAt = usecTimestampNow();
|
||||||
_recentlyDeletedEntitysLock.lockForWrite();
|
_recentlyDeletedEntitiesLock.lockForWrite();
|
||||||
_recentlyDeletedEntityItemIDs.insert(deletedAt, entityItemID);
|
_recentlyDeletedEntityItemIDs.insert(deletedAt, entityItemID);
|
||||||
_recentlyDeletedEntitysLock.unlock();
|
_recentlyDeletedEntitiesLock.unlock();
|
||||||
}
|
}
|
||||||
#endif // 0 //////////////////////////////////////////////////////
|
#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...
|
// we can probably leverage the ordered nature of QMultiMap to do this quickly...
|
||||||
bool hasSomethingNewer = false;
|
bool hasSomethingNewer = false;
|
||||||
|
|
||||||
_recentlyDeletedEntitysLock.lockForRead();
|
_recentlyDeletedEntitiesLock.lockForRead();
|
||||||
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
||||||
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||||
//qDebug() << "considering... time/key:" << iterator.key();
|
//qDebug() << "considering... time/key:" << iterator.key();
|
||||||
|
@ -910,12 +936,12 @@ bool EntityTree::hasEntitysDeletedSince(quint64 sinceTime) {
|
||||||
}
|
}
|
||||||
++iterator;
|
++iterator;
|
||||||
}
|
}
|
||||||
_recentlyDeletedEntitysLock.unlock();
|
_recentlyDeletedEntitiesLock.unlock();
|
||||||
return hasSomethingNewer;
|
return hasSomethingNewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sinceTime is an in/out parameter - it will be side effected with the last time sent out
|
// 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) {
|
size_t maxLength, size_t& outputLength) {
|
||||||
|
|
||||||
bool hasMoreToSend = true;
|
bool hasMoreToSend = true;
|
||||||
|
@ -951,9 +977,9 @@ bool EntityTree::encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber
|
||||||
copyAt += sizeof(numberOfIds);
|
copyAt += sizeof(numberOfIds);
|
||||||
outputLength += 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
|
// deleted since we last sent to this node
|
||||||
_recentlyDeletedEntitysLock.lockForRead();
|
_recentlyDeletedEntitiesLock.lockForRead();
|
||||||
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
QMultiMap<quint64, uint32_t>::const_iterator iterator = _recentlyDeletedEntityItemIDs.constBegin();
|
||||||
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
while (iterator != _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||||
QList<uint32_t> values = _recentlyDeletedEntityItemIDs.values(iterator.key());
|
QList<uint32_t> values = _recentlyDeletedEntityItemIDs.values(iterator.key());
|
||||||
|
@ -988,7 +1014,7 @@ bool EntityTree::encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber
|
||||||
if (iterator == _recentlyDeletedEntityItemIDs.constEnd()) {
|
if (iterator == _recentlyDeletedEntityItemIDs.constEnd()) {
|
||||||
hasMoreToSend = false;
|
hasMoreToSend = false;
|
||||||
}
|
}
|
||||||
_recentlyDeletedEntitysLock.unlock();
|
_recentlyDeletedEntitiesLock.unlock();
|
||||||
|
|
||||||
// replace the correct count for ids included
|
// replace the correct count for ids included
|
||||||
memcpy(numberOfIDsAt, &numberOfIds, sizeof(numberOfIds));
|
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
|
// called by the server when it knows all nodes have been sent deleted packets
|
||||||
|
|
||||||
void EntityTree::forgetEntitysDeletedBefore(quint64 sinceTime) {
|
void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
|
||||||
//qDebug() << "forgetEntitysDeletedBefore()";
|
//qDebug() << "forgetEntitiesDeletedBefore()";
|
||||||
QSet<quint64> keysToRemove;
|
QSet<quint64> keysToRemove;
|
||||||
|
|
||||||
_recentlyDeletedEntitysLock.lockForWrite();
|
_recentlyDeletedEntitiesLock.lockForWrite();
|
||||||
QMultiMap<quint64, uint32_t>::iterator iterator = _recentlyDeletedEntityItemIDs.begin();
|
QMultiMap<quint64, uint32_t>::iterator iterator = _recentlyDeletedEntityItemIDs.begin();
|
||||||
|
|
||||||
// First find all the keys in the map that are older and need to be deleted
|
// 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);
|
_recentlyDeletedEntityItemIDs.remove(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_recentlyDeletedEntitysLock.unlock();
|
_recentlyDeletedEntitiesLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1041,7 +1067,7 @@ void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Shar
|
||||||
processedBytes += sizeof(numberOfIds);
|
processedBytes += sizeof(numberOfIds);
|
||||||
|
|
||||||
if (numberOfIds > 0) {
|
if (numberOfIds > 0) {
|
||||||
QSet<EntityItemID> modelItemIDsToDelete;
|
QSet<EntityItemID> entityItemIDsToDelete;
|
||||||
|
|
||||||
for (size_t i = 0; i < numberOfIds; i++) {
|
for (size_t i = 0; i < numberOfIds; i++) {
|
||||||
if (processedBytes + sizeof(uint32_t) > packetLength) {
|
if (processedBytes + sizeof(uint32_t) > packetLength) {
|
||||||
|
@ -1054,19 +1080,22 @@ void EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Shar
|
||||||
processedBytes += sizeof(entityID);
|
processedBytes += sizeof(entityID);
|
||||||
|
|
||||||
EntityItemID entityItemID(entityID);
|
EntityItemID entityItemID(entityID);
|
||||||
modelItemIDsToDelete << entityItemID;
|
entityItemIDsToDelete << entityItemID;
|
||||||
}
|
}
|
||||||
deleteEntitys(modelItemIDsToDelete);
|
deleteEntities(entityItemIDsToDelete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) const {
|
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ {
|
||||||
//qDebug() << "_modelToElementMap=" << _modelToElementMap;
|
//qDebug() << "_entityToElementMap=" << _entityToElementMap;
|
||||||
|
|
||||||
|
qDebug() << "EntityTree::getContainingElement() entityItemID=" << entityItemID;
|
||||||
|
debugDumpMap();
|
||||||
|
|
||||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
||||||
if (_modelToElementMap.contains(entityItemID)) {
|
if (_entityToElementMap.contains(entityItemID)) {
|
||||||
return _modelToElementMap.value(entityItemID);
|
return _entityToElementMap.value(entityItemID);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1074,21 +1103,23 @@ EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityIt
|
||||||
void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
|
void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) {
|
||||||
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
// TODO: do we need to make this thread safe? Or is it acceptable as is
|
||||||
if (element) {
|
if (element) {
|
||||||
_modelToElementMap[entityItemID] = element;
|
_entityToElementMap[entityItemID] = element;
|
||||||
} else {
|
} else {
|
||||||
_modelToElementMap.remove(entityItemID);
|
_entityToElementMap.remove(entityItemID);
|
||||||
}
|
}
|
||||||
|
|
||||||
//qDebug() << "setContainingElement() entityItemID=" << entityItemID << "element=" << element;
|
//qDebug() << "setContainingElement() entityItemID=" << entityItemID << "element=" << element;
|
||||||
//qDebug() << "AFTER _modelToElementMap=" << _modelToElementMap;
|
//qDebug() << "AFTER _entityToElementMap=" << _entityToElementMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::debugDumpMap() {
|
void EntityTree::debugDumpMap() {
|
||||||
QHashIterator<EntityItemID, EntityTreeElement*> i(_modelToElementMap);
|
qDebug() << "EntityTree::debugDumpMap() --------------------------";
|
||||||
|
QHashIterator<EntityItemID, EntityTreeElement*> i(_entityToElementMap);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
i.next();
|
i.next();
|
||||||
qDebug() << i.key() << ": " << i.value();
|
qDebug() << i.key() << ": " << i.value();
|
||||||
}
|
}
|
||||||
|
qDebug() << "-----------------------------------------------------";
|
||||||
}
|
}
|
||||||
|
|
||||||
class DebugOperator : public RecurseOctreeOperator {
|
class DebugOperator : public RecurseOctreeOperator {
|
||||||
|
@ -1105,7 +1136,7 @@ bool DebugOperator::PreRecursion(OctreeElement* element) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::dumpTree() {
|
void EntityTree::dumpTree() {
|
||||||
// First, look for the existing model in the tree..
|
// First, look for the existing entity in the tree..
|
||||||
DebugOperator theOperator;
|
DebugOperator theOperator;
|
||||||
recurseTreeWithOperator(&theOperator);
|
recurseTreeWithOperator(&theOperator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// EntityTree.h
|
// EntityTree.h
|
||||||
// libraries/models/src
|
// libraries/entities/src
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||||
// Copyright 2013 High Fidelity, Inc.
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
@ -22,7 +22,7 @@ public:
|
||||||
|
|
||||||
class EntityItemFBXService {
|
class EntityItemFBXService {
|
||||||
public:
|
public:
|
||||||
virtual const FBXGeometry* getGeometryForEntity(const EntityItem& modelItem) = 0;
|
virtual const FBXGeometry* getGeometryForEntity(const EntityItem& entityItem) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EntityTree : public Octree {
|
class EntityTree : public Octree {
|
||||||
|
@ -54,49 +54,49 @@ public:
|
||||||
EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties);
|
EntityItem* getOrCreateEntityItem(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
void addEntityItem(EntityItem* entityItem);
|
void addEntityItem(EntityItem* entityItem);
|
||||||
EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
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
|
// the old API
|
||||||
void storeEntity(const EntityItem& model, const SharedNodePointer& senderNode = SharedNodePointer());
|
void storeEntity(const EntityItem& entity, const SharedNodePointer& senderNode = SharedNodePointer());
|
||||||
//void updateEntity(const EntityItemID& modelID, const EntityItemProperties& properties);
|
//void updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
void deleteEntity(const EntityItemID& modelID);
|
void deleteEntity(const EntityItemID& entityID);
|
||||||
void deleteEntitys(QSet<EntityItemID> modelIDs);
|
void deleteEntities(QSet<EntityItemID> entityIDs);
|
||||||
const EntityItem* findClosestEntity(glm::vec3 position, float targetRadius);
|
const EntityItem* findClosestEntity(glm::vec3 position, float targetRadius);
|
||||||
EntityItem* findEntityByID(uint32_t id, bool alreadyLocked = false) const;
|
EntityItem* findEntityByID(uint32_t id, bool alreadyLocked = false) /*const*/;
|
||||||
EntityItem* findEntityByEntityItemID(const EntityItemID& modelID) 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 center the center of the sphere
|
||||||
/// \param radius the radius of the sphere
|
/// \param radius the radius of the sphere
|
||||||
/// \param foundEntitys[out] vector of const EntityItem*
|
/// \param foundEntities[out] vector of const EntityItem*
|
||||||
/// \remark Side effect: any initial contents in foundEntitys will be lost
|
/// \remark Side effect: any initial contents in foundEntities will be lost
|
||||||
void findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntitys);
|
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 cube the query cube
|
||||||
/// \param foundEntitys[out] vector of non-const EntityItem*
|
/// \param foundEntities[out] vector of non-const EntityItem*
|
||||||
/// \remark Side effect: any initial contents in models will be lost
|
/// \remark Side effect: any initial contents in entities will be lost
|
||||||
void findEntities(const AACube& cube, QVector<EntityItem*> foundEntitys);
|
void findEntities(const AACube& cube, QVector<EntityItem*> foundEntities);
|
||||||
|
|
||||||
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||||
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
|
||||||
|
|
||||||
bool hasAnyDeletedEntitys() const { return _recentlyDeletedEntityItemIDs.size() > 0; }
|
bool hasAnyDeletedEntities() const { return _recentlyDeletedEntityItemIDs.size() > 0; }
|
||||||
bool hasEntitysDeletedSince(quint64 sinceTime);
|
bool hasEntitiesDeletedSince(quint64 sinceTime);
|
||||||
bool encodeEntitysDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime,
|
bool encodeEntitiesDeletedSince(OCTREE_PACKET_SEQUENCE sequenceNumber, quint64& sinceTime,
|
||||||
unsigned char* packetData, size_t maxLength, size_t& outputLength);
|
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 processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||||
void handleAddEntityResponse(const QByteArray& packet);
|
void handleAddEntityResponse(const QByteArray& packet);
|
||||||
|
|
||||||
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
||||||
const FBXGeometry* getGeometryForEntity(const EntityItem& modelItem) {
|
const FBXGeometry* getGeometryForEntity(const EntityItem& entityItem) {
|
||||||
return _fbxService ? _fbxService->getGeometryForEntity(modelItem) : NULL;
|
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 setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
|
||||||
void debugDumpMap();
|
void debugDumpMap();
|
||||||
void dumpTree();
|
void dumpTree();
|
||||||
|
@ -123,11 +123,11 @@ private:
|
||||||
QReadWriteLock _newlyCreatedHooksLock;
|
QReadWriteLock _newlyCreatedHooksLock;
|
||||||
QVector<NewlyCreatedEntityHook*> _newlyCreatedHooks;
|
QVector<NewlyCreatedEntityHook*> _newlyCreatedHooks;
|
||||||
|
|
||||||
QReadWriteLock _recentlyDeletedEntitysLock;
|
QReadWriteLock _recentlyDeletedEntitiesLock;
|
||||||
QMultiMap<quint64, uint32_t> _recentlyDeletedEntityItemIDs;
|
QMultiMap<quint64, uint32_t> _recentlyDeletedEntityItemIDs;
|
||||||
EntityItemFBXService* _fbxService;
|
EntityItemFBXService* _fbxService;
|
||||||
|
|
||||||
QHash<EntityItemID, EntityTreeElement*> _modelToElementMap;
|
QHash<EntityItemID, EntityTreeElement*> _entityToElementMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityTree_h
|
#endif // hifi_EntityTree_h
|
||||||
|
|
|
@ -198,6 +198,14 @@ bool EntityTreeElement::bestFitBounds(const AACube& bounds) const {
|
||||||
return bestFitBounds(bounds.getMinimumPoint(), bounds.getMaximumPoint());
|
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 {
|
bool EntityTreeElement::containsBounds(const glm::vec3& minPoint, const glm::vec3& maxPoint) const {
|
||||||
glm::vec3 clampedMin = glm::clamp(minPoint, 0.0f, 1.0f);
|
glm::vec3 clampedMin = glm::clamp(minPoint, 0.0f, 1.0f);
|
||||||
glm::vec3 clampedMax = glm::clamp(maxPoint, 0.0f, 1.0f);
|
glm::vec3 clampedMax = glm::clamp(maxPoint, 0.0f, 1.0f);
|
||||||
|
@ -683,6 +691,9 @@ bool EntityTreeElement::collapseChildren() {
|
||||||
|
|
||||||
|
|
||||||
void EntityTreeElement::debugDump() {
|
void EntityTreeElement::debugDump() {
|
||||||
|
qDebug() << "EntityTreeElement...";
|
||||||
|
qDebug() << "entity count:" << _entityItems->size();
|
||||||
|
qDebug() << "cube:" << getAACube();
|
||||||
for (uint16_t i = 0; i < _entityItems->size(); i++) {
|
for (uint16_t i = 0; i < _entityItems->size(); i++) {
|
||||||
EntityItem* entity = (*_entityItems)[i];
|
EntityItem* entity = (*_entityItems)[i];
|
||||||
entity->debugDump();
|
entity->debugDump();
|
||||||
|
|
|
@ -158,6 +158,9 @@ public:
|
||||||
bool containsBounds(const AACube& bounds) const; // NOTE: units in tree units
|
bool containsBounds(const AACube& bounds) const; // NOTE: units in tree units
|
||||||
bool bestFitBounds(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 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
|
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);
|
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 {
|
int OctreeElement::getMyChildContaining(const AACube& cube) const {
|
||||||
float ourScale = getScale();
|
float ourScale = getScale();
|
||||||
float cubeScale = cube.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
|
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 {
|
int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {
|
||||||
glm::vec3 ourCenter = _cube.calcCenter();
|
glm::vec3 ourCenter = _cube.calcCenter();
|
||||||
int childIndex = CHILD_UNKNOWN;
|
int childIndex = CHILD_UNKNOWN;
|
||||||
|
|
|
@ -237,7 +237,9 @@ public:
|
||||||
|
|
||||||
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
||||||
OctreeElement* getOrCreateChildElementContaining(const AACube& box);
|
OctreeElement* getOrCreateChildElementContaining(const AACube& box);
|
||||||
|
OctreeElement* getOrCreateChildElementContaining(const AABox& box);
|
||||||
int getMyChildContaining(const AACube& cube) const;
|
int getMyChildContaining(const AACube& cube) const;
|
||||||
|
int getMyChildContaining(const AABox& box) const;
|
||||||
int getMyChildContainingPoint(const glm::vec3& point) const;
|
int getMyChildContainingPoint(const glm::vec3& point) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -14,6 +14,11 @@
|
||||||
#include "GeometryUtil.h"
|
#include "GeometryUtil.h"
|
||||||
#include "SharedUtil.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) :
|
AABox::AABox(const glm::vec3& corner, float size) :
|
||||||
_corner(corner), _scale(size, size, size) {
|
_corner(corner), _scale(size, size, size) {
|
||||||
};
|
};
|
||||||
|
@ -443,3 +448,19 @@ BoxFace AABox::getOppositeFace(BoxFace face) {
|
||||||
case MAX_Z_FACE: return MIN_Z_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 <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "BoxBase.h"
|
#include "BoxBase.h"
|
||||||
|
#include "StreamUtils.h"
|
||||||
|
|
||||||
class AACube;
|
class AACube;
|
||||||
|
|
||||||
class AABox {
|
class AABox {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
AABox(const AACube& other);
|
||||||
AABox(const glm::vec3& corner, float size);
|
AABox(const glm::vec3& corner, float size);
|
||||||
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
|
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
|
||||||
AABox();
|
AABox();
|
||||||
|
@ -38,6 +42,7 @@ public:
|
||||||
const glm::vec3& getCorner() const { return _corner; }
|
const glm::vec3& getCorner() const { return _corner; }
|
||||||
const glm::vec3& getScale() const { return _scale; }
|
const glm::vec3& getScale() const { return _scale; }
|
||||||
const glm::vec3& getDimensions() 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 calcCenter() const;
|
||||||
glm::vec3 calcTopFarLeft() const;
|
glm::vec3 calcTopFarLeft() const;
|
||||||
|
@ -62,6 +67,9 @@ public:
|
||||||
|
|
||||||
bool isNull() const { return _scale == glm::vec3(0.0f, 0.0f, 0.0f); }
|
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:
|
private:
|
||||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, 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();
|
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
|
#endif // hifi_AABox_h
|
||||||
|
|
|
@ -433,3 +433,14 @@ BoxFace AACube::getOppositeFace(BoxFace face) {
|
||||||
case MAX_Z_FACE: return MIN_Z_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 <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "BoxBase.h"
|
#include "BoxBase.h"
|
||||||
|
|
||||||
class AABox;
|
class AABox;
|
||||||
|
@ -54,6 +56,9 @@ public:
|
||||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
|
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
|
||||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
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:
|
private:
|
||||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
||||||
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, 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();
|
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
|
#endif // hifi_AACube_h
|
||||||
|
|
|
@ -451,7 +451,7 @@ void EntityTests::entityTreeTests(bool verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 startDelete = usecTimestampNow();
|
quint64 startDelete = usecTimestampNow();
|
||||||
tree.deleteEntitys(entitiesToDelete);
|
tree.deleteEntities(entitiesToDelete);
|
||||||
quint64 endDelete = usecTimestampNow();
|
quint64 endDelete = usecTimestampNow();
|
||||||
totalElapsedDelete += (endDelete - startDelete);
|
totalElapsedDelete += (endDelete - startDelete);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue