From 31fcd55d473ce7a6c9008a373c79b2ca67e3c934 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Sep 2015 10:31:12 -0700 Subject: [PATCH 01/17] octree uses shared pointers --- .../src/entities/EntityServer.cpp | 17 +- assignment-client/src/entities/EntityServer.h | 2 +- .../src/octree/OctreeQueryNode.cpp | 12 +- .../src/octree/OctreeSendThread.cpp | 4 +- assignment-client/src/octree/OctreeServer.cpp | 3 +- assignment-client/src/octree/OctreeServer.h | 6 +- interface/src/Application.cpp | 64 ++++--- interface/src/Application.h | 6 +- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/ModelReferential.cpp | 8 +- interface/src/avatar/ModelReferential.h | 10 +- interface/src/avatar/MyAvatar.cpp | 4 +- .../src/EntityTreeRenderer.cpp | 43 +++-- .../src/EntityTreeRenderer.h | 19 +- .../src/RenderableLightEntityItem.cpp | 2 +- .../src/RenderableLightEntityItem.h | 2 +- .../src/RenderableModelEntityItem.cpp | 7 +- .../src/RenderableModelEntityItem.h | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 10 +- .../src/RenderablePolyVoxEntityItem.h | 2 +- libraries/entities/src/AddEntityOperator.cpp | 15 +- libraries/entities/src/AddEntityOperator.h | 10 +- .../entities/src/DeleteEntityOperator.cpp | 16 +- libraries/entities/src/DeleteEntityOperator.h | 14 +- libraries/entities/src/EntityItem.cpp | 32 +--- libraries/entities/src/EntityItem.h | 13 +- .../entities/src/EntityScriptingInterface.cpp | 16 +- .../entities/src/EntityScriptingInterface.h | 7 +- libraries/entities/src/EntitySimulation.cpp | 2 +- libraries/entities/src/EntitySimulation.h | 6 +- libraries/entities/src/EntityTree.cpp | 115 +++++++----- libraries/entities/src/EntityTree.h | 42 +++-- libraries/entities/src/EntityTreeElement.cpp | 94 ++++++---- libraries/entities/src/EntityTreeElement.h | 29 ++- .../entities/src/EntityTreeHeadlessViewer.cpp | 6 +- .../entities/src/EntityTreeHeadlessViewer.h | 8 +- libraries/entities/src/LineEntityItem.h | 2 +- .../entities/src/MovingEntitiesOperator.cpp | 20 +- .../entities/src/MovingEntitiesOperator.h | 14 +- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.h | 2 +- .../src/RecurseOctreeToMapOperator.cpp | 15 +- .../entities/src/RecurseOctreeToMapOperator.h | 10 +- libraries/entities/src/SphereEntityItem.cpp | 5 +- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- .../entities/src/UpdateEntityOperator.cpp | 38 ++-- libraries/entities/src/UpdateEntityOperator.h | 20 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 2 +- libraries/entities/src/ZoneEntityItem.h | 7 +- libraries/octree/src/Octree.cpp | 177 +++++++++++------- libraries/octree/src/Octree.h | 70 +++---- libraries/octree/src/OctreeElement.cpp | 113 ++++++----- libraries/octree/src/OctreeElement.h | 69 +++---- libraries/octree/src/OctreeElementBag.cpp | 14 +- libraries/octree/src/OctreeElementBag.h | 16 +- libraries/octree/src/OctreeHeadlessViewer.h | 2 +- libraries/octree/src/OctreePersistThread.cpp | 2 +- libraries/octree/src/OctreePersistThread.h | 12 +- libraries/octree/src/OctreeRenderer.cpp | 13 +- libraries/octree/src/OctreeRenderer.h | 16 +- libraries/octree/src/OctreeSceneStats.cpp | 19 +- libraries/octree/src/OctreeSceneStats.h | 18 +- libraries/physics/src/EntityMotionState.cpp | 4 +- .../physics/src/PhysicalEntitySimulation.cpp | 4 +- .../physics/src/PhysicalEntitySimulation.h | 7 +- libraries/physics/src/PhysicsEngine.cpp | 3 - libraries/physics/src/PhysicsEngine.h | 7 +- libraries/shared/src/SharedUtil.h | 9 +- 72 files changed, 748 insertions(+), 624 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index feef396c72..bde53e4a87 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -36,7 +36,7 @@ EntityServer::~EntityServer() { _pruneDeletedEntitiesTimer->deleteLater(); } - EntityTree* tree = (EntityTree*)_tree; + EntityTreePointer tree = std::static_pointer_cast(_tree); tree->removeNewlyCreatedHook(this); } @@ -50,8 +50,9 @@ OctreeQueryNode* EntityServer::createOctreeQueryNode() { return new EntityNodeData(); } -Octree* EntityServer::createTree() { - EntityTree* tree = new EntityTree(true); +OctreePointer EntityServer::createTree() { + EntityTreePointer tree = EntityTreePointer(new EntityTree(true)); + tree->createRootElement(); tree->addNewlyCreatedHook(this); if (!_entitySimulation) { SimpleEntitySimulation* simpleSimulation = new SimpleEntitySimulation(); @@ -82,7 +83,7 @@ bool EntityServer::hasSpecialPacketsToSend(const SharedNodePointer& node) { if (nodeData) { quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt(); - EntityTree* tree = static_cast(_tree); + EntityTreePointer tree = std::static_pointer_cast(_tree); shouldSendDeletedEntities = tree->hasEntitiesDeletedSince(deletedEntitiesSentAt); } @@ -97,7 +98,7 @@ int EntityServer::sendSpecialPackets(const SharedNodePointer& node, OctreeQueryN quint64 deletedEntitiesSentAt = nodeData->getLastDeletedEntitiesSentAt(); quint64 deletePacketSentAt = usecTimestampNow(); - EntityTree* tree = static_cast(_tree); + EntityTreePointer tree = std::static_pointer_cast(_tree); bool hasMoreToSend = true; packetsSent = 0; @@ -122,7 +123,7 @@ int EntityServer::sendSpecialPackets(const SharedNodePointer& node, OctreeQueryN } void EntityServer::pruneDeletedEntities() { - EntityTree* tree = static_cast(_tree); + EntityTreePointer tree = std::static_pointer_cast(_tree); if (tree->hasAnyDeletedEntities()) { quint64 earliestLastDeletedEntitiesSent = usecTimestampNow() + 1; // in the future @@ -147,8 +148,6 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio qDebug("wantEditLogging=%s", debug::valueOf(wantEditLogging)); - EntityTree* tree = static_cast(_tree); + EntityTreePointer tree = std::static_pointer_cast(_tree); tree->setWantEditLogging(wantEditLogging); } - - diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 1c4eda3cc0..7d314057cc 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -47,7 +47,7 @@ public slots: void pruneDeletedEntities(); protected: - virtual Octree* createTree(); + virtual OctreePointer createTree(); private slots: void handleEntityPacket(QSharedPointer packet, SharedNodePointer senderNode); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 6395397c51..64c5b4318a 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -338,9 +338,9 @@ void OctreeQueryNode::dumpOutOfView() { int outOfView = 0; OctreeElementBag tempBag; while (!elementBag.isEmpty()) { - OctreeElement* node = elementBag.extract(); - if (node->isInView(_currentViewFrustum)) { - tempBag.insert(node); + OctreeElementPointer elt = elementBag.extract(); + if (elt->isInView(_currentViewFrustum)) { + tempBag.insert(elt); stillInView++; } else { outOfView++; @@ -348,9 +348,9 @@ void OctreeQueryNode::dumpOutOfView() { } if (stillInView > 0) { while (!tempBag.isEmpty()) { - OctreeElement* node = tempBag.extract(); - if (node->isInView(_currentViewFrustum)) { - elementBag.insert(node); + OctreeElementPointer elt = tempBag.extract(); + if (elt->isInView(_currentViewFrustum)) { + elementBag.insert(elt); } } } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 62517e698b..ad6ac8b39f 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -421,7 +421,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); quint64 encodeStart = usecTimestampNow(); - OctreeElement* subTree = nodeData->elementBag.extract(); + OctreeElementPointer subTree = nodeData->elementBag.extract(); /* TODO: Looking for a way to prevent locking and encoding a tree that is not // going to result in any packets being sent... @@ -430,7 +430,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // and we've already seen at least one duplicate packet, then we probably don't need // to lock the tree and encode, because the result should be that no bytes will be // encoded, and this will be a duplicate packet from the last one we sent... - OctreeElement* root = _myServer->getOctree()->getRoot(); + OctreeElementPointer root = _myServer->getOctree()->getRoot(); bool skipEncode = false; if ( (subTree == root) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index a0350622db..f8bbeeac7b 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -280,8 +280,7 @@ OctreeServer::~OctreeServer() { // cleanup our tree here... qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; - delete _tree; - _tree = NULL; + _tree.reset(); qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]"; if (_instance == this) { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 419cdabc58..54add7a794 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -42,7 +42,7 @@ public: bool wantsDebugReceiving() const { return _debugReceiving; } bool wantsVerboseDebug() const { return _verboseDebug; } - Octree* getOctree() { return _tree; } + OctreePointer getOctree() { return _tree; } JurisdictionMap* getJurisdiction() { return _jurisdiction; } int getPacketsPerClientPerInterval() const { return std::min(_packetsPerClientPerInterval, @@ -131,7 +131,7 @@ private slots: void handleJurisdictionRequestPacket(QSharedPointer packet, SharedNodePointer senderNode); protected: - virtual Octree* createTree() = 0; + virtual OctreePointer createTree() = 0; bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result); bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result); bool readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result); @@ -160,7 +160,7 @@ protected: QString _persistAsFileType; int _packetsPerClientPerInterval; int _packetsTotalPerInterval; - Octree* _tree; // this IS a reaveraging tree + OctreePointer _tree; // this IS a reaveraging tree bool _wantPersist; bool _debugSending; bool _debugReceiving; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8505e999dd..ae97d5aa94 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -333,10 +333,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _frameCount(0), _fps(60.0f), _justStarted(true), - _physicsEngine(glm::vec3(0.0f)), + _physicsEngine(new PhysicsEngine(Vectors::ZERO)), _entities(true, this, this), _entityClipboardRenderer(false, this, this), - _entityClipboard(), + _entityClipboard(new EntityTree()), _viewFrustum(), _lastQueriedViewFrustum(), _lastQueriedTime(usecTimestampNow()), @@ -370,6 +370,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : { setInstance(this); + _entityClipboard->createRootElement(); + _pluginContainer = new PluginContainerProxy(); Plugin::setContainer(_pluginContainer); #ifdef Q_OS_WIN @@ -841,7 +843,7 @@ void Application::emptyLocalCache() { } Application::~Application() { - EntityTree* tree = _entities.getTree(); + EntityTreePointer tree = _entities.getTree(); tree->lockForWrite(); _entities.getTree()->setSimulation(NULL); tree->unlock(); @@ -851,7 +853,7 @@ Application::~Application() { Menu::getInstance()->deleteLater(); - _physicsEngine.setCharacterController(NULL); + _physicsEngine->setCharacterController(NULL); _myAvatar = NULL; ModelEntityItem::cleanupLoadedAnimations(); @@ -866,7 +868,7 @@ Application::~Application() { // remove avatars from physics engine DependencyManager::get()->clearOtherAvatars(); - _physicsEngine.deleteObjects(DependencyManager::get()->getObjectsToDelete()); + _physicsEngine->deleteObjects(DependencyManager::get()->getObjectsToDelete()); DependencyManager::destroy(); DependencyManager::destroy(); @@ -1486,7 +1488,7 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_F: { - _physicsEngine.dumpNextStats(); + _physicsEngine->dumpNextStats(); break; } @@ -2355,7 +2357,7 @@ void Application::saveSettings() { } bool Application::importEntities(const QString& urlOrFilename) { - _entityClipboard.eraseAllOctreeElements(); + _entityClipboard->eraseAllOctreeElements(); QUrl url(urlOrFilename); @@ -2364,15 +2366,15 @@ bool Application::importEntities(const QString& urlOrFilename) { url = QUrl::fromLocalFile(urlOrFilename); } - bool success = _entityClipboard.readFromURL(url.toString()); + bool success = _entityClipboard->readFromURL(url.toString()); if (success) { - _entityClipboard.reaverageOctreeElements(); + _entityClipboard->reaverageOctreeElements(); } return success; } QVector Application::pasteEntities(float x, float y, float z) { - return _entityClipboard.sendEntities(&_entityEditSender, _entities.getTree(), x, y, z); + return _entityClipboard->sendEntities(&_entityEditSender, _entities.getTree(), x, y, z); } void Application::initDisplay() { @@ -2417,10 +2419,10 @@ void Application::init() { _entities.setViewFrustum(getViewFrustum()); ObjectMotionState::setShapeManager(&_shapeManager); - _physicsEngine.init(); + _physicsEngine->init(); - EntityTree* tree = _entities.getTree(); - _entitySimulation.init(tree, &_physicsEngine, &_entityEditSender); + EntityTreePointer tree = _entities.getTree(); + _entitySimulation.init(tree, _physicsEngine, &_entityEditSender); tree->setSimulation(&_entitySimulation); auto entityScriptingInterface = DependencyManager::get(); @@ -2435,10 +2437,10 @@ void Application::init() { _entityClipboardRenderer.init(); _entityClipboardRenderer.setViewFrustum(getViewFrustum()); - _entityClipboardRenderer.setTree(&_entityClipboard); + _entityClipboardRenderer.setTree(_entityClipboard); // Make sure any new sounds are loaded as soon as know about them. - connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); + connect(tree.get(), &EntityTree::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); connect(_myAvatar, &MyAvatar::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); } @@ -2812,18 +2814,18 @@ void Application::update(float deltaTime) { _myAvatar->relayDriveKeysToCharacterController(); _entitySimulation.lock(); - _physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete()); + _physicsEngine->deleteObjects(_entitySimulation.getObjectsToDelete()); _entitySimulation.unlock(); _entities.getTree()->lockForWrite(); _entitySimulation.lock(); - _physicsEngine.addObjects(_entitySimulation.getObjectsToAdd()); + _physicsEngine->addObjects(_entitySimulation.getObjectsToAdd()); _entitySimulation.unlock(); _entities.getTree()->unlock(); _entities.getTree()->lockForWrite(); _entitySimulation.lock(); - VectorOfMotionStates stillNeedChange = _physicsEngine.changeObjects(_entitySimulation.getObjectsToChange()); + VectorOfMotionStates stillNeedChange = _physicsEngine->changeObjects(_entitySimulation.getObjectsToChange()); _entitySimulation.setObjectsToChange(stillNeedChange); _entitySimulation.unlock(); _entities.getTree()->unlock(); @@ -2833,29 +2835,29 @@ void Application::update(float deltaTime) { _entitySimulation.unlock(); AvatarManager* avatarManager = DependencyManager::get().data(); - _physicsEngine.deleteObjects(avatarManager->getObjectsToDelete()); - _physicsEngine.addObjects(avatarManager->getObjectsToAdd()); - _physicsEngine.changeObjects(avatarManager->getObjectsToChange()); + _physicsEngine->deleteObjects(avatarManager->getObjectsToDelete()); + _physicsEngine->addObjects(avatarManager->getObjectsToAdd()); + _physicsEngine->changeObjects(avatarManager->getObjectsToChange()); _entities.getTree()->lockForWrite(); - _physicsEngine.stepSimulation(); + _physicsEngine->stepSimulation(); _entities.getTree()->unlock(); - if (_physicsEngine.hasOutgoingChanges()) { + if (_physicsEngine->hasOutgoingChanges()) { _entities.getTree()->lockForWrite(); _entitySimulation.lock(); - _entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID()); + _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID()); _entitySimulation.unlock(); _entities.getTree()->unlock(); _entities.getTree()->lockForWrite(); - avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges()); + avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges()); _entities.getTree()->unlock(); - auto collisionEvents = _physicsEngine.getCollisionEvents(); + auto collisionEvents = _physicsEngine->getCollisionEvents(); avatarManager->handleCollisionEvents(collisionEvents); - _physicsEngine.dumpStatsIfNecessary(); + _physicsEngine->dumpStatsIfNecessary(); if (!_aboutToQuit) { PerformanceTimer perfTimer("entities"); @@ -4102,7 +4104,7 @@ bool Application::acceptURL(const QString& urlString) { } void Application::setSessionUUID(const QUuid& sessionUUID) { - _physicsEngine.setSessionUUID(sessionUUID); + _physicsEngine->setSessionUUID(sessionUUID); } bool Application::askToSetAvatarUrl(const QString& url) { @@ -4351,7 +4353,7 @@ void Application::openUrl(const QUrl& url) { void Application::updateMyAvatarTransform() { const float SIMULATION_OFFSET_QUANTIZATION = 16.0f; // meters glm::vec3 avatarPosition = _myAvatar->getPosition(); - glm::vec3 physicsWorldOffset = _physicsEngine.getOriginOffset(); + glm::vec3 physicsWorldOffset = _physicsEngine->getOriginOffset(); if (glm::distance(avatarPosition, physicsWorldOffset) > SIMULATION_OFFSET_QUANTIZATION) { glm::vec3 newOriginOffset = avatarPosition; int halfExtent = (int)HALF_SIMULATION_EXTENT; @@ -4360,7 +4362,7 @@ void Application::updateMyAvatarTransform() { ((int)(avatarPosition[i] / SIMULATION_OFFSET_QUANTIZATION)) * (int)SIMULATION_OFFSET_QUANTIZATION)); } // TODO: Andrew to replace this with method that actually moves existing object positions in PhysicsEngine - _physicsEngine.setOriginOffset(newOriginOffset); + _physicsEngine->setOriginOffset(newOriginOffset); } } @@ -4558,7 +4560,7 @@ void Application::checkSkeleton() { _myAvatar->useFullAvatarURL(AvatarData::defaultFullAvatarModelUrl(), DEFAULT_FULL_AVATAR_MODEL_NAME); } else { - _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); + _physicsEngine->setCharacterController(_myAvatar->getCharacterController()); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 6c3b68cf6f..d82a5b378f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -208,7 +208,7 @@ public: QUndoStack* getUndoStack() { return &_undoStack; } MainWindow* getWindow() { return _window; } OctreeQuery& getOctreeQuery() { return _octreeQuery; } - EntityTree* getEntityClipboard() { return &_entityClipboard; } + EntityTreePointer getEntityClipboard() { return _entityClipboard; } EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; } EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; } @@ -533,11 +533,11 @@ private: ShapeManager _shapeManager; PhysicalEntitySimulation _entitySimulation; - PhysicsEngine _physicsEngine; + PhysicsEnginePointer _physicsEngine; EntityTreeRenderer _entities; EntityTreeRenderer _entityClipboardRenderer; - EntityTree _entityClipboard; + EntityTreePointer _entityClipboard; ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 55699bccbe..aa401f91f8 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -152,7 +152,7 @@ void Avatar::simulate(float deltaTime) { // update the avatar's position according to its referential if (_referential) { if (_referential->hasExtraData()) { - EntityTree* tree = Application::getInstance()->getEntities()->getTree(); + EntityTreePointer tree = Application::getInstance()->getEntities()->getTree(); switch (_referential->type()) { case Referential::MODEL: _referential = new ModelReferential(_referential, diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp index 46290b17b5..18c5e36e7a 100644 --- a/interface/src/avatar/ModelReferential.cpp +++ b/interface/src/avatar/ModelReferential.cpp @@ -16,7 +16,7 @@ #include "InterfaceLogging.h" #include "ModelReferential.h" -ModelReferential::ModelReferential(Referential* referential, EntityTree* tree, AvatarData* avatar) : +ModelReferential::ModelReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) : Referential(MODEL, avatar), _tree(tree) { @@ -39,7 +39,7 @@ ModelReferential::ModelReferential(Referential* referential, EntityTree* tree, A } } -ModelReferential::ModelReferential(const QUuid& entityID, EntityTree* tree, AvatarData* avatar) : +ModelReferential::ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) : Referential(MODEL, avatar), _entityID(entityID), _tree(tree) @@ -96,7 +96,7 @@ int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int siz return NUM_BYTES_RFC4122_UUID; } -JointReferential::JointReferential(Referential* referential, EntityTree* tree, AvatarData* avatar) : +JointReferential::JointReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) : ModelReferential(referential, tree, avatar) { _type = JOINT; @@ -115,7 +115,7 @@ JointReferential::JointReferential(Referential* referential, EntityTree* tree, A update(); } -JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTree* tree, AvatarData* avatar) : +JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) : ModelReferential(entityID, tree, avatar), _jointIndex(jointIndex) { diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h index ed38253b0b..810db4b8e5 100644 --- a/interface/src/avatar/ModelReferential.h +++ b/interface/src/avatar/ModelReferential.h @@ -19,8 +19,8 @@ class Model; class ModelReferential : public Referential { public: - ModelReferential(Referential* ref, EntityTree* tree, AvatarData* avatar); - ModelReferential(const QUuid& entityID, EntityTree* tree, AvatarData* avatar); + ModelReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar); + ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar); virtual void update(); protected: @@ -28,13 +28,13 @@ protected: virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); QUuid _entityID; - EntityTree* _tree; + EntityTreePointer _tree; }; class JointReferential : public ModelReferential { public: - JointReferential(Referential* ref, EntityTree* tree, AvatarData* avatar); - JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTree* tree, AvatarData* avatar); + JointReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar); + JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar); virtual void update(); protected: diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index de7e2ba8fb..a9e36d0fa9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -459,7 +459,7 @@ void MyAvatar::clearReferential() { } bool MyAvatar::setModelReferential(const QUuid& id) { - EntityTree* tree = Application::getInstance()->getEntities()->getTree(); + EntityTreePointer tree = Application::getInstance()->getEntities()->getTree(); changeReferential(new ModelReferential(id, tree, this)); if (_referential->isValid()) { return true; @@ -470,7 +470,7 @@ bool MyAvatar::setModelReferential(const QUuid& id) { } bool MyAvatar::setJointReferential(const QUuid& id, int jointIndex) { - EntityTree* tree = Application::getInstance()->getEntities()->getTree(); + EntityTreePointer tree = Application::getInstance()->getEntities()->getTree(); changeReferential(new JointReferential(jointIndex, id, tree, this)); if (!_referential->isValid()) { return true; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 72400dcefb..4b3a1ec5d4 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -107,7 +107,7 @@ void EntityTreeRenderer::clear() { void EntityTreeRenderer::init() { OctreeRenderer::init(); - EntityTree* entityTree = static_cast(_tree); + EntityTreePointer entityTree = std::static_pointer_cast(_tree); entityTree->setFBXService(this); if (_wantScripts) { @@ -121,10 +121,11 @@ void EntityTreeRenderer::init() { // make sure our "last avatar position" is something other than our current position, so that on our // first chance, we'll check for enter/leave entity events. _lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE); - - connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity, Qt::QueuedConnection); - connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::addingEntity, Qt::QueuedConnection); - connect(entityTree, &EntityTree::entityScriptChanging, this, &EntityTreeRenderer::entitySciptChanging, Qt::QueuedConnection); + + connect(entityTree.get(), &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity, Qt::QueuedConnection); + connect(entityTree.get(), &EntityTree::addingEntity, this, &EntityTreeRenderer::addingEntity, Qt::QueuedConnection); + connect(entityTree.get(), &EntityTree::entityScriptChanging, + this, &EntityTreeRenderer::entitySciptChanging, Qt::QueuedConnection); } void EntityTreeRenderer::shutdown() { @@ -149,7 +150,7 @@ void EntityTreeRenderer::errorInLoadingScript(const QUrl& url) { } QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID, bool isPreload, bool reload) { - EntityItemPointer entity = static_cast(_tree)->findEntityByEntityItemID(entityItemID); + EntityItemPointer entity = std::static_pointer_cast(_tree)->findEntityByEntityItemID(entityItemID); return loadEntityScript(entity, isPreload, reload); } @@ -302,16 +303,16 @@ QScriptValue EntityTreeRenderer::getPreviouslyLoadedEntityScript(const EntityIte return QScriptValue(); // no script } -void EntityTreeRenderer::setTree(Octree* newTree) { +void EntityTreeRenderer::setTree(OctreePointer newTree) { OctreeRenderer::setTree(newTree); - static_cast(_tree)->setFBXService(this); + std::static_pointer_cast(_tree)->setFBXService(this); } void EntityTreeRenderer::update() { if (_tree && !_shuttingDown) { - EntityTree* tree = static_cast(_tree); + EntityTreePointer tree = std::static_pointer_cast(_tree); tree->update(); - + // check to see if the avatar has moved and if we need to handle enter/leave entity logic checkEnterLeaveEntities(); @@ -341,7 +342,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { // find the entities near us _tree->lockForRead(); // don't let someone else change our tree while we search - static_cast(_tree)->findEntities(avatarPosition, radius, foundEntities); + std::static_pointer_cast(_tree)->findEntities(avatarPosition, radius, foundEntities); // create a list of entities that actually contain the avatar's position foreach(EntityItemPointer entity, foundEntities) { @@ -553,7 +554,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP return result; } -void EntityTreeRenderer::renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args) { +void EntityTreeRenderer::renderElementProxy(EntityTreeElementPointer entityTreeElement, RenderArgs* args) { auto deferredLighting = DependencyManager::get(); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; @@ -627,10 +628,11 @@ void EntityTreeRenderer::renderProxies(EntityItemPointer entity, RenderArgs* arg } } -void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) { +void EntityTreeRenderer::renderElement(OctreeElementPointer element, RenderArgs* args) { // actually render it here... // we need to iterate the actual entityItems of the element - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); + EntityItems& entityItems = entityTreeElement->getEntities(); @@ -684,7 +686,7 @@ int EntityTreeRenderer::getBoundaryLevelAdjust() const { void EntityTreeRenderer::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) { - static_cast(_tree)->processEraseMessage(packet, sourceNode); + std::static_pointer_cast(_tree)->processEraseMessage(packet, sourceNode); } Model* EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) { @@ -760,9 +762,9 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons bool precisionPicking) { RayToEntityIntersectionResult result; if (_tree) { - EntityTree* entityTree = static_cast(_tree); + EntityTreePointer entityTree = std::static_pointer_cast(_tree); - OctreeElement* element; + OctreeElementPointer element; EntityItemPointer intersectedEntity = NULL; result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, (void**)&intersectedEntity, lockType, &result.accurate, @@ -1018,7 +1020,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) { checkAndCallPreload(entityID); - auto entity = static_cast(_tree)->findEntityByID(entityID); + auto entity = std::static_pointer_cast(_tree)->findEntityByID(entityID); if (entity) { addEntityToScene(entity); } @@ -1063,7 +1065,8 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { } } -void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) { +void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTreePointer entityTree, + const EntityItemID& id, const Collision& collision) { EntityItemPointer entity = entityTree->findEntityByEntityItemID(id); if (!entity) { return; @@ -1130,7 +1133,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons } // See if we should play sounds - EntityTree* entityTree = static_cast(_tree); + EntityTreePointer entityTree = std::static_pointer_cast(_tree); const QUuid& myNodeID = DependencyManager::get()->getSessionUUID(); playEntityCollisionSound(myNodeID, entityTree, idA, collision); playEntityCollisionSound(myNodeID, entityTree, idB, collision); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 25eb87b422..8afdf6e084 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -45,15 +45,15 @@ public: virtual char getMyNodeType() const { return NodeType::EntityServer; } virtual PacketType::Value getMyQueryMessageType() const { return PacketType::EntityQuery; } virtual PacketType::Value getExpectedPacketType() const { return PacketType::EntityData; } - virtual void renderElement(OctreeElement* element, RenderArgs* args); + virtual void renderElement(OctreeElementPointer element, RenderArgs* args); virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; - virtual void setTree(Octree* newTree); + virtual void setTree(OctreePointer newTree); void shutdown(); void update(); - EntityTree* getTree() { return static_cast(_tree); } + EntityTreePointer getTree() { return std::static_pointer_cast(_tree); } void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); @@ -123,15 +123,19 @@ public slots: void setDisplayModelBounds(bool value) { _displayModelBounds = value; } void setDisplayModelElementProxy(bool value) { _displayModelElementProxy = value; } void setDontDoPrecisionPicking(bool value) { _dontDoPrecisionPicking = value; } - + protected: - virtual Octree* createTree() { return new EntityTree(true); } + virtual OctreePointer createTree() { + EntityTreePointer newTree = EntityTreePointer(new EntityTree(true)); + newTree->createRootElement(); + return newTree; + } private: void addEntityToScene(EntityItemPointer entity); void applyZonePropertiesToScene(std::shared_ptr zone); - void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args); + void renderElementProxy(EntityTreeElementPointer entityTreeElement, RenderArgs* args); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false); void checkAndCallUnload(const EntityItemID& entityID); @@ -162,7 +166,8 @@ private: QHash _entityScripts; - void playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision); + void playEntityCollisionSound(const QUuid& myNodeID, EntityTreePointer entityTree, + const EntityItemID& id, const Collision& collision); bool _lastMouseEventValid; MouseEvent _lastMouseEvent; diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 3ce4d404d9..19b1ec9c8d 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -54,7 +54,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) { }; bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { // TODO: consider if this is really what we want to do. We've made it so that "lights are pickable" is a global state diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index a0c424e240..bf73493729 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -26,7 +26,7 @@ public: virtual void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; SIMPLE_RENDERABLE(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index eed908e429..16cf80062d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -367,13 +367,14 @@ EntityItemProperties RenderableModelEntityItem::getProperties() const { } bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { if (!_model) { return true; } - //qCDebug(entitiesrenderer) << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:" << precisionPicking; - + // qCDebug(entitiesrenderer) << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:" + // << precisionPicking; + QString extraInfo; return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 4842063af3..d2c9370553 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -55,7 +55,7 @@ public: virtual void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; Model* getModel(EntityTreeRenderer* renderer); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5ddee32f88..2e8696625c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -351,7 +351,7 @@ public: bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, - OctreeElement*& element, + OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const @@ -858,8 +858,8 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync() { properties.setVoxelDataDirty(); properties.setLastEdited(now); - EntityTreeElement* element = getElement(); - EntityTree* tree = element ? element->getTree() : nullptr; + EntityTreeElementPointer element = getElement(); + EntityTreePointer tree = element ? element->getTree() : nullptr; EntitySimulation* simulation = tree ? tree->getSimulation() : nullptr; PhysicalEntitySimulation* peSimulation = static_cast(simulation); EntityEditPacketSender* packetSender = peSimulation ? peSimulation->getPacketSender() : nullptr; @@ -917,8 +917,8 @@ void RenderablePolyVoxEntityItem::clearOutOfDateNeighbors() { void RenderablePolyVoxEntityItem::cacheNeighbors() { clearOutOfDateNeighbors(); - EntityTreeElement* element = getElement(); - EntityTree* tree = element ? element->getTree() : nullptr; + EntityTreeElementPointer element = getElement(); + EntityTreePointer tree = element ? element->getTree() : nullptr; if (!tree) { return; } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 01578b5e58..14853d929e 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -64,7 +64,7 @@ public: void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; virtual void setVoxelData(QByteArray voxelData); diff --git a/libraries/entities/src/AddEntityOperator.cpp b/libraries/entities/src/AddEntityOperator.cpp index 51015c1ff4..2bfbbe2fd9 100644 --- a/libraries/entities/src/AddEntityOperator.cpp +++ b/libraries/entities/src/AddEntityOperator.cpp @@ -15,8 +15,7 @@ #include "AddEntityOperator.h" -AddEntityOperator::AddEntityOperator(EntityTree* tree, - EntityItemPointer newEntity) : +AddEntityOperator::AddEntityOperator(EntityTreePointer tree, EntityItemPointer newEntity) : _tree(tree), _newEntity(newEntity), _foundNew(false), @@ -25,16 +24,16 @@ AddEntityOperator::AddEntityOperator(EntityTree* tree, { // caller must have verified existence of newEntity assert(_newEntity); - + _newEntityBox = _newEntity->getMaximumAACube().clamp((float)(-HALF_TREE_SCALE), (float)HALF_TREE_SCALE); } -bool AddEntityOperator::preRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); +bool AddEntityOperator::preRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if - // and of the following are true: + // any of the following are true: // * We have not yet found the location for the new entity, and this branch contains the bounds of the new entity bool keepSearching = false; // assume we don't need to search any more @@ -59,7 +58,7 @@ bool AddEntityOperator::preRecursion(OctreeElement* element) { return keepSearching; // if we haven't yet found it, keep looking } -bool AddEntityOperator::postRecursion(OctreeElement* element) { +bool AddEntityOperator::postRecursion(OctreeElementPointer 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 entity and one for the new entity. @@ -73,7 +72,7 @@ bool AddEntityOperator::postRecursion(OctreeElement* element) { return keepSearching; // if we haven't yet found it, keep looking } -OctreeElement* AddEntityOperator::possiblyCreateChildAt(OctreeElement* element, int childIndex) { +OctreeElementPointer AddEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { // If we're getting called, it's because there was no child element at this index while recursing. // We only care if this happens while still searching for the new entity location. // Check to see if diff --git a/libraries/entities/src/AddEntityOperator.h b/libraries/entities/src/AddEntityOperator.h index d7e7371bb0..6aa2d5f727 100644 --- a/libraries/entities/src/AddEntityOperator.h +++ b/libraries/entities/src/AddEntityOperator.h @@ -14,13 +14,13 @@ class AddEntityOperator : public RecurseOctreeOperator { public: - AddEntityOperator(EntityTree* tree, EntityItemPointer newEntity); + AddEntityOperator(EntityTreePointer tree, EntityItemPointer newEntity); - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element); - virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex); + virtual bool preRecursion(OctreeElementPointer element); + virtual bool postRecursion(OctreeElementPointer element); + virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex); private: - EntityTree* _tree; + EntityTreePointer _tree; EntityItemPointer _newEntity; bool _foundNew; quint64 _changeTime; diff --git a/libraries/entities/src/DeleteEntityOperator.cpp b/libraries/entities/src/DeleteEntityOperator.cpp index bb96b9698d..48335c22b8 100644 --- a/libraries/entities/src/DeleteEntityOperator.cpp +++ b/libraries/entities/src/DeleteEntityOperator.cpp @@ -16,7 +16,7 @@ #include "EntitiesLogging.h" #include "DeleteEntityOperator.h" -DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID) : +DeleteEntityOperator::DeleteEntityOperator(EntityTreePointer tree, const EntityItemID& searchEntityID) : _tree(tree), _changeTime(usecTimestampNow()), _foundCount(0), @@ -28,7 +28,7 @@ DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree, const EntityItemID& DeleteEntityOperator::~DeleteEntityOperator() { } -DeleteEntityOperator::DeleteEntityOperator(EntityTree* tree) : +DeleteEntityOperator::DeleteEntityOperator(EntityTreePointer tree) : _tree(tree), _changeTime(usecTimestampNow()), _foundCount(0), @@ -55,7 +55,7 @@ void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEnt // does this entity tree element contain the old entity -bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElement* element) { +bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElementPointer element) { bool containsEntity = false; // If we don't have an old entity, then we don't contain the entity, otherwise @@ -72,9 +72,9 @@ bool DeleteEntityOperator::subTreeContainsSomeEntitiesToDelete(OctreeElement* el return containsEntity; } -bool DeleteEntityOperator::preRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); - +bool DeleteEntityOperator::preRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); + // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if: // * We have not yet found the all entities, and @@ -108,7 +108,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) { return keepSearching; // if we haven't yet found it, keep looking } -bool DeleteEntityOperator::postRecursion(OctreeElement* element) { +bool DeleteEntityOperator::postRecursion(OctreeElementPointer 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 entity and one for the new entity. @@ -125,7 +125,7 @@ bool DeleteEntityOperator::postRecursion(OctreeElement* element) { // children are the containing element for any entity in our lists of entities to delete, then they // must have already deleted the entity, and they are safe to prune. Since this operation doesn't // ever add any elements we don't have to worry about memory being reused within this recursion pass. - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves return keepSearching; // if we haven't yet found it, keep looking } diff --git a/libraries/entities/src/DeleteEntityOperator.h b/libraries/entities/src/DeleteEntityOperator.h index 48024b530c..ae2ec3621e 100644 --- a/libraries/entities/src/DeleteEntityOperator.h +++ b/libraries/entities/src/DeleteEntityOperator.h @@ -16,7 +16,7 @@ class EntityToDeleteDetails { public: EntityItemPointer entity; AACube cube; - EntityTreeElement* containingElement; + EntityTreeElementPointer containingElement; }; typedef QSet RemovedEntities; @@ -31,22 +31,22 @@ inline bool operator==(const EntityToDeleteDetails& a, const EntityToDeleteDetai class DeleteEntityOperator : public RecurseOctreeOperator { public: - DeleteEntityOperator(EntityTree* tree); - DeleteEntityOperator(EntityTree* tree, const EntityItemID& searchEntityID); + DeleteEntityOperator(EntityTreePointer tree); + DeleteEntityOperator(EntityTreePointer tree, const EntityItemID& searchEntityID); ~DeleteEntityOperator(); void addEntityIDToDeleteList(const EntityItemID& searchEntityID); - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element); + virtual bool preRecursion(OctreeElementPointer element); + virtual bool postRecursion(OctreeElementPointer element); const RemovedEntities& getEntities() const { return _entitiesToDelete; } private: - EntityTree* _tree; + EntityTreePointer _tree; RemovedEntities _entitiesToDelete; quint64 _changeTime; int _foundCount; int _lookingCount; - bool subTreeContainsSomeEntitiesToDelete(OctreeElement* element); + bool subTreeContainsSomeEntitiesToDelete(OctreeElementPointer element); }; #endif // hifi_DeleteEntityOperator_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9fa6ccac65..9f06b0d661 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -89,7 +89,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : EntityItem::~EntityItem() { // clear out any left-over actions - EntityTree* entityTree = _element ? _element->getTree() : nullptr; + EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; if (simulation) { clearActions(simulation); @@ -985,6 +985,12 @@ bool EntityItem::isMoving() const { return hasVelocity() || hasAngularVelocity(); } +EntityTreePointer EntityItem::getTree() const { + EntityTreeElementPointer elt = getElement(); + EntityTreePointer tree = elt ? elt->getTree() : nullptr; + return tree; +} + glm::mat4 EntityItem::getEntityToWorldMatrix() const { glm::mat4 translation = glm::translate(getPosition()); glm::mat4 rotation = glm::mat4_cast(getRotation()); @@ -1155,12 +1161,6 @@ void EntityItem::recordCreationTime() { _lastSimulated = now; } -void EntityItem::setCenterPosition(const glm::vec3& position) { - Transform transformToCenter = getTransformToCenter(); - transformToCenter.setTranslation(position); - setTranformToCenter(transformToCenter); -} - const Transform EntityItem::getTransformToCenter() const { Transform result = getTransform(); if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center @@ -1169,18 +1169,6 @@ const Transform EntityItem::getTransformToCenter() const { return result; } -void EntityItem::setTranformToCenter(const Transform& transform) { - if (getRegistrationPoint() == ENTITY_ITEM_HALF_VEC3) { - // If it is already centered, just call setTransform - setTransform(transform); - return; - } - - Transform copy = transform; - copy.postTranslate(getRegistrationPoint() - ENTITY_ITEM_HALF_VEC3); // Center to position - setTransform(copy); -} - void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; @@ -1577,7 +1565,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s assertWriteLocked(); if (_objectActions.contains(actionID)) { if (!simulation) { - EntityTree* entityTree = _element ? _element->getTree() : nullptr; + EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; simulation = entityTree ? entityTree->getSimulation() : nullptr; } @@ -1633,7 +1621,7 @@ void EntityItem::deserializeActionsInternal() { // Keep track of which actions got added or updated by the new actionData - EntityTree* entityTree = _element ? _element->getTree() : nullptr; + EntityTreePointer entityTree = _element ? _element->getTree() : nullptr; assert(entityTree); EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr; assert(simulation); @@ -1770,8 +1758,6 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const { return result; } - - #define ENABLE_LOCKING 1 #ifdef ENABLE_LOCKING diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 54a524b5a2..fee2841ba3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -33,9 +33,11 @@ class EntitySimulation; class EntityTreeElement; class EntityTreeElementExtraEncodeData; - class EntityActionInterface; +class EntityTree; +typedef std::shared_ptr EntityTreePointer; typedef std::shared_ptr EntityActionPointer; +typedef std::shared_ptr EntityTreeElementPointer; namespace render { @@ -201,7 +203,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { return true; } // attributes applicable to all entity types @@ -216,7 +218,7 @@ public: inline const Transform& getTransform() const { return _transform; } inline void setTransform(const Transform& transform) { _transform = transform; requiresRecalcBoxes(); } - /// Position in meters (0.0 - TREE_SCALE) + /// Position in meters (-TREE_SCALE - TREE_SCALE) inline const glm::vec3& getPosition() const { return _transform.getTranslation(); } inline void setPosition(const glm::vec3& value) { _transform.setTranslation(value); requiresRecalcBoxes(); } @@ -388,7 +390,8 @@ public: void* getPhysicsInfo() const { return _physicsInfo; } void setPhysicsInfo(void* data) { _physicsInfo = data; } - EntityTreeElement* getElement() const { return _element; } + EntityTreeElementPointer getElement() const { return _element; } + EntityTreePointer getTree() const; static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } @@ -494,7 +497,7 @@ protected: uint32_t _dirtyFlags; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation // these backpointers are only ever set/cleared by friends: - EntityTreeElement* _element = nullptr; // set by EntityTreeElement + EntityTreeElementPointer _element = nullptr; // set by EntityTreeElement void* _physicsInfo = nullptr; // set by EntitySimulation bool _simulated; // set by EntitySimulation diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index b337c05776..85e2d4c7ba 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -47,19 +47,19 @@ bool EntityScriptingInterface::canRez() { return nodeList->getThisNodeCanRez(); } -void EntityScriptingInterface::setEntityTree(EntityTree* modelTree) { +void EntityScriptingInterface::setEntityTree(EntityTreePointer modelTree) { if (_entityTree) { - disconnect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); - disconnect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); - disconnect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); + disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); + disconnect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); + disconnect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); } _entityTree = modelTree; if (_entityTree) { - connect(_entityTree, &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); - connect(_entityTree, &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); - connect(_entityTree, &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); + connect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); + connect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); + connect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); } } @@ -280,7 +280,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke RayToEntityIntersectionResult result; if (_entityTree) { - OctreeElement* element; + OctreeElementPointer element; EntityItemPointer intersectedEntity = NULL; result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, (void**)&intersectedEntity, lockType, &result.accurate, diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index ff693e4585..50e30c4f37 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -23,6 +23,7 @@ #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" #include "PolyLineEntityItem.h" +#include "EntityTree.h" #include "EntityEditPacketSender.h" @@ -60,8 +61,8 @@ public: virtual NodeType_t getServerNodeType() const { return NodeType::EntityServer; } virtual OctreeEditPacketSender* createPacketSender() { return new EntityEditPacketSender(); } - void setEntityTree(EntityTree* modelTree); - EntityTree* getEntityTree() { return _entityTree; } + void setEntityTree(EntityTreePointer modelTree); + EntityTreePointer getEntityTree() { return _entityTree; } public slots: @@ -178,7 +179,7 @@ private: RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, bool precisionPicking); - EntityTree* _entityTree; + EntityTreePointer _entityTree; }; #endif // hifi_EntityScriptingInterface_h diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 06f5023193..92c1ca2c3b 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -15,7 +15,7 @@ #include "EntitiesLogging.h" #include "MovingEntitiesOperator.h" -void EntitySimulation::setEntityTree(EntityTree* tree) { +void EntitySimulation::setEntityTree(EntityTreePointer tree) { if (_entityTree && _entityTree != tree) { _mortalEntities.clear(); _nextExpiry = quint64(-1); diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index c1822abe77..ec42499d5b 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -51,7 +51,7 @@ public: void unlock() { _mutex.unlock(); } /// \param tree pointer to EntityTree which is stored internally - void setEntityTree(EntityTree* tree); + void setEntityTree(EntityTreePointer tree); void updateEntities(); @@ -82,7 +82,7 @@ protected: // these only called by the EntityTree? public: - EntityTree* getEntityTree() { return _entityTree; } + EntityTreePointer getEntityTree() { return _entityTree; } void getEntitiesToDelete(VectorOfEntities& entitiesToDelete); @@ -106,7 +106,7 @@ protected: QMutex _mutex; // back pointer to EntityTree structure - EntityTree* _entityTree; + EntityTreePointer _entityTree; // We maintain multiple lists, each for its distinct purpose. // An entity may be in more than one list. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index ba0e3f495f..3d2ebf046e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -31,7 +31,6 @@ EntityTree::EntityTree(bool shouldReaverage) : _fbxService(NULL), _simulation(NULL) { - _rootElement = createNewElement(); resetClientEditStats(); } @@ -39,10 +38,19 @@ EntityTree::~EntityTree() { eraseAllOctreeElements(false); } -EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) { - EntityTreeElement* newElement = new EntityTreeElement(octalCode); - newElement->setTree(this); - return newElement; +void EntityTree::createRootElement() { + _rootElement = createNewElement(); +} + +OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { + EntityTreeElementPointer newElement = EntityTreeElementPointer(new EntityTreeElement(octalCode), + // see comment int EntityTreeElement::createNewElement + [=](EntityTreeElement* elt) { + EntityTreeElementPointer tmpSharedPointer(elt); + elt->notifyDeleteHooks(); + }); + newElement->setTree(std::static_pointer_cast(shared_from_this())); + return std::static_pointer_cast(newElement); } void EntityTree::eraseAllOctreeElements(bool createNewRoot) { @@ -54,7 +62,7 @@ void EntityTree::eraseAllOctreeElements(bool createNewRoot) { _simulation->clearEntities(); _simulation->unlock(); } - foreach (EntityTreeElement* element, _entityToElementMap) { + foreach (EntityTreeElementPointer element, _entityToElementMap) { element->cleanupEntities(); } _entityToElementMap.clear(); @@ -90,7 +98,7 @@ void EntityTree::postAddEntity(EntityItemPointer entity) { } bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode) { - EntityTreeElement* containingElement = getContainingElement(entityID); + EntityTreeElementPointer containingElement = getContainingElement(entityID); if (!containingElement) { return false; } @@ -104,7 +112,7 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp } bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode) { - EntityTreeElement* containingElement = getContainingElement(entity->getEntityItemID()); + EntityTreeElementPointer containingElement = getContainingElement(entity->getEntityItemID()); if (!containingElement) { return false; } @@ -112,7 +120,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti } bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& origProperties, - EntityTreeElement* containingElement, const SharedNodePointer& senderNode) { + EntityTreeElementPointer containingElement, const SharedNodePointer& senderNode) { EntityItemProperties properties = origProperties; bool allowLockChange; @@ -139,7 +147,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI if (!wantsLocked) { EntityItemProperties tempProperties; tempProperties.setLocked(wantsLocked); - UpdateEntityOperator theOperator(this, containingElement, entity, tempProperties); + UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, tempProperties); recurseTreeWithOperator(&theOperator); _isDirty = true; } @@ -201,7 +209,7 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI quint64 entityScriptTimestampBefore = entity->getScriptTimestamp(); QString collisionSoundURLBefore = entity->getCollisionSoundURL(); uint32_t preFlags = entity->getDirtyFlags(); - UpdateEntityOperator theOperator(this, containingElement, entity, properties); + UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, properties); recurseTreeWithOperator(&theOperator); _isDirty = true; @@ -258,10 +266,10 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti } // You should not call this on existing entities that are already part of the tree! Call updateEntity() - EntityTreeElement* containingElement = getContainingElement(entityID); + EntityTreeElementPointer containingElement = getContainingElement(entityID); if (containingElement) { qCDebug(entities) << "UNEXPECTED!!! ----- don't call addEntity() on existing entity items. entityID=" << entityID - << "containingElement=" << containingElement; + << "containingElement=" << containingElement.get(); return result; } @@ -274,7 +282,7 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti result->recordCreationTime(); } // Recurse the tree and store the entity in the correct tree element - AddEntityOperator theOperator(this, result); + AddEntityOperator theOperator(getThisPointer(), result); recurseTreeWithOperator(&theOperator); postAddEntity(result); @@ -295,7 +303,7 @@ void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisio void EntityTree::setSimulation(EntitySimulation* simulation) { if (simulation) { // assert that the simulation's backpointer has already been properly connected - assert(simulation->getEntityTree() == this); + assert(simulation->getEntityTree().get() == this); } if (_simulation && _simulation != simulation) { // It's important to clearEntities() on the simulation since taht will update each @@ -308,7 +316,7 @@ void EntityTree::setSimulation(EntitySimulation* simulation) { } void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ignoreWarnings) { - EntityTreeElement* containingElement = getContainingElement(entityID); + EntityTreeElementPointer containingElement = getContainingElement(entityID); if (!containingElement) { if (!ignoreWarnings) { qCDebug(entities) << "UNEXPECTED!!!! EntityTree::deleteEntity() entityID doesn't exist!!! entityID=" << entityID; @@ -335,7 +343,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign emit deletingEntity(entityID); // NOTE: callers must lock the tree before using this method - DeleteEntityOperator theOperator(this, entityID); + DeleteEntityOperator theOperator(getThisPointer(), entityID); recurseTreeWithOperator(&theOperator); processRemovedEntities(theOperator); _isDirty = true; @@ -343,9 +351,9 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign void EntityTree::deleteEntities(QSet entityIDs, bool force, bool ignoreWarnings) { // NOTE: callers must lock the tree before using this method - DeleteEntityOperator theOperator(this); + DeleteEntityOperator theOperator(getThisPointer()); foreach(const EntityItemID& entityID, entityIDs) { - EntityTreeElement* containingElement = getContainingElement(entityID); + EntityTreeElementPointer containingElement = getContainingElement(entityID); if (!containingElement) { if (!ignoreWarnings) { qCDebug(entities) << "UNEXPECTED!!!! EntityTree::deleteEntities() entityID doesn't exist!!! entityID=" << entityID; @@ -418,9 +426,9 @@ public: }; -bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData) { +bool EntityTree::findNearPointOperation(OctreeElementPointer element, void* extraData) { FindNearPointArgs* args = static_cast(extraData); - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); glm::vec3 penetration; bool sphereIntersection = entityTreeElement->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration); @@ -470,14 +478,14 @@ public: }; -bool EntityTree::findInSphereOperation(OctreeElement* element, void* extraData) { +bool EntityTree::findInSphereOperation(OctreeElementPointer element, void* extraData) { FindAllNearPointArgs* args = static_cast(extraData); glm::vec3 penetration; bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration); // If this element contains the point, then search it... if (sphereIntersection) { - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->getEntities(args->position, args->targetRadius, args->entities); return true; // keep searching in case children have closer entities } @@ -506,10 +514,10 @@ public: QVector _foundEntities; }; -bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) { +bool EntityTree::findInCubeOperation(OctreeElementPointer element, void* extraData) { FindEntitiesInCubeArgs* args = static_cast(extraData); if (element->getAACube().touches(args->_cube)) { - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->getEntities(args->_cube, args->_foundEntities); return true; } @@ -535,10 +543,10 @@ public: QVector _foundEntities; }; -bool EntityTree::findInBoxOperation(OctreeElement* element, void* extraData) { +bool EntityTree::findInBoxOperation(OctreeElementPointer element, void* extraData) { FindEntitiesInBoxArgs* args = static_cast(extraData); if (element->getAACube().touches(args->_box)) { - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->getEntities(args->_box, args->_foundEntities); return true; } @@ -561,7 +569,7 @@ EntityItemPointer EntityTree::findEntityByID(const QUuid& id) { EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /*const*/ { EntityItemPointer foundEntity = NULL; - EntityTreeElement* containingElement = getContainingElement(entityID); + EntityTreeElementPointer containingElement = getContainingElement(entityID); if (containingElement) { foundEntity = containingElement->getEntityWithEntityItemID(entityID); } @@ -701,7 +709,7 @@ void EntityTree::removeNewlyCreatedHook(NewlyCreatedEntityHook* hook) { void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncodeData) const { - foreach(void* extraData, *extraEncodeData) { + for (auto extraData : extraEncodeData->values()) { EntityTreeElementExtraEncodeData* thisExtraEncodeData = static_cast(extraData); delete thisExtraEncodeData; } @@ -932,13 +940,13 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons return processedBytes; } -EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ { +EntityTreeElementPointer EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ { // TODO: do we need to make this thread safe? Or is it acceptable as is - EntityTreeElement* element = _entityToElementMap.value(entityItemID); + EntityTreeElementPointer element = _entityToElementMap.value(entityItemID); return element; } -void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element) { +void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTreeElementPointer element) { // TODO: do we need to make this thread safe? Or is it acceptable as is if (element) { _entityToElementMap[entityItemID] = element; @@ -949,25 +957,25 @@ void EntityTree::setContainingElement(const EntityItemID& entityItemID, EntityTr void EntityTree::debugDumpMap() { qCDebug(entities) << "EntityTree::debugDumpMap() --------------------------"; - QHashIterator i(_entityToElementMap); + QHashIterator i(_entityToElementMap); while (i.hasNext()) { i.next(); - qCDebug(entities) << i.key() << ": " << i.value(); + qCDebug(entities) << i.key() << ": " << i.value().get(); } qCDebug(entities) << "-----------------------------------------------------"; } class ContentsDimensionOperator : public RecurseOctreeOperator { public: - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element) { return true; } + virtual bool preRecursion(OctreeElementPointer element); + virtual bool postRecursion(OctreeElementPointer element) { return true; } float getLargestDimension() const { return _contentExtents.largestDimension(); } private: Extents _contentExtents; }; -bool ContentsDimensionOperator::preRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); +bool ContentsDimensionOperator::preRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->expandExtentsToContents(_contentExtents); return true; } @@ -980,13 +988,13 @@ float EntityTree::getContentsLargestDimension() { class DebugOperator : public RecurseOctreeOperator { public: - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element) { return true; } + virtual bool preRecursion(OctreeElementPointer element); + virtual bool postRecursion(OctreeElementPointer element) { return true; } }; -bool DebugOperator::preRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); - qCDebug(entities) << "EntityTreeElement [" << entityTreeElement << "]"; +bool DebugOperator::preRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); + qCDebug(entities) << "EntityTreeElement [" << entityTreeElement.get() << "]"; entityTreeElement->debugDump(); return true; } @@ -998,12 +1006,12 @@ void EntityTree::dumpTree() { class PruneOperator : public RecurseOctreeOperator { public: - virtual bool preRecursion(OctreeElement* element) { return true; } - virtual bool postRecursion(OctreeElement* element); + virtual bool preRecursion(OctreeElementPointer element) { return true; } + virtual bool postRecursion(OctreeElementPointer element); }; -bool PruneOperator::postRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); +bool PruneOperator::postRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->pruneChildren(); return true; } @@ -1013,7 +1021,8 @@ void EntityTree::pruneTree() { recurseTreeWithOperator(&theOperator); } -QVector EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z) { +QVector EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, + float x, float y, float z) { SendEntitiesOperationArgs args; args.packetSender = packetSender; args.localTree = localTree; @@ -1026,9 +1035,9 @@ QVector EntityTree::sendEntities(EntityEditPacketSender* packetSen return newEntityIDs; } -bool EntityTree::sendEntitiesOperation(OctreeElement* element, void* extraData) { +bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extraData) { SendEntitiesOperationArgs* args = static_cast(extraData); - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); const EntityItems& entities = entityTreeElement->getEntities(); for (int i = 0; i < entities.size(); i++) { @@ -1052,8 +1061,10 @@ bool EntityTree::sendEntitiesOperation(OctreeElement* element, void* extraData) return true; } -bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElement* element, bool skipDefaultValues) { - entityDescription["Entities"] = QVariantList(); +bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) { + if (! entityDescription.contains("Entities")) { + entityDescription["Entities"] = QVariantList(); + } QScriptEngine scriptEngine; RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues); recurseTreeWithOperator(&theOperator); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 4ade0afc6d..a813cd4846 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -17,6 +17,10 @@ #include +class EntityTree; +typedef std::shared_ptr EntityTreePointer; + + #include "EntityTreeElement.h" #include "DeleteEntityOperator.h" @@ -39,7 +43,7 @@ public: class SendEntitiesOperationArgs { public: glm::vec3 root; - EntityTree* localTree; + EntityTreePointer localTree; EntityEditPacketSender* packetSender; QVector* newEntityIDs; }; @@ -51,11 +55,18 @@ public: EntityTree(bool shouldReaverage = false); virtual ~EntityTree(); + void createRootElement(); + /// Implements our type specific root element factory - virtual EntityTreeElement* createNewElement(unsigned char * octalCode = NULL); + virtual OctreeElementPointer createNewElement(unsigned char* octalCode = NULL); /// Type safe version of getRoot() - EntityTreeElement* getRoot() { return static_cast(_rootElement); } + EntityTreeElementPointer getRoot() { + if (!_rootElement) { + createRootElement(); + } + return std::static_pointer_cast(_rootElement); + } virtual void eraseAllOctreeElements(bool createNewRoot = true); @@ -145,13 +156,14 @@ public: return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL; } - EntityTreeElement* getContainingElement(const EntityItemID& entityItemID) /*const*/; - void setContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element); + EntityTreeElementPointer getContainingElement(const EntityItemID& entityItemID) /*const*/; + void setContainingElement(const EntityItemID& entityItemID, EntityTreeElementPointer element); void debugDumpMap(); virtual void dumpTree(); virtual void pruneTree(); - QVector sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z); + QVector sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, + float x, float y, float z); void entityChanged(EntityItemPointer entity); @@ -163,7 +175,7 @@ public: bool wantEditLogging() const { return _wantEditLogging; } void setWantEditLogging(bool value) { _wantEditLogging = value; } - bool writeToMap(QVariantMap& entityDescription, OctreeElement* element, bool skipDefaultValues); + bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues); bool readFromMap(QVariantMap& entityDescription); float getContentsLargestDimension(); @@ -193,6 +205,8 @@ public: quint64 getMaxEditDelta() const { return _maxEditDelta; } quint64 getTotalTrackedEdits() const { return _totalTrackedEdits; } + EntityTreePointer getThisPointer() { return std::static_pointer_cast(shared_from_this()); } + signals: void deletingEntity(const EntityItemID& entityID); void addingEntity(const EntityItemID& entityID); @@ -204,13 +218,13 @@ private: void processRemovedEntities(const DeleteEntityOperator& theOperator); bool updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& properties, - EntityTreeElement* containingElement, + EntityTreeElementPointer containingElement, const SharedNodePointer& senderNode = SharedNodePointer(nullptr)); - static bool findNearPointOperation(OctreeElement* element, void* extraData); - static bool findInSphereOperation(OctreeElement* element, void* extraData); - static bool findInCubeOperation(OctreeElement* element, void* extraData); - static bool findInBoxOperation(OctreeElement* element, void* extraData); - static bool sendEntitiesOperation(OctreeElement* element, void* extraData); + static bool findNearPointOperation(OctreeElementPointer element, void* extraData); + static bool findInSphereOperation(OctreeElementPointer element, void* extraData); + static bool findInCubeOperation(OctreeElementPointer element, void* extraData); + static bool findInBoxOperation(OctreeElementPointer element, void* extraData); + static bool sendEntitiesOperation(OctreeElementPointer element, void* extraData); void notifyNewlyCreatedEntity(const EntityItem& newEntity, const SharedNodePointer& senderNode); @@ -221,7 +235,7 @@ private: QMultiMap _recentlyDeletedEntityItemIDs; EntityItemFBXService* _fbxService; - QHash _entityToElementMap; + QHash _entityToElementMap; EntitySimulation* _simulation; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index a023f46c5e..536c3d6d9f 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -30,26 +30,46 @@ EntityTreeElement::~EntityTreeElement() { // This will be called primarily on addChildAt(), which means we're adding a child of our // own type to our own tree. This means we should initialize that child with any tree and type -// specific settings that our children must have. -OctreeElement* EntityTreeElement::createNewElement(unsigned char* octalCode) { - EntityTreeElement* newChild = new EntityTreeElement(octalCode); +// specific settings that our children must have. +OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCode) { + EntityTreeElementPointer newChild = + EntityTreeElementPointer(new EntityTreeElement(octalCode), + // This is a little bit horrible, but I haven't found a better way. The OctreeElement + // destructor used to call notifyDeleteHooks(), which calls zero or more of + // OctreeElementDeleteHook::elementDeleted + // which (now) expects an OctreeElementPointer argument. The destructor doesn't have + // access to the shared pointer (which has had its reference count drop to zero, + // or the destructor wouldn't have been called). The destructor also can't + // make a new shared pointer -- shared_from_this() is forbidden in a destructor, and + // using OctreeElementPointer(this) also fails. So, I've installed a custom deleter: + [=](EntityTreeElement* elt) { + // make a new shared pointer with a reference count of 1 (and no custom deleter) + EntityTreeElementPointer tmpSharedPointer(elt); + // call notifyDeleteHooks which will use shared_from_this() to get this same + // shared pointer, for use with the elementDeleted calls. + elt->notifyDeleteHooks(); + // And now tmpSharedPointer's reference count drops to zero and the + // normal destructors are called. + }); newChild->setTree(_myTree); return newChild; } + + void EntityTreeElement::init(unsigned char* octalCode) { OctreeElement::init(octalCode); _entityItems = new EntityItems; _octreeMemoryUsage += sizeof(EntityTreeElement); } -EntityTreeElement* EntityTreeElement::addChildAtIndex(int index) { - EntityTreeElement* newElement = (EntityTreeElement*)OctreeElement::addChildAtIndex(index); - newElement->setTree(_myTree); +OctreeElementPointer EntityTreeElement::addChildAtIndex(int index) { + OctreeElementPointer newElement = OctreeElement::addChildAtIndex(index); + std::static_pointer_cast(newElement)->setTree(_myTree); return newElement; } -void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) const { +void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) const { qCDebug(entities) << "EntityTreeElement::debugExtraEncodeData()... "; qCDebug(entities) << " element:" << _cube; @@ -57,15 +77,15 @@ void EntityTreeElement::debugExtraEncodeData(EncodeBitstreamParams& params) cons assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes if (extraEncodeData->contains(this)) { - EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData - = static_cast(extraEncodeData->value(this)); + EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData + = static_cast(extraEncodeData->value(this)); qCDebug(entities) << " encode data:" << entityTreeElementExtraEncodeData; } else { qCDebug(entities) << " encode data: MISSING!!"; } } -void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) const { +void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) { OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes // Check to see if this element yet has encode data... if it doesn't create it @@ -73,7 +93,7 @@ void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData = new EntityTreeElementExtraEncodeData(); entityTreeElementExtraEncodeData->elementCompleted = (_entityItems->size() == 0); for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - EntityTreeElement* child = getChildAtIndex(i); + EntityTreeElementPointer child = getChildAtIndex(i); if (!child) { entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed } else { @@ -94,7 +114,7 @@ void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params) } } -bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const { +bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const { OctreeElementExtraEncodeData* extraEncodeData = params.extraEncodeData; assert(extraEncodeData); // EntityTrees always require extra encode data on their encoding passes @@ -115,7 +135,7 @@ bool EntityTreeElement::shouldIncludeChildData(int childIndex, EncodeBitstreamPa } bool EntityTreeElement::shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const { - EntityTreeElement* childElement = getChildAtIndex(childIndex); + EntityTreeElementPointer childElement = getChildAtIndex(childIndex); if (childElement->alreadyFullyEncoded(params)) { return false; } @@ -176,24 +196,24 @@ void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params, Oct // but not necessarily cleanup our own encode data... // // If we're really complete here's what must be true... - // 1) out own data must be complete + // 1) our own data must be complete // 2) the data for all our immediate children must be complete. // However, the following might also be the case... - // 1) it's ok for our child trees to not yet be fully encoded/complete... + // 1) it's ok for our child trees to not yet be fully encoded/complete... // SO LONG AS... the our child's node is in the bag ready for encoding bool someChildTreeNotComplete = false; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - EntityTreeElement* childElement = getChildAtIndex(i); + EntityTreeElementPointer childElement = getChildAtIndex(i); if (childElement) { // why would this ever fail??? // If we've encoding this element before... but we're coming back a second time in an attempt to // encoud our parent... this might happen. - if (extraEncodeData->contains(childElement)) { + if (extraEncodeData->contains(childElement.get())) { EntityTreeElementExtraEncodeData* childExtraEncodeData - = static_cast(extraEncodeData->value(childElement)); - + = static_cast(extraEncodeData->value(childElement.get())); + if (wantDebug) { qCDebug(entities) << "checking child: " << childElement->_cube; qCDebug(entities) << " childElement->isLeaf():" << childElement->isLeaf(); @@ -243,7 +263,8 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData = NULL; bool hadElementExtraData = false; if (extraEncodeData && extraEncodeData->contains(this)) { - entityTreeElementExtraEncodeData = static_cast(extraEncodeData->value(this)); + entityTreeElementExtraEncodeData = + static_cast(extraEncodeData->value(this)); hadElementExtraData = true; } else { // if there wasn't one already, then create one @@ -251,14 +272,15 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData entityTreeElementExtraEncodeData->elementCompleted = (_entityItems->size() == 0); for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - EntityTreeElement* child = getChildAtIndex(i); + EntityTreeElementPointer child = getChildAtIndex(i); if (!child) { entityTreeElementExtraEncodeData->childCompleted[i] = true; // if no child exists, it is completed } else { if (child->hasEntities()) { entityTreeElementExtraEncodeData->childCompleted[i] = false; } else { - entityTreeElementExtraEncodeData->childCompleted[i] = true; // if the child doesn't have enities, it is completed + // if the child doesn't have enities, it is completed + entityTreeElementExtraEncodeData->childCompleted[i] = true; } } } @@ -300,7 +322,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData // we want to use the maximum possible box for this, so that we don't have to worry about the nuance of // simulation changing what's visible. consider the case where the entity contains an angular velocity - // the entity may not be in view and then in view a frame later, let the client side handle it's view + // the entity may not be in view and then in view a frame later, let the client side handle its view // frustum culling on rendering. AACube entityCube = entity->getMaximumAACube(); if (params.viewFrustum->cubeInFrustum(entityCube) == ViewFrustum::OUTSIDE) { @@ -322,8 +344,8 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData foreach (uint16_t i, indexesOfEntitiesToInclude) { EntityItemPointer entity = (*_entityItems)[i]; LevelDetails entityLevel = packetData->startLevel(); - OctreeElement::AppendState appendEntityState = entity->appendEntityData(packetData, - params, entityTreeElementExtraEncodeData); + OctreeElement::AppendState appendEntityState = + entity->appendEntityData(packetData, params, entityTreeElementExtraEncodeData); // If none of this entity data was able to be appended, then discard it // and don't include it in our entity count @@ -473,7 +495,7 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 } bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... @@ -671,7 +693,7 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) { bool EntityTreeElement::removeEntityItem(EntityItemPointer entity) { int numEntries = _entityItems->removeAll(entity); if (numEntries > 0) { - assert(entity->_element == this); + assert(entity->_element.get() == this); entity->_element = NULL; return true; } @@ -694,7 +716,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int ReadBitstreamToTreeParams& args) { // If we're the root, but this bitstream doesn't support root elements with data, then // return without reading any bytes - if (this == _myTree->getRoot() && args.bitstreamVersion < VERSION_ROOT_ELEMENT_HAS_DATA) { + if (this == _myTree->getRoot().get() && args.bitstreamVersion < VERSION_ROOT_ELEMENT_HAS_DATA) { return 0; } @@ -737,7 +759,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int QString entityScriptBefore = entityItem->getScript(); quint64 entityScriptTimestampBefore = entityItem->getScriptTimestamp(); bool bestFitBefore = bestFitEntityBounds(entityItem); - EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); + EntityTreeElementPointer currentContainingElement = _myTree->getContainingElement(entityItemID); bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); if (entityItem->getDirtyFlags()) { @@ -746,13 +768,13 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bool bestFitAfter = bestFitEntityBounds(entityItem); if (bestFitBefore != bestFitAfter) { - // This is the case where the entity existed, and is in some element in our tree... + // This is the case where the entity existed, and is in some element in our tree... if (!bestFitBefore && bestFitAfter) { // This is the case where the entity existed, and is in some element in our tree... - if (currentContainingElement != this) { + if (currentContainingElement.get() != this) { currentContainingElement->removeEntityItem(entityItem); addEntityItem(entityItem); - _myTree->setContainingElement(entityItemID, this); + _myTree->setContainingElement(entityItemID, getThisPointer()); } } } @@ -770,7 +792,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); addEntityItem(entityItem); // add this new entity to this elements entities entityItemID = entityItem->getEntityItemID(); - _myTree->setContainingElement(entityItemID, this); + _myTree->setContainingElement(entityItemID, getThisPointer()); _myTree->postAddEntity(entityItem); if (entityItem->getCreated() == UNKNOWN_CREATED_TIME) { entityItem->recordCreationTime(); @@ -790,9 +812,9 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int void EntityTreeElement::addEntityItem(EntityItemPointer entity) { assert(entity); - assert(entity->_element == NULL); + assert(entity->_element == nullptr); _entityItems->push_back(entity); - entity->_element = this; + entity->_element = getThisPointer(); } // will average a "common reduced LOD view" from the the child elements... @@ -812,7 +834,7 @@ bool EntityTreeElement::collapseChildren() { bool EntityTreeElement::pruneChildren() { bool somethingPruned = false; for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { - EntityTreeElement* child = getChildAtIndex(childIndex); + EntityTreeElementPointer child = getChildAtIndex(childIndex); // if my child is a leaf, but has no entities, then it's safe to delete my child if (child && child->isLeaf() && !child->hasEntities()) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 05d1904384..ca56e9b0fb 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -25,6 +25,7 @@ typedef QVector EntityItems; class EntityTree; class EntityTreeElement; +typedef std::shared_ptr EntityTreeElementPointer; class EntityTreeUpdateArgs { public: @@ -79,18 +80,20 @@ class EntityTreeElement : public OctreeElement { EntityTreeElement(unsigned char* octalCode = NULL); - virtual OctreeElement* createNewElement(unsigned char* octalCode = NULL); + virtual OctreeElementPointer createNewElement(unsigned char* octalCode = NULL); public: virtual ~EntityTreeElement(); // type safe versions of OctreeElement methods - EntityTreeElement* getChildAtIndex(int index) const { return (EntityTreeElement*)OctreeElement::getChildAtIndex(index); } + EntityTreeElementPointer getChildAtIndex(int index) const { + return std::static_pointer_cast(OctreeElement::getChildAtIndex(index)); + } // methods you can and should override to implement your tree functionality /// Adds a child to the current element. Override this if there is additional child initialization your class needs. - virtual EntityTreeElement* addChildAtIndex(int index); + virtual OctreeElementPointer addChildAtIndex(int index); /// Override this to implement LOD averaging on changes to the tree. virtual void calculateAverageFromChildren(); @@ -115,7 +118,7 @@ public: virtual bool requiresSplit() const { return false; } virtual void debugExtraEncodeData(EncodeBitstreamParams& params) const; - virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) const; + virtual void initializeExtraEncodeData(EncodeBitstreamParams& params); virtual bool shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const; virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const; virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const; @@ -140,7 +143,7 @@ public: virtual bool canRayIntersect() const { return hasEntities(); } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, @@ -151,8 +154,8 @@ public: bool hasEntities() const { return _entityItems ? _entityItems->size() > 0 : false; } - void setTree(EntityTree* tree) { _myTree = tree; } - EntityTree* getTree() const { return _myTree; } + void setTree(EntityTreePointer tree) { _myTree = tree; } + EntityTreePointer getTree() const { return _myTree; } bool updateEntity(const EntityItem& entity); void addEntityItem(EntityItemPointer entity); @@ -201,9 +204,19 @@ public: void expandExtentsToContents(Extents& extents); + EntityTreeElementPointer getThisPointer() { + return std::static_pointer_cast(shared_from_this()); + } + OctreeElementPointer getThisOctreeElementPointer() { + return std::static_pointer_cast(shared_from_this()); + } + const ConstOctreeElementPointer getConstThisOctreeElementPointer() const { + return std::static_pointer_cast(shared_from_this()); + } + protected: virtual void init(unsigned char * octalCode); - EntityTree* _myTree; + EntityTreePointer _myTree; EntityItems* _entityItems; }; diff --git a/libraries/entities/src/EntityTreeHeadlessViewer.cpp b/libraries/entities/src/EntityTreeHeadlessViewer.cpp index 80c0a7fa7f..fd1191b968 100644 --- a/libraries/entities/src/EntityTreeHeadlessViewer.cpp +++ b/libraries/entities/src/EntityTreeHeadlessViewer.cpp @@ -23,7 +23,7 @@ void EntityTreeHeadlessViewer::init() { OctreeHeadlessViewer::init(); if (!_simulation) { SimpleEntitySimulation* simpleSimulation = new SimpleEntitySimulation(); - EntityTree* entityTree = static_cast(_tree); + EntityTreePointer entityTree = std::static_pointer_cast(_tree); simpleSimulation->setEntityTree(entityTree); entityTree->setSimulation(simpleSimulation); _simulation = simpleSimulation; @@ -32,7 +32,7 @@ void EntityTreeHeadlessViewer::init() { void EntityTreeHeadlessViewer::update() { if (_tree) { - EntityTree* tree = static_cast(_tree); + EntityTreePointer tree = std::static_pointer_cast(_tree); if (tree->tryLockForWrite()) { tree->update(); tree->unlock(); @@ -41,5 +41,5 @@ void EntityTreeHeadlessViewer::update() { } void EntityTreeHeadlessViewer::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) { - static_cast(_tree)->processEraseMessage(packet, sourceNode); + std::static_pointer_cast(_tree)->processEraseMessage(packet, sourceNode); } diff --git a/libraries/entities/src/EntityTreeHeadlessViewer.h b/libraries/entities/src/EntityTreeHeadlessViewer.h index a14fe14a71..da4ad0eace 100644 --- a/libraries/entities/src/EntityTreeHeadlessViewer.h +++ b/libraries/entities/src/EntityTreeHeadlessViewer.h @@ -36,14 +36,18 @@ public: void update(); - EntityTree* getTree() { return (EntityTree*)_tree; } + EntityTreePointer getTree() { return std::static_pointer_cast(_tree); } void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); virtual void init(); protected: - virtual Octree* createTree() { return new EntityTree(true); } + virtual OctreePointer createTree() { + EntityTreePointer newTree = EntityTreePointer(new EntityTree(true)); + newTree->createRootElement(); + return newTree; + } EntitySimulation* _simulation; }; diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 6d0f00ef04..3b7590a460 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -64,7 +64,7 @@ class LineEntityItem : public EntityItem { // never have a ray intersection pick a LineEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { return false; } virtual void debugDump() const; diff --git a/libraries/entities/src/MovingEntitiesOperator.cpp b/libraries/entities/src/MovingEntitiesOperator.cpp index 7dd1ab849c..0002ebb570 100644 --- a/libraries/entities/src/MovingEntitiesOperator.cpp +++ b/libraries/entities/src/MovingEntitiesOperator.cpp @@ -16,7 +16,7 @@ #include "MovingEntitiesOperator.h" -MovingEntitiesOperator::MovingEntitiesOperator(EntityTree* tree) : +MovingEntitiesOperator::MovingEntitiesOperator(EntityTreePointer tree) : _tree(tree), _changeTime(usecTimestampNow()), _foundOldCount(0), @@ -51,7 +51,7 @@ MovingEntitiesOperator::~MovingEntitiesOperator() { void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const AACube& newCube) { - EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID()); + EntityTreeElementPointer oldContainingElement = _tree->getContainingElement(entity->getEntityItemID()); AABox newCubeClamped = newCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); if (_wantDebug) { @@ -109,7 +109,7 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const } // does this entity tree element contain the old entity -bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) { +bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElementPointer element) { bool containsEntity = false; // If we don't have an old entity, then we don't contain the entity, otherwise @@ -141,8 +141,8 @@ bool MovingEntitiesOperator::shouldRecurseSubTree(OctreeElement* element) { return containsEntity; } -bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); +bool MovingEntitiesOperator::preRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if @@ -169,7 +169,7 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { qCDebug(entities) << " entityTreeElement->bestFitBounds(details.newCube):" << entityTreeElement->bestFitBounds(details.newCube); qCDebug(entities) << " details.entity:" << details.entity->getEntityItemID(); qCDebug(entities) << " details.oldContainingElementCube:" << details.oldContainingElementCube; - qCDebug(entities) << " entityTreeElement:" << entityTreeElement; + qCDebug(entities) << " entityTreeElement:" << entityTreeElement.get(); qCDebug(entities) << " details.newCube:" << details.newCube; qCDebug(entities) << " details.newCubeClamped:" << details.newCubeClamped; qCDebug(entities) << " _lookingCount:" << _lookingCount; @@ -195,7 +195,7 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { if (!details.newFound && entityTreeElement->bestFitBounds(details.newCube)) { EntityItemID entityItemID = details.entity->getEntityItemID(); // remove from the old before adding - EntityTreeElement* oldElement = details.entity->getElement(); + EntityTreeElementPointer oldElement = details.entity->getElement(); if (oldElement != entityTreeElement) { if (oldElement) { oldElement->removeEntityItem(details.entity); @@ -221,7 +221,7 @@ bool MovingEntitiesOperator::preRecursion(OctreeElement* element) { return keepSearching; // if we haven't yet found it, keep looking } -bool MovingEntitiesOperator::postRecursion(OctreeElement* element) { +bool MovingEntitiesOperator::postRecursion(OctreeElementPointer 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 entity and one for the new entity. @@ -254,14 +254,14 @@ bool MovingEntitiesOperator::postRecursion(OctreeElement* element) { } } if (!elementSubTreeContainsOldElements || !elementIsDirectParentOfOldElment) { - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves } return keepSearching; // if we haven't yet found it, keep looking } -OctreeElement* MovingEntitiesOperator::possiblyCreateChildAt(OctreeElement* element, int childIndex) { +OctreeElementPointer MovingEntitiesOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { // If we're getting called, it's because there was no child element at this index while recursing. // We only care if this happens while still searching for the new entity locations. if (_foundNewCount < _lookingCount) { diff --git a/libraries/entities/src/MovingEntitiesOperator.h b/libraries/entities/src/MovingEntitiesOperator.h index bef17058f4..5d16c41543 100644 --- a/libraries/entities/src/MovingEntitiesOperator.h +++ b/libraries/entities/src/MovingEntitiesOperator.h @@ -18,7 +18,7 @@ public: AACube oldCube; // meters AACube newCube; // meters AABox newCubeClamped; // meters - EntityTreeElement* oldContainingElement; + EntityTreeElementPointer oldContainingElement; AACube oldContainingElementCube; // meters bool oldFound; bool newFound; @@ -34,22 +34,22 @@ inline bool operator==(const EntityToMoveDetails& a, const EntityToMoveDetails& class MovingEntitiesOperator : public RecurseOctreeOperator { public: - MovingEntitiesOperator(EntityTree* tree); + MovingEntitiesOperator(EntityTreePointer tree); ~MovingEntitiesOperator(); void addEntityToMoveList(EntityItemPointer entity, const AACube& newCube); - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element); - virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex); + virtual bool preRecursion(OctreeElementPointer element); + virtual bool postRecursion(OctreeElementPointer element); + virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex); bool hasMovingEntities() const { return _entitiesToMove.size() > 0; } private: - EntityTree* _tree; + EntityTreePointer _tree; QSet _entitiesToMove; quint64 _changeTime; int _foundOldCount; int _foundNewCount; int _lookingCount; - bool shouldRecurseSubTree(OctreeElement* element); + bool shouldRecurseSubTree(OctreeElementPointer element); bool _wantDebug; }; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 25b348fa55..e5fdcf9b78 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -73,7 +73,7 @@ class PolyLineEntityItem : public EntityItem { // never have a ray intersection pick a PolyLineEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { return false; } virtual void debugDump() const; diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 20a0646c9b..31906a9cc0 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -44,7 +44,7 @@ class PolyVoxEntityItem : public EntityItem { // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { return false; } virtual void debugDump() const; diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.cpp b/libraries/entities/src/RecurseOctreeToMapOperator.cpp index 167e3513c1..a249262b2b 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.cpp +++ b/libraries/entities/src/RecurseOctreeToMapOperator.cpp @@ -13,8 +13,8 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, - OctreeElement *top, - QScriptEngine *engine, + OctreeElementPointer top, + QScriptEngine* engine, bool skipDefaultValues) : RecurseOctreeOperator(), _map(map), @@ -22,7 +22,7 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, _engine(engine), _skipDefaultValues(skipDefaultValues) { - // if some element "top" was given, only save information for that element and it's children. + // if some element "top" was given, only save information for that element and its children. if (_top) { _withinTop = false; } else { @@ -31,18 +31,15 @@ RecurseOctreeToMapOperator::RecurseOctreeToMapOperator(QVariantMap& map, } }; -bool RecurseOctreeToMapOperator::preRecursion(OctreeElement* element) { +bool RecurseOctreeToMapOperator::preRecursion(OctreeElementPointer element) { if (element == _top) { _withinTop = true; } return true; } -bool RecurseOctreeToMapOperator::postRecursion(OctreeElement* element) { - - EntityItemProperties defaultProperties; - - EntityTreeElement* entityTreeElement = static_cast(element); +bool RecurseOctreeToMapOperator::postRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); const EntityItems& entities = entityTreeElement->getEntities(); QVariantList entitiesQList = qvariant_cast(_map["Entities"]); diff --git a/libraries/entities/src/RecurseOctreeToMapOperator.h b/libraries/entities/src/RecurseOctreeToMapOperator.h index bfa5024b09..35c7f1b6a9 100644 --- a/libraries/entities/src/RecurseOctreeToMapOperator.h +++ b/libraries/entities/src/RecurseOctreeToMapOperator.h @@ -13,13 +13,13 @@ class RecurseOctreeToMapOperator : public RecurseOctreeOperator { public: - RecurseOctreeToMapOperator(QVariantMap& map, OctreeElement *top, QScriptEngine *engine, bool skipDefaultValues); - bool preRecursion(OctreeElement* element); - bool postRecursion(OctreeElement* element); + RecurseOctreeToMapOperator(QVariantMap& map, OctreeElementPointer top, QScriptEngine* engine, bool skipDefaultValues); + bool preRecursion(OctreeElementPointer element); + bool postRecursion(OctreeElementPointer element); private: QVariantMap& _map; - OctreeElement *_top; - QScriptEngine *_engine; + OctreeElementPointer _top; + QScriptEngine* _engine; bool _withinTop; bool _skipDefaultValues; }; diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index c77a513cfc..48eb5e01f7 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -94,8 +94,9 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi } bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const { + bool& keepSearching, OctreeElementPointer& element, + float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const { // determine the ray in the frame of the entity transformed from a unit sphere glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix(); glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 94c1d77096..3b29a3a1f5 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -54,7 +54,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; virtual void debugDump() const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 3ab15ba6cb..61730b208c 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -129,7 +129,7 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits } bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index bf03c192c7..a659f3c39b 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -47,7 +47,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; static const QString DEFAULT_TEXT; diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 991d725f97..5d6f3986b2 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -16,14 +16,14 @@ #include "UpdateEntityOperator.h" -UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, - EntityTreeElement* containingElement, - EntityItemPointer existingEntity, +UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree, + EntityTreeElementPointer containingElement, + EntityItemPointer existingEntity, const EntityItemProperties& properties) : _tree(tree), _existingEntity(existingEntity), _containingElement(containingElement), - _containingElementCube(containingElement->getAACube()), + _containingElementCube(containingElement->getAACube()), _properties(properties), _entityItemID(existingEntity->getEntityItemID()), _foundOld(false), @@ -37,10 +37,10 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree, { // caller must have verified existence of containingElement and oldEntity assert(_containingElement && _existingEntity); - + if (_wantDebug) { qCDebug(entities) << "UpdateEntityOperator::UpdateEntityOperator() -----------------------------"; - } + } // Here we have a choice to make, do we want to "tight fit" the actual minimum for the // entity into the the element, or do we want to use the entities "relaxed" bounds @@ -144,7 +144,7 @@ UpdateEntityOperator::~UpdateEntityOperator() { // does this entity tree element contain the old entity -bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) { +bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElementPointer element) { // We've found cases where the old entity might be placed in an element that is not actually the best fit // so when we're searching the tree for the old element, we use the known cube for the known containing element @@ -162,7 +162,7 @@ bool UpdateEntityOperator::subTreeContainsOldEntity(OctreeElement* element) { return elementContainsOldBox; } -bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElement* element) { +bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElementPointer element) { bool elementContainsNewBox = element->getAACube().contains(_newEntityBox); if (_wantDebug) { @@ -179,8 +179,8 @@ bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElement* element) { } -bool UpdateEntityOperator::preRecursion(OctreeElement* element) { - EntityTreeElement* entityTreeElement = static_cast(element); +bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if @@ -211,8 +211,8 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { if (_wantDebug) { qCDebug(entities) << " OLD TREE CASE...."; - qCDebug(entities) << " entityTreeElement=" << entityTreeElement; - qCDebug(entities) << " _containingElement=" << _containingElement; + qCDebug(entities) << " entityTreeElement=" << entityTreeElement.get(); + qCDebug(entities) << " _containingElement=" << _containingElement.get(); } // If this is the element we're looking for, then ask it to remove the old entity @@ -234,7 +234,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { // the entity knows what element it's in, so we remove it from that one // NOTE: we know we haven't yet added it to its new element because _removeOld is true - EntityTreeElement* oldElement = _existingEntity->getElement(); + EntityTreeElementPointer oldElement = _existingEntity->getElement(); oldElement->removeEntityItem(_existingEntity); _tree->setContainingElement(_entityItemID, NULL); @@ -260,8 +260,8 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { if (_wantDebug) { qCDebug(entities) << " NEW TREE CASE...."; - qCDebug(entities) << " entityTreeElement=" << entityTreeElement; - qCDebug(entities) << " _containingElement=" << _containingElement; + qCDebug(entities) << " entityTreeElement=" << entityTreeElement.get(); + qCDebug(entities) << " _containingElement=" << _containingElement.get(); qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox); } @@ -272,7 +272,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { qCDebug(entities) << " *** THIS ELEMENT IS BEST FIT ***"; } - EntityTreeElement* oldElement = _existingEntity->getElement(); + EntityTreeElementPointer oldElement = _existingEntity->getElement(); // if we are the existing containing element, then we can just do the update of the entity properties if (entityTreeElement == oldElement) { @@ -317,7 +317,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElement* element) { return keepSearching; // if we haven't yet found it, keep looking } -bool UpdateEntityOperator::postRecursion(OctreeElement* element) { +bool UpdateEntityOperator::postRecursion(OctreeElementPointer 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 entity and one for the new entity. @@ -342,14 +342,14 @@ bool UpdateEntityOperator::postRecursion(OctreeElement* element) { // 2) we are removing the old, but this subtree doesn't contain the old // 3) we are removing the old, this subtree contains the old, but this element isn't a direct parent of _containingElement if (!_removeOld || !subtreeContainsOld || !element->isParentOf(_containingElement)) { - EntityTreeElement* entityTreeElement = static_cast(element); + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves } return keepSearching; // if we haven't yet found it, keep looking } -OctreeElement* UpdateEntityOperator::possiblyCreateChildAt(OctreeElement* element, int childIndex) { +OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { // If we're getting called, it's because there was no child element at this index while recursing. // We only care if this happens while still searching for the new entity location. // Check to see if diff --git a/libraries/entities/src/UpdateEntityOperator.h b/libraries/entities/src/UpdateEntityOperator.h index 5091ef4c5d..f1c791f9f1 100644 --- a/libraries/entities/src/UpdateEntityOperator.h +++ b/libraries/entities/src/UpdateEntityOperator.h @@ -14,17 +14,17 @@ class UpdateEntityOperator : public RecurseOctreeOperator { public: - UpdateEntityOperator(EntityTree* tree, EntityTreeElement* containingElement, - EntityItemPointer existingEntity, const EntityItemProperties& properties); + UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement, + EntityItemPointer existingEntity, const EntityItemProperties& properties); ~UpdateEntityOperator(); - - virtual bool preRecursion(OctreeElement* element); - virtual bool postRecursion(OctreeElement* element); - virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex); + + virtual bool preRecursion(OctreeElementPointer element); + virtual bool postRecursion(OctreeElementPointer element); + virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex); private: - EntityTree* _tree; + EntityTreePointer _tree; EntityItemPointer _existingEntity; - EntityTreeElement* _containingElement; + EntityTreeElementPointer _containingElement; AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element EntityItemProperties _properties; EntityItemID _entityItemID; @@ -40,8 +40,8 @@ private: AABox _oldEntityBox; // clamped to domain AABox _newEntityBox; // clamped to domain - bool subTreeContainsOldEntity(OctreeElement* element); - bool subTreeContainsNewEntity(OctreeElement* element); + bool subTreeContainsOldEntity(OctreeElementPointer element); + bool subTreeContainsNewEntity(OctreeElementPointer element); bool _wantDebug; }; diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index c3dc757199..041022a916 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -99,7 +99,7 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst } bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index d98eab8d24..24e19e1cb1 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -46,7 +46,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; virtual void setSourceUrl(const QString& value); diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index fb8ec325a3..fed85bf6a5 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -246,7 +246,7 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) { } bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const { return _zonesArePickable; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 1aa3f3e13a..e112103529 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -15,7 +15,8 @@ #include #include "AtmospherePropertyGroup.h" -#include "EntityItem.h" +#include "EntityItem.h" +#include "EntityTree.h" class ZoneEntityItem : public EntityItem { public: @@ -99,7 +100,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) const; virtual void debugDump() const; @@ -129,6 +130,8 @@ protected: static bool _drawZoneBoundaries; static bool _zonesArePickable; + + EntityTreePointer subTree; }; #endif // hifi_ZoneEntityItem_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 93933c5301..e7f265b4f2 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -71,6 +71,44 @@ Octree::~Octree() { eraseAllOctreeElements(false); } + +// Inserts the value and key into three arrays sorted by the key array, the first array is the value, +// the second array is a sorted key for the value, the third array is the index for the value in it original +// non-sorted array +// returns -1 if size exceeded +// originalIndexArray is optional +int insertOctreeElementIntoSortedArrays(OctreeElementPointer value, float key, int originalIndex, + OctreeElementPointer* valueArray, float* keyArray, int* originalIndexArray, + int currentCount, int maxCount) { + + if (currentCount < maxCount) { + int i = 0; + if (currentCount > 0) { + while (i < currentCount && key > keyArray[i]) { + i++; + } + // i is our desired location + // shift array elements to the right + if (i < currentCount && i+1 < maxCount) { + for (int j = currentCount - 1; j > i; j--) { + valueArray[j] = valueArray[j - 1]; + keyArray[j] = keyArray[j - 1]; + } + } + } + // place new element at i + valueArray[i] = value; + keyArray[i] = key; + if (originalIndexArray) { + originalIndexArray[i] = originalIndex; + } + return currentCount + 1; + } + return -1; // error case +} + + + // Recurses voxel tree calling the RecurseOctreeOperation function for each element. // stops recursion if operation function returns false. void Octree::recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData) { @@ -83,7 +121,7 @@ void Octree::recurseTreeWithPostOperation(RecurseOctreeOperation operation, void } // Recurses voxel element with an operation function -void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, +void Octree::recurseElementWithOperation(OctreeElementPointer element, RecurseOctreeOperation operation, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage @@ -96,7 +134,7 @@ void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOp if (operation(element, extraData)) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* child = element->getChildAtIndex(i); + OctreeElementPointer child = element->getChildAtIndex(i); if (child) { recurseElementWithOperation(child, operation, extraData, recursionCount+1); } @@ -105,8 +143,8 @@ void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOp } // Recurses voxel element with an operation function -void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, void* extraData, - int recursionCount) { +void Octree::recurseElementWithPostOperation(OctreeElementPointer element, RecurseOctreeOperation operation, + void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( @@ -117,7 +155,7 @@ void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctr } for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* child = element->getChildAtIndex(i); + OctreeElementPointer child = element->getChildAtIndex(i); if (child) { recurseElementWithPostOperation(child, operation, extraData, recursionCount+1); } @@ -134,7 +172,7 @@ void Octree::recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation opera } // Recurses voxel element with an operation function -void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, +void Octree::recurseElementWithOperationDistanceSorted(OctreeElementPointer element, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { @@ -148,24 +186,24 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R if (operation(element, extraData)) { // determine the distance sorted order of our children - OctreeElement* sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + OctreeElementPointer sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; float distancesToChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int indexOfChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int currentCount = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childElement = element->getChildAtIndex(i); + OctreeElementPointer childElement = element->getChildAtIndex(i); if (childElement) { // chance to optimize, doesn't need to be actual distance!! Could be distance squared float distanceSquared = childElement->distanceSquareToPoint(point); - currentCount = insertIntoSortedArrays((void*)childElement, distanceSquared, i, - (void**)&sortedChildren, (float*)&distancesToChildren, - (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); + currentCount = insertOctreeElementIntoSortedArrays(childElement, distanceSquared, i, + sortedChildren, (float*)&distancesToChildren, + (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); } } for (int i = 0; i < currentCount; i++) { - OctreeElement* childElement = sortedChildren[i]; + OctreeElementPointer childElement = sortedChildren[i]; if (childElement) { recurseElementWithOperationDistanceSorted(childElement, operation, point, extraData); } @@ -177,7 +215,8 @@ void Octree::recurseTreeWithOperator(RecurseOctreeOperator* operatorObject) { recurseElementWithOperator(_rootElement, operatorObject); } -bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount) { +bool Octree::recurseElementWithOperator(OctreeElementPointer element, + RecurseOctreeOperator* operatorObject, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( @@ -189,7 +228,7 @@ bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOpe if (operatorObject->preRecursion(element)) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* child = element->getChildAtIndex(i); + OctreeElementPointer child = element->getChildAtIndex(i); // If there is no child at that location, the Operator may want to create a child at that location. // So give the operator a chance to do so.... @@ -209,8 +248,8 @@ bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOpe } -OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement, - const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const { +OctreeElementPointer Octree::nodeForOctalCode(OctreeElementPointer ancestorElement, const unsigned char* needleCode, + OctreeElementPointer* parentOfFoundElement) const { // special case for NULL octcode if (!needleCode) { return _rootElement; @@ -219,7 +258,7 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement, // find the appropriate branch index based on this ancestorElement if (*needleCode > 0) { int branchForNeedle = branchIndexWithDescendant(ancestorElement->getOctalCode(), needleCode); - OctreeElement* childElement = ancestorElement->getChildAtIndex(branchForNeedle); + OctreeElementPointer childElement = ancestorElement->getChildAtIndex(branchForNeedle); if (childElement) { if (*childElement->getOctalCode() == *needleCode) { @@ -245,7 +284,8 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement, } // returns the element created! -OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount) { +OctreeElementPointer Octree::createMissingElement(OctreeElementPointer lastParentElement, + const unsigned char* codeToReach, int recursionCount) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { static QString repeatedMessage @@ -274,7 +314,7 @@ OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, co } } -int Octree::readElementData(OctreeElement* destinationElement, const unsigned char* nodeData, int bytesAvailable, +int Octree::readElementData(OctreeElementPointer destinationElement, const unsigned char* nodeData, int bytesAvailable, ReadBitstreamToTreeParams& args) { int bytesLeftToRead = bytesAvailable; @@ -305,7 +345,7 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch if (oneAtBit(colorInPacketMask, i)) { // addChildAtIndex() should actually be called getOrAddChildAtIndex(). // When it adds the child it automatically sets the detinationElement dirty. - OctreeElement* childElementAt = destinationElement->addChildAtIndex(i); + OctreeElementPointer childElementAt = destinationElement->addChildAtIndex(i); int childElementDataRead = childElementAt->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args); childElementAt->setSourceUUID(args.sourceUUID); @@ -405,7 +445,8 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long // if there are more bytes after that, it's assumed to be another root relative tree while (bitstreamAt < bitstream + bufferSizeBytes) { - OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL); + OctreeElementPointer bitstreamRootElement = nodeForOctalCode(args.destinationElement, + (unsigned char *)bitstreamAt, NULL); int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes); if (numberOfThreeBitSectionsInStream > UNREASONABLY_DEEP_RECURSION) { static QString repeatedMessage @@ -491,7 +532,7 @@ void Octree::deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool colla deleteOctalCodeFromTreeRecursion(_rootElement, &args); } -void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extraData) { +void Octree::deleteOctalCodeFromTreeRecursion(OctreeElementPointer element, void* extraData) { DeleteOctalCodeFromTreeArgs* args = (DeleteOctalCodeFromTreeArgs*)extraData; int lengthOfElementCode = numberOfThreeBitSectionsInCode(element->getOctalCode()); @@ -508,14 +549,14 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extr // Ok, we know we haven't reached our target element yet, so keep looking int childIndex = branchIndexWithDescendant(element->getOctalCode(), args->codeBuffer); - OctreeElement* childElement = element->getChildAtIndex(childIndex); + OctreeElementPointer childElement = element->getChildAtIndex(childIndex); // If there is no child at the target location, and the current parent element is a colored leaf, // then it means we were asked to delete a child out of a larger leaf voxel. // We support this by breaking up the parent voxel into smaller pieces. if (!childElement && element->requiresSplit()) { // we need to break up ancestors until we get to the right level - OctreeElement* ancestorElement = element; + OctreeElementPointer ancestorElement = element; while (true) { int index = branchIndexWithDescendant(ancestorElement->getOctalCode(), args->codeBuffer); @@ -576,23 +617,22 @@ void Octree::deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extr // If the lower level did some work, then we need to let this element know, so it can // do any bookkeeping it wants to, like color re-averaging, time stamp marking, etc if (args->pathChanged) { - element->handleSubtreeChanged(this); + element->handleSubtreeChanged(shared_from_this()); } } void Octree::eraseAllOctreeElements(bool createNewRoot) { - delete _rootElement; // this will recurse and delete all children - _rootElement = NULL; - if (createNewRoot) { _rootElement = createNewElement(); + } else { + _rootElement.reset(); // this will recurse and delete all children } _isDirty = true; } // Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startElement) -void Octree::reaverageOctreeElements(OctreeElement* startElement) { +void Octree::reaverageOctreeElements(OctreeElementPointer startElement) { if (!startElement) { startElement = getRoot(); } @@ -628,9 +668,9 @@ void Octree::reaverageOctreeElements(OctreeElement* startElement) { } } -OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) const { +OctreeElementPointer Octree::getOctreeElementAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* element = nodeForOctalCode(_rootElement, octalCode, NULL); + OctreeElementPointer element = nodeForOctalCode(_rootElement, octalCode, NULL); if (*element->getOctalCode() != *octalCode) { element = NULL; } @@ -638,20 +678,20 @@ OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) co return element; } -OctreeElement* Octree::getOctreeEnclosingElementAt(float x, float y, float z, float s) const { +OctreeElementPointer Octree::getOctreeEnclosingElementAt(float x, float y, float z, float s) const { unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* element = nodeForOctalCode(_rootElement, octalCode, NULL); + OctreeElementPointer element = nodeForOctalCode(_rootElement, octalCode, NULL); delete[] octalCode; // cleanup memory return element; } -OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, float s) { +OctreeElementPointer Octree::getOrCreateChildElementAt(float x, float y, float z, float s) { return getRoot()->getOrCreateChildElementAt(x, y, z, s); } -OctreeElement* Octree::getOrCreateChildElementContaining(const AACube& box) { +OctreeElementPointer Octree::getOrCreateChildElementContaining(const AACube& box) { return getRoot()->getOrCreateChildElementContaining(box); } @@ -660,7 +700,7 @@ class RayArgs { public: glm::vec3 origin; glm::vec3 direction; - OctreeElement*& element; + OctreeElementPointer& element; float& distance; BoxFace& face; void** intersectedObject; @@ -668,7 +708,7 @@ public: bool precisionPicking; }; -bool findRayIntersectionOp(OctreeElement* element, void* extraData) { +bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) { RayArgs* args = static_cast(extraData); bool keepSearching = true; if (element->findRayIntersection(args->origin, args->direction, keepSearching, @@ -679,7 +719,7 @@ bool findRayIntersectionOp(OctreeElement* element, void* extraData) { } bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject, + OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, Octree::lockType lockType, bool* accurateResult, bool precisionPicking) { RayArgs args = { origin, direction, element, distance, face, intersectedObject, false, precisionPicking}; @@ -720,7 +760,7 @@ public: void* penetratedObject; /// the type is defined by the type of Octree, the caller is assumed to know the type }; -bool findSpherePenetrationOp(OctreeElement* element, void* extraData) { +bool findSpherePenetrationOp(OctreeElementPointer element, void* extraData) { SphereArgs* args = static_cast(extraData); // coarse check against bounds @@ -797,7 +837,7 @@ public: CubeList* cubes; }; -bool findCapsulePenetrationOp(OctreeElement* element, void* extraData) { +bool findCapsulePenetrationOp(OctreeElementPointer element, void* extraData) { CapsuleArgs* args = static_cast(extraData); // coarse check against bounds @@ -830,7 +870,7 @@ uint qHash(const glm::vec3& point) { (((quint64)(point.z * RESOLUTION_PER_METER)) % MAX_SCALED_COMPONENT << 2 * BITS_PER_COMPONENT)); } -bool findContentInCubeOp(OctreeElement* element, void* extraData) { +bool findContentInCubeOp(OctreeElementPointer element, void* extraData) { ContentArgs* args = static_cast(extraData); // coarse check against bounds @@ -894,12 +934,12 @@ bool Octree::findContentInCube(const AACube& cube, CubeList& cubes) { class GetElementEnclosingArgs { public: - OctreeElement* element; + OctreeElementPointer element; glm::vec3 point; }; // Find the smallest colored voxel enclosing a point (if there is one) -bool getElementEnclosingOperation(OctreeElement* element, void* extraData) { +bool getElementEnclosingOperation(OctreeElementPointer element, void* extraData) { GetElementEnclosingArgs* args = static_cast(extraData); if (element->getAACube().contains(args->point)) { if (element->hasContent() && element->isLeaf()) { @@ -914,7 +954,7 @@ bool getElementEnclosingOperation(OctreeElement* element, void* extraData) { return true; // keep looking } -OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType, bool* accurateResult) { +OctreeElementPointer Octree::getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType, bool* accurateResult) { GetElementEnclosingArgs args; args.point = point; args.element = NULL; @@ -947,9 +987,9 @@ OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree:: -int Octree::encodeTreeBitstream(OctreeElement* element, - OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params) { +int Octree::encodeTreeBitstream(OctreeElementPointer element, + OctreePacketData* packetData, OctreeElementBag& bag, + EncodeBitstreamParams& params) { // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -1005,7 +1045,7 @@ int Octree::encodeTreeBitstream(OctreeElement* element, ViewFrustum::location parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully int childBytesWritten = encodeTreeBitstreamRecursion(element, packetData, bag, params, - currentEncodeLevel, parentLocationThisView); + currentEncodeLevel, parentLocationThisView); // if childBytesWritten == 1 then something went wrong... that's not possible @@ -1036,10 +1076,10 @@ int Octree::encodeTreeBitstream(OctreeElement* element, return bytesWritten; } -int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, - OctreePacketData* packetData, OctreeElementBag& bag, - EncodeBitstreamParams& params, int& currentEncodeLevel, - const ViewFrustum::location& parentLocationThisView) const { +int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, + OctreePacketData* packetData, OctreeElementBag& bag, + EncodeBitstreamParams& params, int& currentEncodeLevel, + const ViewFrustum::location& parentLocationThisView) const { const bool wantDebug = false; @@ -1228,13 +1268,13 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, int inViewNotLeafCount = 0; int inViewWithColorCount = 0; - OctreeElement* sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + OctreeElementPointer sortedChildren[NUMBER_OF_CHILDREN] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; float distancesToChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int indexOfChildren[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; int currentCount = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childElement = element->getChildAtIndex(i); + OctreeElementPointer childElement = element->getChildAtIndex(i); // if the caller wants to include childExistsBits, then include them even if not in view, if however, // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist @@ -1254,9 +1294,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, if (childElement) { float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; - currentCount = insertIntoSortedArrays((void*)childElement, distance, i, - (void**)&sortedChildren, (float*)&distancesToChildren, - (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); + currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, + sortedChildren, (float*)&distancesToChildren, + (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); } } else { sortedChildren[i] = childElement; @@ -1275,7 +1315,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int i = 0; i < currentCount; i++) { - OctreeElement* childElement = sortedChildren[i]; + OctreeElementPointer childElement = sortedChildren[i]; int originalIndex = indexOfChildren[i]; bool childIsInView = (childElement && @@ -1291,7 +1331,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, params.stats->skippedOutOfView(childElement); } } else { - // Before we determine consider this further, let's see if it's in our LOD scope... + // Before we consider this further, let's see if it's in our LOD scope... float distance = distancesToChildren[i]; float boundaryDistance = !params.viewFrustum ? 1 : boundaryDistanceForRenderLevel(childElement->getLevel() + params.boundaryLevelAdjust, @@ -1318,7 +1358,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // If the user also asked for occlusion culling, check if this element is occluded if (params.wantOcclusionCulling && childElement->isLeaf()) { // Don't check occlusion here, just add them to our distance ordered array... - + // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( params.viewFrustum->getProjectedPolygon(childElement->getAACube())); @@ -1432,7 +1472,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, if (params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenDataBits, i)) { - OctreeElement* childElement = element->getChildAtIndex(i); + OctreeElementPointer childElement = element->getChildAtIndex(i); // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the @@ -1578,7 +1618,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element, // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { - OctreeElement* childElement = sortedChildren[indexByDistance]; + OctreeElementPointer childElement = sortedChildren[indexByDistance]; int originalIndex = indexOfChildren[indexByDistance]; if (oneAtBit(childrenExistInPacketBits, originalIndex)) { @@ -2058,7 +2098,7 @@ bool Octree::readJSONFromStream(unsigned long streamLength, QDataStream& inputSt return true; } -void Octree::writeToFile(const char* fileName, OctreeElement* element, QString persistAsFileType) { +void Octree::writeToFile(const char* fileName, OctreeElementPointer element, QString persistAsFileType) { // make the sure file extension makes sense QString qFileName = fileNameWithoutExtension(QString(fileName), PERSIST_EXTENSIONS) + "." + persistAsFileType; QByteArray byteArray = qFileName.toUtf8(); @@ -2075,12 +2115,12 @@ void Octree::writeToFile(const char* fileName, OctreeElement* element, QString p } } -void Octree::writeToJSONFile(const char* fileName, OctreeElement* element, bool doGzip) { +void Octree::writeToJSONFile(const char* fileName, OctreeElementPointer element, bool doGzip) { QVariantMap entityDescription; qCDebug(octree, "Saving JSON SVO to file %s...", fileName); - OctreeElement* top; + OctreeElementPointer top; if (element) { top = element; } else { @@ -2120,7 +2160,7 @@ void Octree::writeToJSONFile(const char* fileName, OctreeElement* element, bool } } -void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { +void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) { std::ofstream file(fileName, std::ios::out|std::ios::binary); if(file.is_open()) { @@ -2160,7 +2200,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElement* element) { bool lastPacketWritten = false; while (!elementBag.isEmpty()) { - OctreeElement* subTree = elementBag.extract(); + OctreeElementPointer subTree = elementBag.extract(); lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); @@ -2208,7 +2248,7 @@ unsigned long Octree::getOctreeElementsCount() { return nodeCount; } -bool Octree::countOctreeElementsOperation(OctreeElement* element, void* extraData) { +bool Octree::countOctreeElementsOperation(OctreeElementPointer element, void* extraData) { (*(unsigned long*)extraData)++; return true; // keep going } @@ -2216,4 +2256,3 @@ bool Octree::countOctreeElementsOperation(OctreeElement* element, void* extraDat void Octree::cancelImport() { _stopImport = true; } - diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 0b3dc0027f..fe6b31807b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -14,6 +14,7 @@ #include #include +#include class CoverageMap; class ReadBitstreamToTreeParams; @@ -22,7 +23,7 @@ class OctreeElement; class OctreeElementBag; class OctreePacketData; class Shape; - +typedef std::shared_ptr OctreePointer; #include "JurisdictionMap.h" #include "ViewFrustum.h" @@ -35,19 +36,18 @@ class Shape; #include #include - extern QVector PERSIST_EXTENSIONS; /// derive from this class to use the Octree::recurseTreeWithOperator() method class RecurseOctreeOperator { public: - virtual bool preRecursion(OctreeElement* element) = 0; - virtual bool postRecursion(OctreeElement* element) = 0; - virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex) { return NULL; } + virtual bool preRecursion(OctreeElementPointer element) = 0; + virtual bool postRecursion(OctreeElementPointer element) = 0; + virtual OctreeElementPointer possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { return NULL; } }; // Callback function, for recuseTreeWithOperation -typedef bool (*RecurseOctreeOperation)(OctreeElement* element, void* extraData); +typedef bool (*RecurseOctreeOperation)(OctreeElementPointer element, void* extraData); typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; typedef QHash CubeList; @@ -190,7 +190,7 @@ class ReadBitstreamToTreeParams { public: bool includeColor; bool includeExistsBits; - OctreeElement* destinationElement; + OctreeElementPointer destinationElement; QUuid sourceUUID; SharedNodePointer sourceNode; bool wantImportProgress; @@ -201,7 +201,7 @@ public: ReadBitstreamToTreeParams( bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, - OctreeElement* destinationElement = NULL, + OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, @@ -216,14 +216,14 @@ public: {} }; -class Octree : public QObject { +class Octree : public QObject, public std::enable_shared_from_this { Q_OBJECT public: Octree(bool shouldReaverage = false); virtual ~Octree(); /// Your tree class must implement this to create the correct element type - virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) = 0; + virtual OctreeElementPointer createNewElement(unsigned char * octalCode = NULL) = 0; // These methods will allow the OctreeServer to send your tree inbound edit packets of your // own definition. Implement these to allow your octree based server to support editing @@ -250,26 +250,26 @@ public: virtual void update() { } // nothing to do by default - OctreeElement* getRoot() { return _rootElement; } + OctreeElementPointer getRoot() { return _rootElement; } virtual void eraseAllOctreeElements(bool createNewRoot = true); void readBitstreamToTree(const unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args); void deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE); - void reaverageOctreeElements(OctreeElement* startElement = NULL); + void reaverageOctreeElements(OctreeElementPointer startElement = NULL); void deleteOctreeElementAt(float x, float y, float z, float s); /// Find the voxel at position x,y,z,s /// \return pointer to the OctreeElement or NULL if none at x,y,z,s. - OctreeElement* getOctreeElementAt(float x, float y, float z, float s) const; + OctreeElementPointer getOctreeElementAt(float x, float y, float z, float s) const; /// Find the voxel at position x,y,z,s /// \return pointer to the OctreeElement or to the smallest enclosing parent if none at x,y,z,s. - OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const; + OctreeElementPointer getOctreeEnclosingElementAt(float x, float y, float z, float s) const; - OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); - OctreeElement* getOrCreateChildElementContaining(const AACube& box); + OctreeElementPointer getOrCreateChildElementAt(float x, float y, float z, float s); + OctreeElementPointer getOrCreateChildElementContaining(const AACube& box); void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL); void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL); @@ -282,7 +282,7 @@ public: void recurseTreeWithOperator(RecurseOctreeOperator* operatorObject); - int encodeTreeBitstream(OctreeElement* element, OctreePacketData* packetData, OctreeElementBag& bag, + int encodeTreeBitstream(OctreeElementPointer element, OctreePacketData* packetData, OctreeElementBag& bag, EncodeBitstreamParams& params) ; bool isDirty() const { return _isDirty; } @@ -303,7 +303,7 @@ public: } lockType; bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElement*& node, float& distance, BoxFace& face, + OctreeElementPointer& node, float& distance, BoxFace& face, void** intersectedObject = NULL, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL, @@ -322,17 +322,17 @@ public: /// \param point query point in world-frame (meters) /// \param lockType how to lock the tree (Lock, TryLock, NoLock) /// \param[out] accurateResult pointer to output result, will be set "true" or "false" if non-null - OctreeElement* getElementEnclosingPoint(const glm::vec3& point, + OctreeElementPointer getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files void loadOctreeFile(const char* fileName, bool wantColorRandomizer); // Octree exporters - void writeToFile(const char* filename, OctreeElement* element = NULL, QString persistAsFileType = "svo"); - void writeToJSONFile(const char* filename, OctreeElement* element = NULL, bool doGzip = false); - void writeToSVOFile(const char* filename, OctreeElement* element = NULL); - virtual bool writeToMap(QVariantMap& entityDescription, OctreeElement* element, bool skipDefaultValues) = 0; + void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); + void writeToJSONFile(const char* filename, OctreeElementPointer element = NULL, bool doGzip = false); + void writeToSVOFile(const char* filename, OctreeElementPointer element = NULL); + virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) = 0; // Octree importers bool readFromFile(const char* filename); @@ -347,18 +347,18 @@ public: bool getShouldReaverage() const { return _shouldReaverage; } - void recurseElementWithOperation(OctreeElement* element, RecurseOctreeOperation operation, + void recurseElementWithOperation(OctreeElementPointer element, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); /// Traverse child nodes of node applying operation in post-fix order /// - void recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation, + void recurseElementWithPostOperation(OctreeElementPointer element, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); - void recurseElementWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation, + void recurseElementWithOperationDistanceSorted(OctreeElementPointer element, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount = 0); - bool recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount = 0); + bool recurseElementWithOperator(OctreeElementPointer element, RecurseOctreeOperator* operatorObject, int recursionCount = 0); bool getIsViewing() const { return _isViewing; } /// This tree is receiving inbound viewer datagrams. void setIsViewing(bool isViewing) { _isViewing = isViewing; } @@ -389,28 +389,28 @@ public slots: protected: - void deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extraData); + void deleteOctalCodeFromTreeRecursion(OctreeElementPointer element, void* extraData); - int encodeTreeBitstreamRecursion(OctreeElement* element, + int encodeTreeBitstreamRecursion(OctreeElementPointer element, OctreePacketData* packetData, OctreeElementBag& bag, EncodeBitstreamParams& params, int& currentEncodeLevel, const ViewFrustum::location& parentLocationThisView) const; - static bool countOctreeElementsOperation(OctreeElement* element, void* extraData); + static bool countOctreeElementsOperation(OctreeElementPointer element, void* extraData); - OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const; - OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount = 0); - int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData, + OctreeElementPointer nodeForOctalCode(OctreeElementPointer ancestorElement, const unsigned char* needleCode, OctreeElementPointer* parentOfFoundElement) const; + OctreeElementPointer createMissingElement(OctreeElementPointer lastParentElement, const unsigned char* codeToReach, int recursionCount = 0); + int readElementData(OctreeElementPointer destinationElement, const unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args); - OctreeElement* _rootElement; + OctreeElementPointer _rootElement = nullptr; bool _isDirty; bool _shouldReaverage; bool _stopImport; QReadWriteLock _lock; - + bool _isViewing; bool _isServer; }; diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 2bbacccf95..9e2cfbbf63 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -42,7 +42,7 @@ void OctreeElement::resetPopulationStatistics() { OctreeElement::OctreeElement() { // Note: you must call init() from your subclass, otherwise the OctreeElement will not be properly // initialized. You will see DEADBEEF in your memory debugger if you have not properly called init() - debug::setDeadBeef(this, sizeof(*this)); + // debug::setDeadBeef(this, sizeof(*this)); } void OctreeElement::init(unsigned char * octalCode) { @@ -80,9 +80,13 @@ void OctreeElement::init(unsigned char * octalCode) { #endif #ifdef SIMPLE_EXTERNAL_CHILDREN - _children.single = NULL; + _childrenSingle.reset(); #endif + for (int i = 0; i < NUMBER_OF_CHILDREN; i ++) { + _externalChildren[i].reset(); + } + _isDirty = true; _shouldRender = false; _sourceUUIDKey = 0; @@ -91,7 +95,10 @@ void OctreeElement::init(unsigned char * octalCode) { } OctreeElement::~OctreeElement() { - notifyDeleteHooks(); + // We can't call notifyDeleteHooks from here: + // notifyDeleteHooks(); + // see comment in EntityTreeElement::createNewElement. + assert(_deleteHooksNotified); _voxelNodeCount--; if (isLeaf()) { _voxelNodeLeafCount--; @@ -117,7 +124,7 @@ void OctreeElement::markWithChangedTime() { // changed. However, you should hopefully make your bookkeeping relatively // localized, because this method will get called for every node in an // recursive unwinding case like delete or add voxel -void OctreeElement::handleSubtreeChanged(Octree* myTree) { +void OctreeElement::handleSubtreeChanged(OctreePointer myTree) { // here's a good place to do color re-averaging... if (myTree->getShouldReaverage()) { calculateAverageFromChildren(); @@ -196,9 +203,9 @@ void OctreeElement::calculateAACube() { } void OctreeElement::deleteChildAtIndex(int childIndex) { - OctreeElement* childAt = getChildAtIndex(childIndex); + OctreeElementPointer childAt = getChildAtIndex(childIndex); if (childAt) { - delete childAt; + childAt.reset(); setChildAtIndex(childIndex, NULL); _isDirty = true; markWithChangedTime(); @@ -211,8 +218,8 @@ void OctreeElement::deleteChildAtIndex(int childIndex) { } // does not delete the node! -OctreeElement* OctreeElement::removeChildAtIndex(int childIndex) { - OctreeElement* returnedChild = getChildAtIndex(childIndex); +OctreeElementPointer OctreeElement::removeChildAtIndex(int childIndex) { + OctreeElementPointer returnedChild = getChildAtIndex(childIndex); if (returnedChild) { setChildAtIndex(childIndex, NULL); _isDirty = true; @@ -226,10 +233,10 @@ OctreeElement* OctreeElement::removeChildAtIndex(int childIndex) { return returnedChild; } -bool OctreeElement::isParentOf(OctreeElement* possibleChild) const { +bool OctreeElement::isParentOf(OctreeElementPointer possibleChild) const { if (possibleChild) { for (int childIndex = 0; childIndex < NUMBER_OF_CHILDREN; childIndex++) { - OctreeElement* childAt = getChildAtIndex(childIndex); + OctreeElementPointer childAt = getChildAtIndex(childIndex); if (childAt == possibleChild) { return true; } @@ -246,7 +253,7 @@ quint64 OctreeElement::_setChildAtIndexCalls = 0; quint64 OctreeElement::_externalChildrenCount = 0; quint64 OctreeElement::_childrenCount[NUMBER_OF_CHILDREN + 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const { +OctreeElementPointer OctreeElement::getChildAtIndex(int childIndex) const { #ifdef SIMPLE_CHILD_ARRAY return _simpleChildArray[childIndex]; #endif // SIMPLE_CHILD_ARRAY @@ -264,14 +271,14 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const { // return null int firstIndex = getNthBit(_childBitmask, 1); if (firstIndex == childIndex) { - return _children.single; + return _childrenSingle; } else { return NULL; } } break; default : { - return _children.external[childIndex]; + return _externalChildren[childIndex]; } break; } #endif // def SIMPLE_EXTERNAL_CHILDREN @@ -280,19 +287,21 @@ OctreeElement* OctreeElement::getChildAtIndex(int childIndex) const { void OctreeElement::deleteAllChildren() { // first delete all the OctreeElement objects... for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childAt = getChildAtIndex(i); + OctreeElementPointer childAt = getChildAtIndex(i); if (childAt) { - delete childAt; + childAt.reset(); } } if (_childrenExternal) { // if the children_t union represents _children.external we need to delete it here - delete[] _children.external; + for (int i = 0; i < NUMBER_OF_CHILDREN; i ++) { + _externalChildren[i].reset(); + } } } -void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { +void OctreeElement::setChildAtIndex(int childIndex, OctreeElementPointer child) { #ifdef SIMPLE_CHILD_ARRAY int previousChildCount = getChildCount(); if (child) { @@ -332,44 +341,47 @@ void OctreeElement::setChildAtIndex(int childIndex, OctreeElement* child) { } if ((previousChildCount == 0 || previousChildCount == 1) && newChildCount == 0) { - _children.single = NULL; + _childrenSingle.reset(); } else if (previousChildCount == 0 && newChildCount == 1) { - _children.single = child; + _childrenSingle = child; } else if (previousChildCount == 1 && newChildCount == 2) { - OctreeElement* previousChild = _children.single; - _children.external = new OctreeElement*[NUMBER_OF_CHILDREN]; - memset(_children.external, 0, sizeof(OctreeElement*) * NUMBER_OF_CHILDREN); - _children.external[firstIndex] = previousChild; - _children.external[childIndex] = child; + OctreeElementPointer previousChild = _childrenSingle; + for (int i = 0; i < NUMBER_OF_CHILDREN; i ++) { + _externalChildren[i].reset(); + } + _externalChildren[firstIndex] = previousChild; + _externalChildren[childIndex] = child; _childrenExternal = true; - _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElement*); + _externalChildrenMemoryUsage += NUMBER_OF_CHILDREN * sizeof(OctreeElementPointer); } else if (previousChildCount == 2 && newChildCount == 1) { assert(!child); // we are removing a child, so this must be true! - OctreeElement* previousFirstChild = _children.external[firstIndex]; - OctreeElement* previousSecondChild = _children.external[secondIndex]; + OctreeElementPointer previousFirstChild = _externalChildren[firstIndex]; + OctreeElementPointer previousSecondChild = _externalChildren[secondIndex]; - delete[] _children.external; + for (int i = 0; i < NUMBER_OF_CHILDREN; i ++) { + _externalChildren[i].reset(); + } _childrenExternal = false; - _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElement*); + _externalChildrenMemoryUsage -= NUMBER_OF_CHILDREN * sizeof(OctreeElementPointer); if (childIndex == firstIndex) { - _children.single = previousSecondChild; + _childrenSingle = previousSecondChild; } else { - _children.single = previousFirstChild; + _childrenSingle = previousFirstChild; } } else { - _children.external[childIndex] = child; + _externalChildren[childIndex] = child; } #endif // def SIMPLE_EXTERNAL_CHILDREN } -OctreeElement* OctreeElement::addChildAtIndex(int childIndex) { - OctreeElement* childAt = getChildAtIndex(childIndex); +OctreeElementPointer OctreeElement::addChildAtIndex(int childIndex) { + OctreeElementPointer childAt = getChildAtIndex(childIndex); if (!childAt) { // before adding a child, see if we're currently a leaf if (isLeaf()) { @@ -397,7 +409,7 @@ bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCoun qCDebug(octree) << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; return deleteApproved; } - OctreeElement* childToDelete = getChildAtIndex(childIndex); + OctreeElementPointer childToDelete = getChildAtIndex(childIndex); if (childToDelete) { if (childToDelete->deleteApproved()) { // If the child is not a leaf, then call ourselves recursively on all the children @@ -428,7 +440,7 @@ bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCoun void OctreeElement::printDebugDetails(const char* label) const { unsigned char childBits = 0; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - OctreeElement* childAt = getChildAtIndex(i); + OctreeElementPointer childAt = getChildAtIndex(i); if (childAt) { setAtBit(childBits,i); } @@ -534,9 +546,10 @@ void OctreeElement::removeDeleteHook(OctreeElementDeleteHook* hook) { void OctreeElement::notifyDeleteHooks() { _deleteHooksLock.lockForRead(); for (unsigned int i = 0; i < _deleteHooks.size(); i++) { - _deleteHooks[i]->elementDeleted(this); + _deleteHooks[i]->elementDeleted(shared_from_this()); } _deleteHooksLock.unlock(); + _deleteHooksNotified = true; } std::vector OctreeElement::_updateHooks; @@ -556,12 +569,12 @@ void OctreeElement::removeUpdateHook(OctreeElementUpdateHook* hook) { void OctreeElement::notifyUpdateHooks() { for (unsigned int i = 0; i < _updateHooks.size(); i++) { - _updateHooks[i]->elementUpdated(this); + _updateHooks[i]->elementUpdated(shared_from_this()); } } bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking) { keepSearching = true; // assume that we will continue searching after this. @@ -599,12 +612,12 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 } bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // we did hit this element, so calculate appropriate distances if (hasContent()) { - element = this; + element = shared_from_this(); distance = distanceToElementCube; if (intersectedObject) { *intersectedObject = this; @@ -622,8 +635,8 @@ bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, } // TODO: consider removing this, or switching to using getOrCreateChildElementContaining(const AACube& box)... -OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float z, float s) { - OctreeElement* child = NULL; +OctreeElementPointer OctreeElement::getOrCreateChildElementAt(float x, float y, float z, float s) { + OctreeElementPointer child = NULL; // If the requested size is less than or equal to our scale, but greater than half our scale, then // we are the Element they are looking for. float ourScale = getScale(); @@ -635,7 +648,7 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float } if (s > halfOurScale) { - return this; + return shared_from_this(); } int childIndex = getMyChildContainingPoint(glm::vec3(x, y, z)); @@ -651,15 +664,15 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float } -OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) { - OctreeElement* child = NULL; +OctreeElementPointer OctreeElement::getOrCreateChildElementContaining(const AACube& cube) { + OctreeElementPointer child = NULL; int childIndex = getMyChildContaining(cube); // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level // is the correct level for this cube if (childIndex == CHILD_UNKNOWN) { - return this; + return shared_from_this(); } // Now, check if we have a child at that location @@ -677,15 +690,15 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu return child->getOrCreateChildElementContaining(cube); } -OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) { - OctreeElement* child = NULL; +OctreeElementPointer OctreeElement::getOrCreateChildElementContaining(const AABox& box) { + OctreeElementPointer 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; + return shared_from_this(); } // Now, check if we have a child at that location diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index d2f3f7d3aa..475d9568bb 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -33,27 +33,30 @@ class OctreePacketData; class ReadBitstreamToTreeParams; class Shape; class VoxelSystem; +typedef std::shared_ptr OctreeElementPointer; +typedef std::shared_ptr ConstOctreeElementPointer; +typedef std::shared_ptr OctreePointer; // Callers who want delete hook callbacks should implement this class class OctreeElementDeleteHook { public: - virtual void elementDeleted(OctreeElement* element) = 0; + virtual void elementDeleted(OctreeElementPointer element) = 0; }; // Callers who want update hook callbacks should implement this class class OctreeElementUpdateHook { public: - virtual void elementUpdated(OctreeElement* element) = 0; + virtual void elementUpdated(OctreeElementPointer element) = 0; }; -class OctreeElement { +class OctreeElement: public std::enable_shared_from_this { protected: // can only be constructed by derived implementation OctreeElement(); - virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) = 0; + virtual OctreeElementPointer createNewElement(unsigned char * octalCode = NULL) = 0; public: virtual void init(unsigned char * octalCode); /// Your subclass must call init on construction. @@ -62,7 +65,7 @@ public: // methods you can and should override to implement your tree functionality /// Adds a child to the current element. Override this if there is additional child initialization your class needs. - virtual OctreeElement* addChildAtIndex(int childIndex); + virtual OctreeElementPointer addChildAtIndex(int childIndex); /// Override this to implement LOD averaging on changes to the tree. virtual void calculateAverageFromChildren() { } @@ -90,7 +93,7 @@ public: typedef enum { COMPLETED, PARTIAL, NONE } AppendState; virtual void debugExtraEncodeData(EncodeBitstreamParams& params) const { } - virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) const { } + virtual void initializeExtraEncodeData(EncodeBitstreamParams& params) { } virtual bool shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const { return true; } virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const { return true; } @@ -116,11 +119,11 @@ public: virtual bool canRayIntersect() const { return isLeaf(); } virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& node, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& node, float& distance, BoxFace& face, void** intersectedObject = NULL, bool precisionPicking = false); virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, bool precisionPicking, float distanceToElementCube); /// \param center center of sphere in meters @@ -132,10 +135,10 @@ public: // Base class methods you don't need to implement const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; } - OctreeElement* getChildAtIndex(int childIndex) const; + OctreeElementPointer getChildAtIndex(int childIndex) const; void deleteChildAtIndex(int childIndex); - OctreeElement* removeChildAtIndex(int childIndex); - bool isParentOf(OctreeElement* possibleChild) const; + OctreeElementPointer removeChildAtIndex(int childIndex); + bool isParentOf(OctreeElementPointer possibleChild) const; /// handles deletion of all descendants, returns false if delete not approved bool safeDeepDeleteChildAtIndex(int childIndex, int recursionCount = 0); @@ -145,16 +148,16 @@ public: const glm::vec3& getCorner() const { return _cube.getCorner(); } float getScale() const { return _cube.getScale(); } int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; } - + float getEnclosingRadius() const; bool isInView(const ViewFrustum& viewFrustum) const { return inFrustum(viewFrustum) != ViewFrustum::OUTSIDE; } ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const; - float distanceToCamera(const ViewFrustum& viewFrustum) const; + float distanceToCamera(const ViewFrustum& viewFrustum) const; float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const; - bool calculateShouldRender(const ViewFrustum* viewFrustum, + bool calculateShouldRender(const ViewFrustum* viewFrustum, float voxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE, int boundaryLevelAdjust = 0) const; - + // points are assumed to be in Voxel Coordinates (not TREE_SCALE'd) float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this. float distanceToPoint(const glm::vec3& point) const; @@ -168,13 +171,13 @@ public: bool hasChangedSince(quint64 time) const { return (_lastChanged > time); } void markWithChangedTime(); quint64 getLastChanged() const { return _lastChanged; } - void handleSubtreeChanged(Octree* myTree); - + void handleSubtreeChanged(OctreePointer myTree); + // Used by VoxelSystem for rendering in/out of view and LOD void setShouldRender(bool shouldRender); bool getShouldRender() const { return _shouldRender; } - - + + void setSourceUUID(const QUuid& sourceID); QUuid getSourceUUID() const; uint16_t getSourceUUIDKey() const { return _sourceUUIDKey; } @@ -186,7 +189,7 @@ public: static void addUpdateHook(OctreeElementUpdateHook* hook); static void removeUpdateHook(OctreeElementUpdateHook* hook); - + static void resetPopulationStatistics(); static unsigned long getNodeCount() { return _voxelNodeCount; } static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; } @@ -204,7 +207,7 @@ public: static quint64 getExternalChildrenCount() { return _externalChildrenCount; } static quint64 getChildrenCount(int childCount) { return _childrenCount[childCount]; } - + enum ChildIndex { CHILD_BOTTOM_RIGHT_NEAR = 0, CHILD_BOTTOM_RIGHT_FAR = 1, @@ -231,9 +234,9 @@ public: }; - OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); - OctreeElement* getOrCreateChildElementContaining(const AACube& box); - OctreeElement* getOrCreateChildElementContaining(const AABox& box); + OctreeElementPointer getOrCreateChildElementAt(float x, float y, float z, float s); + OctreeElementPointer getOrCreateChildElementContaining(const AACube& box); + OctreeElementPointer getOrCreateChildElementContaining(const AABox& box); int getMyChildContaining(const AACube& cube) const; int getMyChildContaining(const AABox& box) const; int getMyChildContainingPoint(const glm::vec3& point) const; @@ -241,7 +244,7 @@ public: protected: void deleteAllChildren(); - void setChildAtIndex(int childIndex, OctreeElement* child); + void setChildAtIndex(int childIndex, OctreeElementPointer child); void calculateAACube(); void notifyDeleteHooks(); @@ -253,22 +256,22 @@ protected: union octalCode_t { unsigned char buffer[8]; unsigned char* pointer; - } _octalCode; + } _octalCode; quint64 _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes /// Client and server, pointers to child nodes, various encodings #ifdef SIMPLE_CHILD_ARRAY - OctreeElement* _simpleChildArray[8]; /// Only used when SIMPLE_CHILD_ARRAY is enabled + OctreeElementPointer _simpleChildArray[8]; /// Only used when SIMPLE_CHILD_ARRAY is enabled #endif #ifdef SIMPLE_EXTERNAL_CHILDREN - union children_t { - OctreeElement* single; - OctreeElement** external; - } _children; + // union children_t { + OctreeElementPointer _childrenSingle; + OctreeElementPointer _externalChildren[NUMBER_OF_CHILDREN]; + // } _children; #endif - + uint16_t _sourceUUIDKey; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes // Support for _sourceUUID, we use these static member variables to track the UUIDs that are @@ -287,6 +290,8 @@ protected: _unknownBufferIndex : 1, _childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit + bool _deleteHooksNotified = false; + static QReadWriteLock _deleteHooksLock; static std::vector _deleteHooks; diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index 0f1e091c6f..5af63c7bb1 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -31,7 +31,7 @@ void OctreeElementBag::unhookNotifications() { } } -void OctreeElementBag::elementDeleted(OctreeElement* element) { +void OctreeElementBag::elementDeleted(OctreeElementPointer element) { remove(element); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() } @@ -41,25 +41,25 @@ void OctreeElementBag::deleteAll() { } -void OctreeElementBag::insert(OctreeElement* element) { +void OctreeElementBag::insert(OctreeElementPointer element) { _bagElements.insert(element); } -OctreeElement* OctreeElementBag::extract() { - OctreeElement* result = NULL; +OctreeElementPointer OctreeElementBag::extract() { + OctreeElementPointer result = NULL; if (_bagElements.size() > 0) { - QSet::iterator front = _bagElements.begin(); + QSet::iterator front = _bagElements.begin(); result = *front; _bagElements.erase(front); } return result; } -bool OctreeElementBag::contains(OctreeElement* element) { +bool OctreeElementBag::contains(OctreeElementPointer element) { return _bagElements.contains(element); } -void OctreeElementBag::remove(OctreeElement* element) { +void OctreeElementBag::remove(OctreeElementPointer element) { _bagElements.remove(element); } diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index 1b74f507c6..8ef01b44a2 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -23,24 +23,24 @@ class OctreeElementBag : public OctreeElementDeleteHook { public: OctreeElementBag(); ~OctreeElementBag(); - - void insert(OctreeElement* element); // put a element into the bag - OctreeElement* extract(); // pull a element out of the bag (could come in any order) - bool contains(OctreeElement* element); // is this element in the bag? - void remove(OctreeElement* element); // remove a specific element from the bag + + void insert(OctreeElementPointer element); // put a element into the bag + OctreeElementPointer extract(); // pull a element out of the bag (could come in any order) + bool contains(OctreeElementPointer element); // is this element in the bag? + void remove(OctreeElementPointer element); // remove a specific element from the bag bool isEmpty() const { return _bagElements.isEmpty(); } int count() const { return _bagElements.size(); } void deleteAll(); - virtual void elementDeleted(OctreeElement* element); + virtual void elementDeleted(OctreeElementPointer element); void unhookNotifications(); private: - QSet _bagElements; + QSet _bagElements; bool _hooked; }; -typedef QMap OctreeElementExtraEncodeData; +typedef QMap OctreeElementExtraEncodeData; #endif // hifi_OctreeElementBag_h diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index d54d54952a..be076e7b5f 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -30,7 +30,7 @@ class OctreeHeadlessViewer : public OctreeRenderer { public: OctreeHeadlessViewer(); virtual ~OctreeHeadlessViewer(); - virtual void renderElement(OctreeElement* element, RenderArgs* args) { /* swallow these */ } + virtual void renderElement(OctreeElementPointer element, RenderArgs* args) { /* swallow these */ } virtual void init(); virtual void render(RenderArgs* renderArgs) override { /* swallow these */ } diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index bb6f62ef84..332a60feb9 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -31,7 +31,7 @@ const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds -OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval, +OctreePersistThread::OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval, bool wantBackup, const QJsonObject& settings, bool debugTimestampNow, QString persistAsFileType) : _tree(tree), diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index e756c13f59..d3aa3d3968 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -33,8 +33,8 @@ public: static const int DEFAULT_PERSIST_INTERVAL; - OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL, - bool wantBackup = false, const QJsonObject& settings = QJsonObject(), + OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL, + bool wantBackup = false, const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false, QString persistAsFileType="svo"); bool isInitialLoadComplete() const { return _initialLoadComplete; } @@ -48,7 +48,7 @@ signals: protected: /// Implements generic processing behavior for this thread. virtual bool process(); - + void persist(); void backup(); void rollOldBackupVersions(const BackupRule& rule); @@ -56,9 +56,9 @@ protected: bool getMostRecentBackup(const QString& format, QString& mostRecentBackupFileName, QDateTime& mostRecentBackupTime); quint64 getMostRecentBackupTimeInUsecs(const QString& format); void parseSettings(const QJsonObject& settings); - + private: - Octree* _tree; + OctreePointer _tree; QString _filename; int _persistInterval; bool _initialLoadComplete; @@ -69,7 +69,7 @@ private: quint64 _lastCheck; bool _wantBackup; QVector _backupRules; - + bool _debugTimestampNow; quint64 _lastTimeDebug; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index ce9bd1e3fd..1b221f8d0f 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -35,22 +35,15 @@ void OctreeRenderer::init() { } OctreeRenderer::~OctreeRenderer() { - if (_tree && _managedTree) { - delete _tree; - } } -void OctreeRenderer::setTree(Octree* newTree) { - if (_tree && _managedTree) { - delete _tree; - _managedTree = false; - } +void OctreeRenderer::setTree(OctreePointer newTree) { _tree = newTree; } void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceNode) { bool extraDebugging = false; - + if (extraDebugging) { qCDebug(octree) << "OctreeRenderer::processDatagram()"; } @@ -199,7 +192,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN } } -bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { +bool OctreeRenderer::renderOperation(OctreeElementPointer element, void* extraData) { RenderArgs* args = static_cast(extraData); if (element->isInView(*args->_viewFrustum)) { if (element->hasContent()) { diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 85a193a3e6..a49ca5bae5 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -38,12 +38,12 @@ public: virtual char getMyNodeType() const = 0; virtual PacketType::Value getMyQueryMessageType() const = 0; virtual PacketType::Value getExpectedPacketType() const = 0; - virtual void renderElement(OctreeElement* element, RenderArgs* args) = 0; + virtual void renderElement(OctreeElementPointer element, RenderArgs* args) = 0; virtual float getSizeScale() const { return DEFAULT_OCTREE_SIZE_SCALE; } virtual int getBoundaryLevelAdjust() const { return 0; } - virtual void setTree(Octree* newTree); - + virtual void setTree(OctreePointer newTree); + /// process incoming data virtual void processDatagram(NLPacket& packet, SharedNodePointer sourceNode); @@ -56,7 +56,7 @@ public: ViewFrustum* getViewFrustum() const { return _viewFrustum; } void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } - static bool renderOperation(OctreeElement* element, void* extraData); + static bool renderOperation(OctreeElementPointer element, void* extraData); /// clears the tree virtual void clear(); @@ -71,11 +71,11 @@ public: float getAverageWaitLockPerPacket() const { return _waitLockPerPacket.getAverage(); } float getAverageUncompressPerPacket() const { return _uncompressPerPacket.getAverage(); } float getAverageReadBitstreamPerPacket() const { return _readBitstreamPerPacket.getAverage(); } - -protected: - virtual Octree* createTree() = 0; - Octree* _tree; +protected: + virtual OctreePointer createTree() = 0; + + OctreePointer _tree; bool _managedTree; ViewFrustum* _viewFrustum; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 55213fdb7a..cd60b8b846 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -149,7 +149,8 @@ OctreeSceneStats::~OctreeSceneStats() { reset(); } -void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, OctreeElement* root, JurisdictionMap* jurisdictionMap) { +void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, OctreeElementPointer root, + JurisdictionMap* jurisdictionMap) { reset(); // resets packet and octree stats _isStarted = true; _start = usecTimestampNow(); @@ -286,7 +287,7 @@ void OctreeSceneStats::packetSent(int bytes) { _bytes += bytes; } -void OctreeSceneStats::traversed(const OctreeElement* element) { +void OctreeSceneStats::traversed(const OctreeElementPointer element) { _traversed++; if (element->isLeaf()) { _leaves++; @@ -295,7 +296,7 @@ void OctreeSceneStats::traversed(const OctreeElement* element) { } } -void OctreeSceneStats::skippedDistance(const OctreeElement* element) { +void OctreeSceneStats::skippedDistance(const OctreeElementPointer element) { _skippedDistance++; if (element->isLeaf()) { _leavesSkippedDistance++; @@ -304,7 +305,7 @@ void OctreeSceneStats::skippedDistance(const OctreeElement* element) { } } -void OctreeSceneStats::skippedOutOfView(const OctreeElement* element) { +void OctreeSceneStats::skippedOutOfView(const OctreeElementPointer element) { _skippedOutOfView++; if (element->isLeaf()) { _leavesSkippedOutOfView++; @@ -313,7 +314,7 @@ void OctreeSceneStats::skippedOutOfView(const OctreeElement* element) { } } -void OctreeSceneStats::skippedWasInView(const OctreeElement* element) { +void OctreeSceneStats::skippedWasInView(const OctreeElementPointer element) { _skippedWasInView++; if (element->isLeaf()) { _leavesSkippedWasInView++; @@ -322,7 +323,7 @@ void OctreeSceneStats::skippedWasInView(const OctreeElement* element) { } } -void OctreeSceneStats::skippedNoChange(const OctreeElement* element) { +void OctreeSceneStats::skippedNoChange(const OctreeElementPointer element) { _skippedNoChange++; if (element->isLeaf()) { _leavesSkippedNoChange++; @@ -331,7 +332,7 @@ void OctreeSceneStats::skippedNoChange(const OctreeElement* element) { } } -void OctreeSceneStats::skippedOccluded(const OctreeElement* element) { +void OctreeSceneStats::skippedOccluded(const OctreeElementPointer element) { _skippedOccluded++; if (element->isLeaf()) { _leavesSkippedOccluded++; @@ -340,7 +341,7 @@ void OctreeSceneStats::skippedOccluded(const OctreeElement* element) { } } -void OctreeSceneStats::colorSent(const OctreeElement* element) { +void OctreeSceneStats::colorSent(const OctreeElementPointer element) { _colorSent++; if (element->isLeaf()) { _leavesColorSent++; @@ -349,7 +350,7 @@ void OctreeSceneStats::colorSent(const OctreeElement* element) { } } -void OctreeSceneStats::didntFit(const OctreeElement* element) { +void OctreeSceneStats::didntFit(const OctreeElementPointer element) { _didntFit++; if (element->isLeaf()) { _leavesDidntFit++; diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index d840c0d6f6..77cc02b247 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -37,7 +37,7 @@ public: OctreeSceneStats& operator= (const OctreeSceneStats& other); // copy assignment /// Call when beginning the computation of a scene. Initializes internal structures - void sceneStarted(bool fullScene, bool moving, OctreeElement* root, JurisdictionMap* jurisdictionMap); + void sceneStarted(bool fullScene, bool moving, OctreeElementPointer root, JurisdictionMap* jurisdictionMap); bool getIsSceneStarted() const { return _isStarted; } /// Call when the computation of a scene is completed. Finalizes internal structures @@ -55,28 +55,28 @@ public: void encodeStopped(); /// Track that a element was traversed as part of computation of a scene. - void traversed(const OctreeElement* element); + void traversed(const OctreeElementPointer element); /// Track that a element was skipped as part of computation of a scene due to being beyond the LOD distance. - void skippedDistance(const OctreeElement* element); + void skippedDistance(const OctreeElementPointer element); /// Track that a element was skipped as part of computation of a scene due to being out of view. - void skippedOutOfView(const OctreeElement* element); + void skippedOutOfView(const OctreeElementPointer element); /// Track that a element was skipped as part of computation of a scene due to previously being in view while in delta sending - void skippedWasInView(const OctreeElement* element); + void skippedWasInView(const OctreeElementPointer element); /// Track that a element was skipped as part of computation of a scene due to not having changed since last full scene sent - void skippedNoChange(const OctreeElement* element); + void skippedNoChange(const OctreeElementPointer element); /// Track that a element was skipped as part of computation of a scene due to being occluded - void skippedOccluded(const OctreeElement* element); + void skippedOccluded(const OctreeElementPointer element); /// Track that a element's color was was sent as part of computation of a scene - void colorSent(const OctreeElement* element); + void colorSent(const OctreeElementPointer element); /// Track that a element was due to be sent, but didn't fit in the packet and was moved to next packet - void didntFit(const OctreeElement* element); + void didntFit(const OctreeElementPointer element); /// Track that the color bitmask was was sent as part of computation of a scene void colorBitsWritten(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index dc3c0ea4e8..0b0979f03b 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -31,8 +31,8 @@ const quint64 USECS_BETWEEN_OWNERSHIP_BIDS = USECS_PER_SECOND / 5; #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS bool EntityMotionState::entityTreeIsLocked() const { - EntityTreeElement* element = _entity ? _entity->getElement() : nullptr; - EntityTree* tree = element ? element->getTree() : nullptr; + EntityTreeElementPointer element = _entity ? _entity->getElement() : nullptr; + EntityTreePointer tree = element ? element->getTree() : nullptr; if (tree) { bool readSuccess = tree->tryLockForRead(); if (readSuccess) { diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 97cf6a549a..92658b27a1 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -24,8 +24,8 @@ PhysicalEntitySimulation::~PhysicalEntitySimulation() { } void PhysicalEntitySimulation::init( - EntityTree* tree, - PhysicsEngine* physicsEngine, + EntityTreePointer tree, + PhysicsEnginePointer physicsEngine, EntityEditPacketSender* packetSender) { assert(tree); setEntityTree(tree); diff --git a/libraries/physics/src/PhysicalEntitySimulation.h b/libraries/physics/src/PhysicalEntitySimulation.h index 7599c7d1b5..aaf729dcb8 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.h +++ b/libraries/physics/src/PhysicalEntitySimulation.h @@ -30,7 +30,7 @@ public: PhysicalEntitySimulation(); ~PhysicalEntitySimulation(); - void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender); + void init(EntityTreePointer tree, PhysicsEnginePointer engine, EntityEditPacketSender* packetSender); virtual void addAction(EntityActionPointer action); virtual void applyActionChanges(); @@ -66,10 +66,13 @@ private: SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine VectorOfMotionStates _tempVector; // temporary array reference, valid immediately after getObjectsToRemove() (and friends) - PhysicsEngine* _physicsEngine = nullptr; + PhysicsEnginePointer _physicsEngine = nullptr; EntityEditPacketSender* _entityPacketSender = nullptr; uint32_t _lastStepSendPackets = 0; }; + +typedef std::shared_ptr PhysicalEntitySimulationPointer; + #endif // hifi_PhysicalEntitySimulation_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 040055b313..2931f58ccd 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -17,9 +17,6 @@ #include "ThreadSafeDynamicsWorld.h" #include "PhysicsLogging.h" -static uint32_t _numSubsteps; - -// static uint32_t PhysicsEngine::getNumSubsteps() { return _numSubsteps; } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 67b38323cc..ad7820a311 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -44,8 +44,7 @@ typedef QVector CollisionEvents; class PhysicsEngine { public: - // TODO: find a good way to make this a non-static method - static uint32_t getNumSubsteps(); + uint32_t getNumSubsteps(); PhysicsEngine(const glm::vec3& offset); ~PhysicsEngine(); @@ -129,6 +128,10 @@ private: QHash _objectActions; btHashMap _collisionMasks; + + uint32_t _numSubsteps; }; +typedef std::shared_ptr PhysicsEnginePointer; + #endif // hifi_PhysicsEngine_h diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 17a32e7910..4967778cb4 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -12,6 +12,7 @@ #ifndef hifi_SharedUtil_h #define hifi_SharedUtil_h +#include #include #include @@ -123,11 +124,17 @@ private: bool isBetween(int64_t value, int64_t max, int64_t min); -/// \return bool is the float NaN +/// \return bool is the float NaN bool isNaN(float value); QString formatUsecTime(float usecs, int prec = 3); QString formatSecondsElapsed(float seconds); bool similarStrings(const QString& stringA, const QString& stringB); +template +uint qHash(const std::shared_ptr& ptr, uint seed = 0) +{ + return qHash(ptr.get(), seed); +} + #endif // hifi_SharedUtil_h From 4fa1818807a0b6e0a2c7ecf84d6374da90b6f5cc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 8 Sep 2015 19:19:49 -0700 Subject: [PATCH 02/17] remove a line that leaked over from other branch --- libraries/entities/src/ZoneEntityItem.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index e112103529..41af2f14d8 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -130,8 +130,6 @@ protected: static bool _drawZoneBoundaries; static bool _zonesArePickable; - - EntityTreePointer subTree; }; #endif // hifi_ZoneEntityItem_h From 7b656d5eade4509b3cef3ab4486522743752bc81 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 9 Sep 2015 03:30:09 -0700 Subject: [PATCH 03/17] make a couple variable names better --- assignment-client/src/octree/OctreeQueryNode.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 1a90c71b82..c68fb4e1b5 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -338,9 +338,9 @@ void OctreeQueryNode::dumpOutOfView() { int outOfView = 0; OctreeElementBag tempBag; while (!elementBag.isEmpty()) { - OctreeElementPointer elt = elementBag.extract(); - if (elt->isInView(_currentViewFrustum)) { - tempBag.insert(elt); + OctreeElementPointer elementToCheck = elementBag.extract(); + if (elementToCheck->isInView(_currentViewFrustum)) { + tempBag.insert(elementToCheck); stillInView++; } else { outOfView++; @@ -348,9 +348,9 @@ void OctreeQueryNode::dumpOutOfView() { } if (stillInView > 0) { while (!tempBag.isEmpty()) { - OctreeElementPointer elt = tempBag.extract(); - if (elt->isInView(_currentViewFrustum)) { - elementBag.insert(elt); + OctreeElementPointer elementToKeepInBag = tempBag.extract(); + if (elementToKeepInBag->isInView(_currentViewFrustum)) { + elementBag.insert(elementToKeepInBag); } } } From 66e4acf65192d2d6c2798eec6ffad70719ee7827 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 10 Sep 2015 16:21:57 -0700 Subject: [PATCH 04/17] trying to move to instant reset --- examples/entityScripts/sprayPaintCan.js | 19 ++++++- examples/sprayPaintSpawner.js | 66 ++++++------------------- 2 files changed, 33 insertions(+), 52 deletions(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index c42a9bd659..76ba9f7613 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -25,6 +25,10 @@ running: true }); + var totalTime = 0; + var RESET_TIME_THRESHOLD = 2; + var RESET_POSITION = {x: 549.12, y: 495.555, z: 503.77}; + this.getUserData = function() { @@ -40,8 +44,21 @@ } this.update = function(deltaTime) { - self.properties = Entities.getEntityProperties(self.entityId); self.getUserData(); + self.properties = Entities.getEntityProperties(self.entityId); + totalTime += deltaTime; + if(totalTime > RESET_TIME_THRESHOLD) { + if(!self.activated) { + print("RESET"); + Entities.editEntity(self.entityId, { + position: RESET_POSITION, + rotation: Quat.fromPitchYawRollDegrees(0, 0, 0), + angularVelocity: ZERO_VEC, + velocity: ZERO_VEC + }); + } + totalTime = 0; + } if (self.userData.grabKey && self.userData.grabKey.activated === true) { if (self.activated !== true) { Entities.editEntity(self.paintStream, { diff --git a/examples/sprayPaintSpawner.js b/examples/sprayPaintSpawner.js index bd4edbb07c..df04a4efcc 100644 --- a/examples/sprayPaintSpawner.js +++ b/examples/sprayPaintSpawner.js @@ -8,67 +8,31 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -var scriptURL = "entityScripts/sprayPaintCan.js"; +// var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; +var scriptURL = "file:////Users/ericlevin/hifi/examples/entityScripts/sprayPaintCan.js?=v1" + Math.random(); +var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx"; var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); -var paintGun = Entities.addEntity({ +var sprayCan = Entities.addEntity({ type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/eric/models/sprayGun.fbx?=v4", - position: center, + name: "spraycan", + modelURL: modelURL, + position: {x: 549.12, y:495.55, z:503.77}, + rotation: {x: 0, y: 0, z: 0, w: 1}, dimensions: { - x: 0.03, - y: 0.15, - z: 0.34 + x: 0.07, + y: 0.17, + z: 0.07 }, collisionsWillMove: true, shapeType: 'box', - script: scriptURL -}); - -var whiteboard = Entities.addEntity({ - type: "Box", - position: center, - dimensions: { - x: 2, - y: 1.5, - z: .01 - }, - rotation: orientationOf(Vec3.subtract(MyAvatar.position, center)), - color: { - red: 250, - green: 250, - blue: 250 - }, - // visible: false + script: scriptURL, + gravity: {x: 0, y: -0.5, z: 0}, + velocity: {x: 0, y: -.01, z: 0} }); function cleanup() { - Entities.deleteEntity(paintGun); - Entities.deleteEntity(whiteboard); + Entities.deleteEntity(sprayCan); } - Script.scriptEnding.connect(cleanup); - - -function orientationOf(vector) { - var Y_AXIS = { - x: 0, - y: 1, - z: 0 - }; - var X_AXIS = { - x: 1, - y: 0, - z: 0 - }; - - var theta = 0.0; - - var RAD_TO_DEG = 180.0 / Math.PI; - var direction, yaw, pitch; - direction = Vec3.normalize(vector); - yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); - pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); - return Quat.multiply(yaw, pitch); -} From 510e253575de2c3d477187495c3dcd3ed1bff626 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 10 Sep 2015 16:26:57 -0700 Subject: [PATCH 05/17] switching to hosted script for testing --- examples/entityScripts/sprayPaintCan.js | 31 ++++++++++++------------- examples/sprayPaintSpawner.js | 4 ++-- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 76ba9f7613..47da0b5171 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -25,9 +25,11 @@ running: true }); - var totalTime = 0; - var RESET_TIME_THRESHOLD = 2; - var RESET_POSITION = {x: 549.12, y: 495.555, z: 503.77}; + var RESET_POSITION = { + x: 549.12, + y: 495.555, + z: 503.77 + }; this.getUserData = function() { @@ -46,19 +48,6 @@ this.update = function(deltaTime) { self.getUserData(); self.properties = Entities.getEntityProperties(self.entityId); - totalTime += deltaTime; - if(totalTime > RESET_TIME_THRESHOLD) { - if(!self.activated) { - print("RESET"); - Entities.editEntity(self.entityId, { - position: RESET_POSITION, - rotation: Quat.fromPitchYawRollDegrees(0, 0, 0), - angularVelocity: ZERO_VEC, - velocity: ZERO_VEC - }); - } - totalTime = 0; - } if (self.userData.grabKey && self.userData.grabKey.activated === true) { if (self.activated !== true) { Entities.editEntity(self.paintStream, { @@ -73,9 +62,19 @@ animationSettings: stopSetting }); self.activated = false; + self.reset(); } } + this.reset = function() { + Entities.editEntity(self.entityId, { + position: RESET_POSITION, + rotation: Quat.fromPitchYawRollDegrees(0, 0, 0), + angularVelocity: ZERO_VEC, + velocity: ZERO_VEC + }); + } + this.sprayStream = function() { var forwardVec = Quat.getFront(self.properties.rotation); forwardVec = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 90, 0), forwardVec); diff --git a/examples/sprayPaintSpawner.js b/examples/sprayPaintSpawner.js index df04a4efcc..ffedfb1cbf 100644 --- a/examples/sprayPaintSpawner.js +++ b/examples/sprayPaintSpawner.js @@ -8,8 +8,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; -var scriptURL = "file:////Users/ericlevin/hifi/examples/entityScripts/sprayPaintCan.js?=v1" + Math.random(); +var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; +// var scriptURL = "file:////Users/ericlevin/hifi/examples/entityScripts/sprayPaintCan.js?=v1" + Math.random(); var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx"; var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); From a1fd867c096887837cd9065e28bcec63b1dfaab2 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 10 Sep 2015 16:46:25 -0700 Subject: [PATCH 06/17] timer fix for reset --- examples/entityScripts/sprayPaintCan.js | 20 ++++++++++++++++---- examples/sprayPaintSpawner.js | 4 +++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 47da0b5171..81cb14489d 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -25,6 +25,8 @@ running: true }); + var timeSinceLastMoved = 0; + var RESET_TIME_THRESHOLD = 5; var RESET_POSITION = { x: 549.12, y: 495.555, @@ -48,6 +50,17 @@ this.update = function(deltaTime) { self.getUserData(); self.properties = Entities.getEntityProperties(self.entityId); + + timeSinceLastMoved += deltaTime; + if (Vec3.length(self.properties.velocity) < 0.1) { + if (timeSinceLastMoved > RESET_TIME_THRESHOLD) { + self.reset(); + timeSinceLastMoved = 0; + } + } else { + timeSinceLastMoved = 0; + } + if (self.userData.grabKey && self.userData.grabKey.activated === true) { if (self.activated !== true) { Entities.editEntity(self.paintStream, { @@ -62,7 +75,6 @@ animationSettings: stopSetting }); self.activated = false; - self.reset(); } } @@ -150,9 +162,9 @@ blue: randInt(190, 250) }, dimensions: { - x: 5, - y: 5, - z: 5 + x: 50, + y: 50, + z: 50 }, lifetime: 100 }); diff --git a/examples/sprayPaintSpawner.js b/examples/sprayPaintSpawner.js index ffedfb1cbf..f049c5a1af 100644 --- a/examples/sprayPaintSpawner.js +++ b/examples/sprayPaintSpawner.js @@ -8,7 +8,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; +//Just temporarily using my own bucket here so others can test the entity. Once PR is tested and merged, then the entity script will appear in its proper place in S3, and I wil switch it +var scriptURL = "https://hifi-public.s3.amazonaws.com/eric/scripts/sprayPaintCan.js"; +// var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; // var scriptURL = "file:////Users/ericlevin/hifi/examples/entityScripts/sprayPaintCan.js?=v1" + Math.random(); var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx"; var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); From 94dc86833f451f920ea579046b5f0d5cecbe94d0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 10 Sep 2015 17:01:11 -0700 Subject: [PATCH 07/17] Revert "edit.js adjustment" --- examples/edit.js | 7 +++++-- examples/libraries/entityList.js | 3 +-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 55b745a4e1..d778ff324d 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -260,6 +260,7 @@ var toolBar = (function () { cameraManager.disable(); } else { hasShownPropertiesTool = false; + cameraManager.enable(); entityListTool.setVisible(true); gridTool.setVisible(true); grid.setEnabled(true); @@ -669,11 +670,15 @@ function mouseMove(event) { lastMousePosition = { x: event.x, y: event.y }; + highlightEntityUnderCursor(lastMousePosition, false); idleMouseTimerId = Script.setTimeout(handleIdleMouse, IDLE_MOUSE_TIMEOUT); } function handleIdleMouse() { idleMouseTimerId = null; + if (isActive) { + highlightEntityUnderCursor(lastMousePosition, true); + } } function highlightEntityUnderCursor(position, accurateRay) { @@ -797,7 +802,6 @@ function mouseClickEvent(event) { selectionDisplay.select(selectedEntityID, event); if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { - cameraManager.enable(); cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); @@ -1138,7 +1142,6 @@ Controller.keyReleaseEvent.connect(function (event) { } else if (event.text == "f") { if (isActive) { if (selectionManager.hasSelection()) { - cameraManager.enable(); cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index 3d6bf4d14f..66dc9f336f 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -49,7 +49,7 @@ EntityListTool = function(opts) { var selectedIDs = []; for (var i = 0; i < selectionManager.selections.length; i++) { - selectedIDs.push(selectionManager.selections[i].id); + selectedIDs.push(selectionManager.selections[i].id); // ? } var data = { @@ -70,7 +70,6 @@ EntityListTool = function(opts) { } selectionManager.setSelections(entityIDs); if (data.focus) { - cameraManager.enable(); cameraManager.focus(selectionManager.worldPosition, selectionManager.worldDimensions, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); From 7969fb64cedd6b02656da2a08c8982eb79b944f5 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 10 Sep 2015 17:08:52 -0700 Subject: [PATCH 08/17] tweaking distance threshold --- examples/entityScripts/sprayPaintCan.js | 13 +++++++------ examples/sprayPaintSpawner.js | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 81cb14489d..203be9ba20 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -27,12 +27,12 @@ var timeSinceLastMoved = 0; var RESET_TIME_THRESHOLD = 5; - var RESET_POSITION = { + var DISTANCE_FROM_HOME_THRESHOLD = .5; + var HOME_POSITION = { x: 549.12, y: 495.555, z: 503.77 }; - this.getUserData = function() { @@ -51,13 +51,14 @@ self.getUserData(); self.properties = Entities.getEntityProperties(self.entityId); - timeSinceLastMoved += deltaTime; - if (Vec3.length(self.properties.velocity) < 0.1) { + if (Vec3.length(self.properties.velocity) < 0.1 && Vec3.distance(HOME_POSITION, self.properties.position) > DISTANCE_FROM_HOME_THRESHOLD) { + timeSinceLastMoved += deltaTime; if (timeSinceLastMoved > RESET_TIME_THRESHOLD) { self.reset(); timeSinceLastMoved = 0; } - } else { + } + else { timeSinceLastMoved = 0; } @@ -80,7 +81,7 @@ this.reset = function() { Entities.editEntity(self.entityId, { - position: RESET_POSITION, + position: HOME_POSITION, rotation: Quat.fromPitchYawRollDegrees(0, 0, 0), angularVelocity: ZERO_VEC, velocity: ZERO_VEC diff --git a/examples/sprayPaintSpawner.js b/examples/sprayPaintSpawner.js index f049c5a1af..991ba25064 100644 --- a/examples/sprayPaintSpawner.js +++ b/examples/sprayPaintSpawner.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html //Just temporarily using my own bucket here so others can test the entity. Once PR is tested and merged, then the entity script will appear in its proper place in S3, and I wil switch it -var scriptURL = "https://hifi-public.s3.amazonaws.com/eric/scripts/sprayPaintCan.js"; +var scriptURL = "https://hifi-public.s3.amazonaws.com/eric/scripts/sprayPaintCan.js?=v1" + Math.random(); // var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; // var scriptURL = "file:////Users/ericlevin/hifi/examples/entityScripts/sprayPaintCan.js?=v1" + Math.random(); var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx"; @@ -30,7 +30,7 @@ var sprayCan = Entities.addEntity({ shapeType: 'box', script: scriptURL, gravity: {x: 0, y: -0.5, z: 0}, - velocity: {x: 0, y: -.01, z: 0} + velocity: {x: 0, y: -1, z: 0} }); function cleanup() { From b1c5a04531a69d78a336d3953c96844ccd1aa2ef Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 11 Sep 2015 09:29:52 -0700 Subject: [PATCH 09/17] respond to code review --- libraries/entities/src/EntityItem.cpp | 4 ++-- libraries/entities/src/EntityScriptingInterface.cpp | 4 ++-- libraries/entities/src/EntityTree.cpp | 6 +++--- libraries/entities/src/EntityTreeElement.cpp | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 9f06b0d661..80ac715994 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -986,8 +986,8 @@ bool EntityItem::isMoving() const { } EntityTreePointer EntityItem::getTree() const { - EntityTreeElementPointer elt = getElement(); - EntityTreePointer tree = elt ? elt->getTree() : nullptr; + EntityTreeElementPointer containingElement = getElement(); + EntityTreePointer tree = containingElement ? containingElement->getTree() : nullptr; return tree; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index fd099344ba..2e01d7f774 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -47,14 +47,14 @@ bool EntityScriptingInterface::canRez() { return nodeList->getThisNodeCanRez(); } -void EntityScriptingInterface::setEntityTree(EntityTreePointer modelTree) { +void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { if (_entityTree) { disconnect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); disconnect(_entityTree.get(), &EntityTree::deletingEntity, this, &EntityScriptingInterface::deletingEntity); disconnect(_entityTree.get(), &EntityTree::clearingEntities, this, &EntityScriptingInterface::clearingEntities); } - _entityTree = modelTree; + _entityTree = elementTree; if (_entityTree) { connect(_entityTree.get(), &EntityTree::addingEntity, this, &EntityScriptingInterface::addingEntity); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 26c6cd2f0b..10e5ea5a39 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -45,9 +45,9 @@ void EntityTree::createRootElement() { OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { EntityTreeElementPointer newElement = EntityTreeElementPointer(new EntityTreeElement(octalCode), // see comment int EntityTreeElement::createNewElement - [=](EntityTreeElement* elt) { - EntityTreeElementPointer tmpSharedPointer(elt); - elt->notifyDeleteHooks(); + [=](EntityTreeElement* dyingElement) { + EntityTreeElementPointer tmpSharedPointer(dyingElement); + dyingElement->notifyDeleteHooks(); }); newElement->setTree(std::static_pointer_cast(shared_from_this())); return std::static_pointer_cast(newElement); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 536c3d6d9f..9a31c18219 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -42,12 +42,12 @@ OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCod // or the destructor wouldn't have been called). The destructor also can't // make a new shared pointer -- shared_from_this() is forbidden in a destructor, and // using OctreeElementPointer(this) also fails. So, I've installed a custom deleter: - [=](EntityTreeElement* elt) { + [=](EntityTreeElement* dyingElement) { // make a new shared pointer with a reference count of 1 (and no custom deleter) - EntityTreeElementPointer tmpSharedPointer(elt); + EntityTreeElementPointer tmpSharedPointer(dyingElement); // call notifyDeleteHooks which will use shared_from_this() to get this same // shared pointer, for use with the elementDeleted calls. - elt->notifyDeleteHooks(); + dyingElement->notifyDeleteHooks(); // And now tmpSharedPointer's reference count drops to zero and the // normal destructors are called. }); From 1991ba0eba512490b112cbeca432503eb7ddd846 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 11 Sep 2015 09:37:03 -0700 Subject: [PATCH 10/17] absolute path for now- just for testing purposes before merge --- examples/entityScripts/sprayPaintCan.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 203be9ba20..9ba6d75600 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -1,5 +1,7 @@ (function() { - Script.include("../libraries/utils.js"); + // Script.include("../libraries/utils.js"); + //Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge + Script.include("https://hifi-public.s3.amazonaws.com/scripts/libraries/utils.js"); GRAB_FRAME_USER_DATA_KEY = "grabFrame"; this.userData = {}; From b9d5412aad8a6b23cb2b45ec2cde96f9581b1362 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Sep 2015 09:48:42 -0700 Subject: [PATCH 11/17] prevent sending signals in the entities script engine --- .../src/EntityTreeRenderer.cpp | 4 +- libraries/script-engine/src/ScriptEngine.cpp | 70 ++++++++++++++----- libraries/script-engine/src/ScriptEngine.h | 4 +- 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4a91850fb7..a24461da83 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -113,10 +113,10 @@ void EntityTreeRenderer::init() { if (_wantScripts) { _entitiesScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities", - _scriptingServices->getControllerScriptingInterface()); + _scriptingServices->getControllerScriptingInterface(), false); _scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine); - _sandboxScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities Sandbox", NULL); + _sandboxScriptEngine = new ScriptEngine(NO_SCRIPT, "Entities Sandbox", NULL, false); } // make sure our "last avatar position" is something other than our current position, so that on our diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index b6c3205fb7..9f061a5cdb 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -81,7 +81,7 @@ void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputCon } ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, - AbstractControllerScriptingInterface* controllerScriptingInterface) : + AbstractControllerScriptingInterface* controllerScriptingInterface, bool wantSignals) : _scriptContents(scriptContents), _isFinished(false), @@ -95,6 +95,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _avatarSound(NULL), _numAvatarSoundSentBytes(0), _controllerScriptingInterface(controllerScriptingInterface), + _wantSignals(wantSignals), _avatarData(NULL), _scriptName(), _fileNameString(fileNameString), @@ -299,10 +300,14 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { qCDebug(scriptengine) << "ScriptEngine loading file:" << _fileNameString; QTextStream in(&scriptFile); _scriptContents = in.readAll(); - emit scriptLoaded(_fileNameString); + if (_wantSignals) { + emit scriptLoaded(_fileNameString); + } } else { qCDebug(scriptengine) << "ERROR Loading file:" << _fileNameString << "line:" << __LINE__; - emit errorLoadingScript(_fileNameString); + if (_wantSignals) { + emit errorLoadingScript(_fileNameString); + } } } else { bool isPending; @@ -314,12 +319,16 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) { _scriptContents = scriptContents; - emit scriptLoaded(_fileNameString); + if (_wantSignals) { + emit scriptLoaded(_fileNameString); + } } void ScriptEngine::errorInLoadingScript(const QUrl& url) { qCDebug(scriptengine) << "ERROR Loading file:" << url.toString() << "line:" << __LINE__; - emit errorLoadingScript(_fileNameString); // ?? + if (_wantSignals) { + emit errorLoadingScript(_fileNameString); // ?? + } } void ScriptEngine::init() { @@ -524,7 +533,9 @@ void ScriptEngine::evaluate() { if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << result.toString(); - emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); + if (_wantSignals) { + emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + result.toString()); + } clearExceptions(); } } @@ -541,7 +552,9 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); } _evaluatesPending--; - emit evaluationFinished(result, hasUncaughtException()); + if (_wantSignals) { + emit evaluationFinished(result, hasUncaughtException()); + } clearExceptions(); return result; } @@ -567,7 +580,9 @@ void ScriptEngine::run() { } _isRunning = true; _isFinished = false; - emit runningStateChanged(); + if (_wantSignals) { + emit runningStateChanged(); + } QScriptValue result = evaluate(_scriptContents); @@ -714,19 +729,25 @@ void ScriptEngine::run() { if (hasUncaughtException()) { int line = uncaughtExceptionLineNumber(); qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString(); - emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); + if (_wantSignals) { + emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); + } clearExceptions(); } if (!_isFinished) { - emit update(deltaTime); + if (_wantSignals) { + emit update(deltaTime); + } } lastUpdate = now; } stopAllTimers(); // make sure all our timers are stopped if the script is ending - emit scriptEnding(); + if (_wantSignals) { + emit scriptEnding(); + } // kill the avatar identity timer delete _avatarIdentityTimer; @@ -747,12 +768,15 @@ void ScriptEngine::run() { } } - emit finished(_fileNameString); + if (_wantSignals) { + emit finished(_fileNameString); + } _isRunning = false; - emit runningStateChanged(); - - emit doneRunning(); + if (_wantSignals) { + emit runningStateChanged(); + emit doneRunning(); + } _doneRunningThisScript = true; } @@ -771,7 +795,9 @@ void ScriptEngine::stopAllTimers() { void ScriptEngine::stop() { if (!_isFinished) { _isFinished = true; - emit runningStateChanged(); + if (_wantSignals) { + emit runningStateChanged(); + } } } @@ -859,7 +885,9 @@ QUrl ScriptEngine::resolvePath(const QString& include) const { } void ScriptEngine::print(const QString& message) { - emit printedMessage(message); + if (_wantSignals) { + emit printedMessage(message); + } } // If a callback is specified, the included files will be loaded asynchronously and the callback will be called @@ -943,9 +971,13 @@ void ScriptEngine::load(const QString& loadFile) { if (_isReloading) { auto scriptCache = DependencyManager::get(); scriptCache->deleteScript(url.toString()); - emit reloadScript(url.toString(), false); + if (_wantSignals) { + emit reloadScript(url.toString(), false); + } } else { - emit loadScript(url.toString(), false); + if (_wantSignals) { + emit loadScript(url.toString(), false); + } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c55f13ab47..2bfcecc99e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -45,7 +45,8 @@ class ScriptEngine : public QScriptEngine, public ScriptUser { public: ScriptEngine(const QString& scriptContents = NO_SCRIPT, const QString& fileNameString = QString(""), - AbstractControllerScriptingInterface* controllerScriptingInterface = NULL); + AbstractControllerScriptingInterface* controllerScriptingInterface = NULL, + bool wantSignals = true); ~ScriptEngine(); @@ -156,6 +157,7 @@ protected: int _numAvatarSoundSentBytes; bool _isAgent = false; QSet _includedURLs; + bool _wantSignals = true; private: void stopAllTimers(); From 7996a02bd8270c2321a72f758bacc32d397fc6fe Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 11 Sep 2015 09:48:48 -0700 Subject: [PATCH 12/17] Added head target to AnimGraph IK node. * In HMD mode head orientation and position is set. * When not in HMD only orientation is set, position should default to the underlying pose position. --- interface/src/avatar/MyAvatar.cpp | 3 +- interface/src/avatar/SkeletonModel.cpp | 11 +++ .../animation/src/AnimInverseKinematics.cpp | 2 +- libraries/animation/src/AnimVariant.h | 1 + libraries/animation/src/Rig.cpp | 76 ++++++++++++------- libraries/animation/src/Rig.h | 9 ++- libraries/render-utils/src/AnimDebugDraw.cpp | 18 +++++ libraries/render-utils/src/AnimDebugDraw.h | 9 +++ tests/animation/src/data/avatar.json | 5 ++ 9 files changed, 101 insertions(+), 33 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bafca2844d..85c47ad665 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1276,7 +1276,8 @@ void MyAvatar::initAnimGraph() { // // or run a local web-server // python -m SimpleHTTPServer& - auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/e58e0a24cc341ad5d060/raw/2a994bef7726ce8e9efcee7622b8b1a1b6b67490/ik-avatar.json"); + // auto graphUrl = QUrl("http://localhost:8000/avatar.json"); + auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/e58e0a24cc341ad5d060/raw/8f824da2908fd89ad1befadd1d8f5d7b3b6efa66/ik-avatar.json"); _rig->initAnimGraph(graphUrl, _skeletonModel.getGeometry()->getFBXGeometry()); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8a05b15c4c..41ca193a7a 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -116,6 +116,17 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.leanForward = head->getFinalLeanForward(); params.torsoTwist = head->getTorsoTwist(); params.localHeadOrientation = head->getFinalOrientationInLocalFrame(); + params.localHeadPitch = head->getFinalPitch(); + params.localHeadYaw = head->getFinalYaw(); + params.localHeadRoll = head->getFinalRoll(); + params.isInHMD = qApp->getAvatarUpdater()->isHMDMode(); + + // get HMD position from sensor space into world space, and back into model space + glm::mat4 worldToModel = glm::inverse(createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition())); + glm::vec3 yAxis(0.0f, 1.0f, 0.0f); + glm::vec3 hmdPosition = glm::angleAxis((float)M_PI, yAxis) * transformPoint(worldToModel * myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition()); + params.localHeadPosition = hmdPosition; + params.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); params.eyeLookAt = head->getLookAtPosition(); params.eyeSaccade = head->getSaccade(); diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 71401b6c60..3aa3f7718f 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -40,7 +40,7 @@ void AnimInverseKinematics::loadPoses(const AnimPoseVec& poses) { void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) const { int numJoints = (int)_relativePoses.size(); absolutePoses.clear(); - absolutePoses.reserve(numJoints); + absolutePoses.resize(numJoints); assert(numJoints <= _skeleton->getNumJoints()); for (int i = 0; i < numJoints; ++i) { int parentIndex = _skeleton->getParentIndex(i); diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 1d720ba565..ac84aafc32 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -149,6 +149,7 @@ public: void set(const std::string& key, const glm::quat& value) { _map[key] = AnimVariant(value); } void set(const std::string& key, const glm::mat4& value) { _map[key] = AnimVariant(value); } void set(const std::string& key, const std::string& value) { _map[key] = AnimVariant(value); } + void unset(const std::string& key) { _map.erase(key); } void setTrigger(const std::string& key) { _triggers.insert(key); } void clearTriggers() { _triggers.clear(); } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index e0a2b31622..528f678b33 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -30,6 +30,9 @@ void Rig::HeadParameters::dump() const { qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta); axis = glm::axis(worldHeadOrientation); theta = glm::angle(worldHeadOrientation); + qCDebug(animation, " localHead pitch = %.5f, yaw = %.5f, roll = %.5f", (double)localHeadPitch, (double)localHeadYaw, (double)localHeadRoll); + qCDebug(animation, " localHeadPosition = (%.5f, %.5f, %.5f)", (double)localHeadPosition.x, (double)localHeadPosition.y, (double)localHeadPosition.z); + qCDebug(animation, " isInHMD = %s", isInHMD ? "true" : "false"); qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta); axis = glm::axis(modelRotation); theta = glm::angle(modelRotation); @@ -953,56 +956,71 @@ void Rig::updateFromHeadParameters(const HeadParameters& params) { if (params.enableLean) { updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); } - updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist); + updateNeckJoint(params.neckJointIndex, params); updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); } +static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f); +static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f); +static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f); + void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { if (_enableAnimGraph && _animSkeleton) { - glm::vec3 xAxis(1.0f, 0.0f, 0.0f); - glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - glm::vec3 zAxis(0.0f, 0.0f, 1.0f); - glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, zAxis) * - glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, xAxis) * - glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, yAxis)); + glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, Z_AXIS) * + glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, X_AXIS) * + glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, Y_AXIS)); _animVars.set("lean", absRot); } else if (!_enableAnimGraph) { auto& parentState = _jointStates[_jointStates[index].getParentIndex()]; // get the rotation axes in joint space and use them to adjust the rotation - glm::vec3 xAxis(1.0f, 0.0f, 0.0f); - glm::vec3 yAxis(0.0f, 1.0f, 0.0f); - glm::vec3 zAxis(0.0f, 0.0f, 1.0f); glm::quat inverse = glm::inverse(parentState.getRotation() * getJointDefaultRotationInParentFrame(index)); setJointRotationInConstrainedFrame(index, - glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * zAxis) * - glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * xAxis) * - glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * yAxis) * + glm::angleAxis(- RADIANS_PER_DEGREE * leanSideways, inverse * Z_AXIS) * + glm::angleAxis(- RADIANS_PER_DEGREE * leanForward, inverse * X_AXIS) * + glm::angleAxis(RADIANS_PER_DEGREE * torsoTwist, inverse * Y_AXIS) * getJointState(index).getDefaultRotation(), DEFAULT_PRIORITY); } } } -void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist) { +void Rig::updateNeckJoint(int index, const HeadParameters& params) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { - auto& state = _jointStates[index]; - auto& parentState = _jointStates[state.getParentIndex()]; + if (_enableAnimGraph && _animSkeleton) { + // the params.localHeadOrientation is composed incorrectly, so re-compose it correctly from pitch, yaw and roll. + glm::quat realLocalHeadOrientation = (glm::angleAxis(glm::radians(-params.localHeadRoll), Z_AXIS) * + glm::angleAxis(glm::radians(params.localHeadYaw), Y_AXIS) * + glm::angleAxis(glm::radians(-params.localHeadPitch), X_AXIS)); + _animVars.set("headRotation", realLocalHeadOrientation); - // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(glm::quat()); - glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * - glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * - state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); - glm::vec3 pitchYawRoll = safeEulerAngles(localHeadOrientation); - glm::vec3 lean = glm::radians(glm::vec3(leanForward, torsoTwist, leanSideways)); - pitchYawRoll -= lean; - setJointRotationInConstrainedFrame(index, - glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * axes[2])) * - glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * axes[1])) * - glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * axes[0])) * - state.getDefaultRotation(), DEFAULT_PRIORITY); + auto rootTrans = _animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans; + + if (params.isInHMD) { + _animVars.set("headPosition", params.localHeadPosition + rootTrans); + } else { + _animVars.unset("headPosition"); + } + } else if (!_enableAnimGraph) { + + auto& state = _jointStates[index]; + auto& parentState = _jointStates[state.getParentIndex()]; + + // get the rotation axes in joint space and use them to adjust the rotation + glm::mat3 axes = glm::mat3_cast(glm::quat()); + glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * + glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * + state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); + glm::vec3 pitchYawRoll = safeEulerAngles(params.localHeadOrientation); + glm::vec3 lean = glm::radians(glm::vec3(params.leanForward, params.torsoTwist, params.leanSideways)); + pitchYawRoll -= lean; + setJointRotationInConstrainedFrame(index, + glm::angleAxis(-pitchYawRoll.z, glm::normalize(inverse * Z_AXIS)) * + glm::angleAxis(pitchYawRoll.y, glm::normalize(inverse * Y_AXIS)) * + glm::angleAxis(-pitchYawRoll.x, glm::normalize(inverse * X_AXIS)) * + state.getDefaultRotation(), DEFAULT_PRIORITY); + } } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 0a3ebad5d2..5f04dd550f 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -59,10 +59,15 @@ public: bool enableLean = false; glm::quat modelRotation = glm::quat(); glm::quat localHeadOrientation = glm::quat(); + float localHeadPitch = 0.0f; // degrees + float localHeadYaw = 0.0f; // degrees + float localHeadRoll = 0.0f; // degrees + glm::vec3 localHeadPosition = glm::vec3(0); + bool isInHMD = false; glm::quat worldHeadOrientation = glm::quat(); glm::vec3 eyeLookAt = glm::vec3(); // world space glm::vec3 eyeSaccade = glm::vec3(); // world space - glm::vec3 modelTranslation = glm::vec3(); + glm::vec3 modelTranslation = glm::vec3(0); int leanJointIndex = -1; int neckJointIndex = -1; int leftEyeJointIndex = -1; @@ -177,7 +182,7 @@ public: protected: void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist); - void updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist); + void updateNeckJoint(int index, const HeadParameters& params); void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); QVector _jointStates; diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index b91db94f74..d057bf067f 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -176,6 +176,14 @@ void AnimDebugDraw::removePoses(const std::string& key) { _poses.erase(key); } +void AnimDebugDraw::addPose(const std::string& key, const AnimPose& pose, const AnimPose& rootPose) { + _singlePoses[key] = SinglePoseInfo(pose, rootPose); +} + +void AnimDebugDraw::removePose(const std::string& key) { + _singlePoses.erase(key); +} + static const uint32_t red = toRGBA(255, 0, 0, 255); static const uint32_t green = toRGBA(0, 255, 0, 255); static const uint32_t blue = toRGBA(0, 0, 255, 255); @@ -333,6 +341,7 @@ void AnimDebugDraw::update() { const size_t VERTICES_PER_LINK = 8 * 2; const float BONE_RADIUS = 0.01f; // 1 cm + const float POSE_RADIUS = 0.1f; // 10 cm // figure out how many verts we will need. int numVerts = 0; @@ -371,6 +380,8 @@ void AnimDebugDraw::update() { } } + numVerts += _singlePoses.size() * VERTICES_PER_BONE; + data._vertexBuffer->resize(sizeof(Vertex) * numVerts); Vertex* verts = (Vertex*)data._vertexBuffer->editData(); Vertex* v = verts; @@ -475,6 +486,13 @@ void AnimDebugDraw::update() { } } + for (auto& iter : _singlePoses) { + AnimPose pose = std::get<0>(iter.second); + AnimPose rootPose = std::get<1>(iter.second); + const float radius = POSE_RADIUS / (pose.scale.x * rootPose.scale.x); + addBone(rootPose, pose, radius, v); + } + assert(numVerts == (v - verts)); data._indexBuffer->resize(sizeof(uint16_t) * numVerts); diff --git a/libraries/render-utils/src/AnimDebugDraw.h b/libraries/render-utils/src/AnimDebugDraw.h index cd17f62590..5bb19097f2 100644 --- a/libraries/render-utils/src/AnimDebugDraw.h +++ b/libraries/render-utils/src/AnimDebugDraw.h @@ -27,15 +27,22 @@ public: AnimDebugDraw(); ~AnimDebugDraw(); + // draw a skeleton bind pose void addSkeleton(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPose& rootPose, const glm::vec4& color); void removeSkeleton(const std::string& key); + // draw the interal poses for a specific animNode void addAnimNode(const std::string& key, AnimNode::ConstPointer animNode, const AnimPose& rootPose, const glm::vec4& color); void removeAnimNode(const std::string& key); + // draw a set of poses with a skeleton void addPoses(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPoseVec& poses, const AnimPose& rootPose, const glm::vec4& color); void removePoses(const std::string& key); + // draw a single pose + void addPose(const std::string& key, const AnimPose& rootPose, const AnimPose& pose); + void removePose(const std::string& key); + void update(); protected: @@ -48,10 +55,12 @@ protected: typedef std::tuple SkeletonInfo; typedef std::tuple AnimNodeInfo; typedef std::tuple PosesInfo; + typedef std::tuple SinglePoseInfo; std::unordered_map _skeletons; std::unordered_map _animNodes; std::unordered_map _poses; + std::unordered_map _singlePoses; // no copies AnimDebugDraw(const AnimDebugDraw&) = delete; diff --git a/tests/animation/src/data/avatar.json b/tests/animation/src/data/avatar.json index 3122fd433d..08425201b0 100644 --- a/tests/animation/src/data/avatar.json +++ b/tests/animation/src/data/avatar.json @@ -22,6 +22,11 @@ "jointName": "LeftHand", "positionVar": "leftHandPosition", "rotationVar": "leftHandRotation" + }, + { + "jointName": "Head", + "positionVar": "headPosition", + "rotationVar": "headRotation" } ] }, From 8e504e63b0fab35356d637651080ceed907bc165 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 11 Sep 2015 10:43:49 -0700 Subject: [PATCH 13/17] Removed unused variable, changed glm::vec3(0) to glm::vec3() --- libraries/animation/src/Rig.cpp | 1 - libraries/animation/src/Rig.h | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 528f678b33..3729dc8ca7 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1008,7 +1008,6 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { auto& parentState = _jointStates[state.getParentIndex()]; // get the rotation axes in joint space and use them to adjust the rotation - glm::mat3 axes = glm::mat3_cast(glm::quat()); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.getTransform() * glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * state.getPreTransform() * glm::mat4_cast(state.getPreRotation()))); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 5f04dd550f..68a0b327da 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -62,12 +62,12 @@ public: float localHeadPitch = 0.0f; // degrees float localHeadYaw = 0.0f; // degrees float localHeadRoll = 0.0f; // degrees - glm::vec3 localHeadPosition = glm::vec3(0); + glm::vec3 localHeadPosition = glm::vec3(); bool isInHMD = false; glm::quat worldHeadOrientation = glm::quat(); glm::vec3 eyeLookAt = glm::vec3(); // world space glm::vec3 eyeSaccade = glm::vec3(); // world space - glm::vec3 modelTranslation = glm::vec3(0); + glm::vec3 modelTranslation = glm::vec3(); int leanJointIndex = -1; int neckJointIndex = -1; int leftEyeJointIndex = -1; From 6e46e3d3b67a7a592d4f652133b6aa0e0d2d3600 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 11 Sep 2015 11:24:53 -0700 Subject: [PATCH 14/17] cleanup for paintcan --- examples/entityScripts/sprayPaintCan.js | 2 +- examples/sprayPaintSpawner.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 9ba6d75600..8a5829c441 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -29,7 +29,7 @@ var timeSinceLastMoved = 0; var RESET_TIME_THRESHOLD = 5; - var DISTANCE_FROM_HOME_THRESHOLD = .5; + var DISTANCE_FROM_HOME_THRESHOLD = 0.5; var HOME_POSITION = { x: 549.12, y: 495.555, diff --git a/examples/sprayPaintSpawner.js b/examples/sprayPaintSpawner.js index 991ba25064..77b74e6520 100644 --- a/examples/sprayPaintSpawner.js +++ b/examples/sprayPaintSpawner.js @@ -9,9 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html //Just temporarily using my own bucket here so others can test the entity. Once PR is tested and merged, then the entity script will appear in its proper place in S3, and I wil switch it -var scriptURL = "https://hifi-public.s3.amazonaws.com/eric/scripts/sprayPaintCan.js?=v1" + Math.random(); -// var scriptURL = "https://hifi-public.s3.amazonaws.com/scripts/entityScripts/sprayPaintCan.js"; -// var scriptURL = "file:////Users/ericlevin/hifi/examples/entityScripts/sprayPaintCan.js?=v1" + Math.random(); +var scriptURL = "https://hifi-public.s3.amazonaws.com/eric/scripts/sprayPaintCan.js?=v1"; var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx"; var center = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation()))); From eabdd1f4d9f6a42d648047f870695079e626b297 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 11 Sep 2015 11:33:21 -0700 Subject: [PATCH 15/17] quick fix for particles hanging around --- examples/entityScripts/sprayPaintCan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 8a5829c441..4af404d275 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -229,7 +229,7 @@ green: 20, blue: 150 }, - lifespan: 5, + lifetime: 1000, }); } From 5c6d8da97b26c3ffb4a0fbe7b5593077d028fba2 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 11 Sep 2015 11:55:36 -0700 Subject: [PATCH 16/17] Revert "Make sure all entity script callbacks happen on the Entities script engine thread" --- .../src/EntityTreeRenderer.cpp | 63 ++++++------------- libraries/script-engine/src/ScriptCache.cpp | 1 - libraries/script-engine/src/ScriptEngine.cpp | 14 ----- libraries/script-engine/src/ScriptEngine.h | 2 - libraries/shared/src/RegisteredMetaTypes.cpp | 3 +- 5 files changed, 21 insertions(+), 62 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a24461da83..93a9996740 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -242,7 +242,6 @@ QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool QString scriptContents = loadScriptContents(entityScript, isURL, isPending, url, reload); if (isPending && isPreload && isURL) { - //qDebug() << "attempted to load script, isPending, _waitingOnPreload.insert() url:" << url << "entityID:" << entityID; _waitingOnPreload.insert(url, entityID); } @@ -325,8 +324,7 @@ void EntityTreeRenderer::update() { QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, _lastMouseEvent); QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { - //qDebug() << "About to call holdingClickOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("holdingClickOnEntity", currentClickingEntity, currentClickingEntityArgs); + currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); } } @@ -365,9 +363,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { QScriptValueList entityArgs = createEntityArgs(entityID); QScriptValue entityScript = loadEntityScript(entityID); if (entityScript.property("leaveEntity").isValid()) { - - //qDebug() << "About to call leaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("leaveEntity", entityScript, entityArgs); + entityScript.property("leaveEntity").call(entityScript, entityArgs); } } @@ -380,8 +376,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { QScriptValueList entityArgs = createEntityArgs(entityID); QScriptValue entityScript = loadEntityScript(entityID); if (entityScript.property("enterEntity").isValid()) { - //qDebug() << "About to call enterEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("enterEntity", entityScript, entityArgs); + entityScript.property("enterEntity").call(entityScript, entityArgs); } } } @@ -400,8 +395,7 @@ void EntityTreeRenderer::leaveAllEntities() { QScriptValueList entityArgs = createEntityArgs(entityID); QScriptValue entityScript = loadEntityScript(entityID); if (entityScript.property("leaveEntity").isValid()) { - //qDebug() << "About to call leaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("leaveEntity", entityScript, entityArgs); + entityScript.property("leaveEntity").call(entityScript, entityArgs); } } _currentEntitiesInside.clear(); @@ -857,7 +851,7 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device bool precisionPicking = !_dontDoPrecisionPicking; RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::Lock, precisionPicking); if (rayPickResult.intersects) { - qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID; + //qCDebug(entitiesrenderer) << "mousePressEvent over entity:" << rayPickResult.entityID; QString urlString = rayPickResult.properties.getHref(); QUrl url = QUrl(urlString, QUrl::StrictMode); @@ -871,15 +865,13 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event, unsigned int device QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); QScriptValue entityScript = loadEntityScript(rayPickResult.entity); if (entityScript.property("mousePressOnEntity").isValid()) { - //qDebug() << "About to call mousePressOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("mousePressOnEntity", entityScript, entityScriptArgs); + entityScript.property("mousePressOnEntity").call(entityScript, entityScriptArgs); } _currentClickingOnEntityID = rayPickResult.entityID; emit clickDownOnEntity(_currentClickingOnEntityID, MouseEvent(*event, deviceID)); if (entityScript.property("clickDownOnEntity").isValid()) { - //qDebug() << "About to call clickDownOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("clickDownOnEntity", entityScript, entityScriptArgs); + entityScript.property("clickDownOnEntity").call(entityScript, entityScriptArgs); } } else { emit mousePressOffEntity(rayPickResult, event, deviceID); @@ -905,7 +897,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi QScriptValueList entityScriptArgs = createMouseEventArgs(rayPickResult.entityID, event, deviceID); QScriptValue entityScript = loadEntityScript(rayPickResult.entity); if (entityScript.property("mouseReleaseOnEntity").isValid()) { - _entitiesScriptEngine->callScriptMethod("mouseReleaseOnEntity", entityScript, entityScriptArgs); + entityScript.property("mouseReleaseOnEntity").call(entityScript, entityScriptArgs); } } @@ -917,8 +909,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event, unsigned int devi QScriptValueList currentClickingEntityArgs = createMouseEventArgs(_currentClickingOnEntityID, event, deviceID); QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); if (currentClickingEntity.property("clickReleaseOnEntity").isValid()) { - //qDebug() << "About to call clickReleaseOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("clickReleaseOnEntity", currentClickingEntity, currentClickingEntityArgs); + currentClickingEntity.property("clickReleaseOnEntity").call(currentClickingEntity, currentClickingEntityArgs); } } @@ -946,13 +937,11 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI // load the entity script if needed... QScriptValue entityScript = loadEntityScript(rayPickResult.entity); if (entityScript.property("mouseMoveEvent").isValid()) { - //qDebug() << "About to call mouseMoveEvent() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("mouseMoveEvent", entityScript, entityScriptArgs); + entityScript.property("mouseMoveEvent").call(entityScript, entityScriptArgs); } emit mouseMoveOnEntity(rayPickResult, event, deviceID); if (entityScript.property("mouseMoveOnEntity").isValid()) { - //qDebug() << "About to call mouseMoveOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("mouseMoveOnEntity", entityScript, entityScriptArgs); + entityScript.property("mouseMoveOnEntity").call(entityScript, entityScriptArgs); } // handle the hover logic... @@ -966,9 +955,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { - //qDebug() << "About to call hoverLeaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("hoverLeaveEntity", currentHoverEntity, currentHoverEntityArgs); - + currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); } } @@ -977,8 +964,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI if (rayPickResult.entityID != _currentHoverOverEntityID) { emit hoverEnterEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); if (entityScript.property("hoverEnterEntity").isValid()) { - //qDebug() << "About to call hoverEnterEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("hoverEnterEntity", entityScript, entityScriptArgs); + entityScript.property("hoverEnterEntity").call(entityScript, entityScriptArgs); } } @@ -986,8 +972,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI // we should send our hover over event emit hoverOverEntity(rayPickResult.entityID, MouseEvent(*event, deviceID)); if (entityScript.property("hoverOverEntity").isValid()) { - //qDebug() << "About to call hoverOverEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("hoverOverEntity", entityScript, entityScriptArgs); + entityScript.property("hoverOverEntity").call(entityScript, entityScriptArgs); } // remember what we're hovering over @@ -1004,8 +989,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI QScriptValue currentHoverEntity = loadEntityScript(_currentHoverOverEntityID); if (currentHoverEntity.property("hoverLeaveEntity").isValid()) { - //qDebug() << "About to call hoverLeaveEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("hoverLeaveEntity", currentHoverEntity, currentHoverEntityArgs); + currentHoverEntity.property("hoverLeaveEntity").call(currentHoverEntity, currentHoverEntityArgs); } _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID @@ -1021,8 +1005,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI QScriptValue currentClickingEntity = loadEntityScript(_currentClickingOnEntityID); if (currentClickingEntity.property("holdingClickOnEntity").isValid()) { - //qDebug() << "About to call holdingClickOnEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("holdingClickOnEntity", currentClickingEntity, currentClickingEntityArgs); + currentClickingEntity.property("holdingClickOnEntity").call(currentClickingEntity, currentClickingEntityArgs); } } _lastMouseEvent = MouseEvent(*event, deviceID); @@ -1077,8 +1060,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const QScriptValue entityScript = loadEntityScript(entityID, true, reload); // is preload! if (entityScript.property("preload").isValid()) { QScriptValueList entityArgs = createEntityArgs(entityID); - //qDebug() << "About to call preload() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("preload", entityScript, entityArgs); + entityScript.property("preload").call(entityScript, entityArgs); } } } @@ -1088,8 +1070,7 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) { QScriptValue entityScript = getPreviouslyLoadedEntityScript(entityID); if (entityScript.property("unload").isValid()) { QScriptValueList entityArgs = createEntityArgs(entityID); - //qDebug() << "About to call unload() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("unload", entityScript, entityArgs); + entityScript.property("unload").call(entityScript, entityArgs); } } } @@ -1174,9 +1155,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons args << idA.toScriptValue(_entitiesScriptEngine); args << idB.toScriptValue(_entitiesScriptEngine); args << collisionToScriptValue(_entitiesScriptEngine, collision); - - //qDebug() << "About to call collisionWithEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("collisionWithEntity", entityScriptA, args); + entityScriptA.property("collisionWithEntity").call(entityScriptA, args); } emit collisionWithEntity(idB, idA, collision); @@ -1186,9 +1165,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons args << idB.toScriptValue(_entitiesScriptEngine); args << idA.toScriptValue(_entitiesScriptEngine); args << collisionToScriptValue(_entitiesScriptEngine, collision); - - //qDebug() << "About to call collisionWithEntity() current thread:" << QThread::currentThread() << "entities thread:" << _entitiesScriptEngine->thread(); - _entitiesScriptEngine->callScriptMethod("collisionWithEntity", entityScriptB, args); + entityScriptB.property("collisionWithEntity").call(entityScriptA, args); } } diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index fb523b157c..9e04cd4ec3 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -68,7 +68,6 @@ void ScriptCache::scriptDownloaded() { qCDebug(scriptengine) << "Done downloading script at:" << url.toString(); foreach(ScriptUser* user, scriptUsers) { - // FIXME - I sometimes get a crash deep below here inside of Qt while evaluating the script user->scriptContentsAvailable(url, _scriptCache[url]); } } else { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 9f061a5cdb..e401398d24 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -261,20 +261,6 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents, const QStrin return true; } -void ScriptEngine::callScriptMethod(QString methodName, QScriptValue script, QScriptValueList args) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, - "callScriptMethod", - Q_ARG(QString, methodName), - Q_ARG(QScriptValue, script), - Q_ARG(QScriptValueList, args)); - return; - } - - //qDebug() << "About to call " << methodName << "() current thread : " << QThread::currentThread() << "engine thread : " << thread(); - script.property(methodName).call(script, args); -} - void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) { if (_isRunning) { return; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 2bfcecc99e..b9156c718e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -65,8 +65,6 @@ public: int numArguments = -1); Q_INVOKABLE void setIsAvatar(bool isAvatar); - Q_INVOKABLE void callScriptMethod(QString methodName, QScriptValue script, QScriptValueList args); - bool isAvatar() const { return _isAvatar; } void setAvatarData(AvatarData* avatarData, const QString& objectName); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index d110635f92..b2389f4db6 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -26,8 +26,7 @@ static int quatMetaTypeId = qRegisterMetaType(); static int xColorMetaTypeId = qRegisterMetaType(); static int pickRayMetaTypeId = qRegisterMetaType(); static int collisionMetaTypeId = qRegisterMetaType(); -static int qMapURLStringMetaTypeId = qRegisterMetaType>(); -static int qScriptValueListMetaTypeId = qRegisterMetaType("QScriptValueList"); +static int qMapURLStringMetaTypeId = qRegisterMetaType>(); void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); From 0a46db60acc5cbc1936e4e56ce6ce39527e8d2a7 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 11 Sep 2015 12:01:01 -0700 Subject: [PATCH 17/17] spawning particles on grab and deleting on release, with a lifetime, for better cleanup of particles --- examples/controllers/handControllerGrab.js | 2 +- examples/entityScripts/sprayPaintCan.js | 85 +++++++++++----------- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 523cb4eff9..7d4380d764 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -144,7 +144,7 @@ controller.prototype.checkPointer = function() { Script.setTimeout(function() { var props = Entities.getEntityProperties(self.pointer); Entities.editEntity(self.pointer, { - lifetime: props.age + EXTRA_TIME + lifetime: props.age + EXTRA_TIME + LIFETIME }); self.checkPointer(); }, POINTER_CHECK_TIME); diff --git a/examples/entityScripts/sprayPaintCan.js b/examples/entityScripts/sprayPaintCan.js index 4af404d275..4407140184 100644 --- a/examples/entityScripts/sprayPaintCan.js +++ b/examples/entityScripts/sprayPaintCan.js @@ -20,13 +20,6 @@ var self = this; - var stopSetting = JSON.stringify({ - running: false - }); - var startSetting = JSON.stringify({ - running: true - }); - var timeSinceLastMoved = 0; var RESET_TIME_THRESHOLD = 5; var DISTANCE_FROM_HOME_THRESHOLD = 0.5; @@ -59,17 +52,17 @@ self.reset(); timeSinceLastMoved = 0; } - } - else { + } else { timeSinceLastMoved = 0; } if (self.userData.grabKey && self.userData.grabKey.activated === true) { if (self.activated !== true) { + //We were just grabbed, so create a particle system + self.grab(); Entities.editEntity(self.paintStream, { animationSettings: startSetting }); - self.activated = true; } //Move emitter to where entity is always when its activated self.sprayStream(); @@ -81,6 +74,45 @@ } } + this.grab = function() { + self.activated = true; + var animationSettings = JSON.stringify({ + fps: 30, + loop: true, + firstFrame: 1, + lastFrame: 10000, + running: true + }); + + this.paintStream = Entities.addEntity({ + type: "ParticleEffect", + animationSettings: animationSettings, + position: this.properties.position, + textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png", + emitVelocity: ZERO_VEC, + emitAcceleration: ZERO_VEC, + velocitySpread: { + x: .02, + y: .02, + z: 0.02 + }, + emitRate: 100, + particleRadius: 0.01, + color: { + red: 170, + green: 20, + blue: 150 + }, + lifetime: 500, //probably wont be holding longer than this straight + }); + + } + + this.letGo = function() { + self.activated = false; + Entities.deleteEntity(this.paintStream); + } + this.reset = function() { Entities.editEntity(self.entityId, { position: HOME_POSITION, @@ -198,41 +230,8 @@ } setEntityCustomData(GRAB_FRAME_USER_DATA_KEY, this.entityId, data); } - this.initialize(); } - this.initialize = function() { - var animationSettings = JSON.stringify({ - fps: 30, - loop: true, - firstFrame: 1, - lastFrame: 10000, - running: false - }); - - this.paintStream = Entities.addEntity({ - type: "ParticleEffect", - animationSettings: animationSettings, - position: this.properties.position, - textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png", - emitVelocity: ZERO_VEC, - emitAcceleration: ZERO_VEC, - velocitySpread: { - x: .02, - y: .02, - z: 0.02 - }, - emitRate: 100, - particleRadius: 0.01, - color: { - red: 170, - green: 20, - blue: 150 - }, - lifetime: 1000, - }); - - } this.unload = function() { Script.update.disconnect(this.update);