diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 76fae500dd..1268449ac6 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -54,6 +54,8 @@ void VoxelNode::init(unsigned char * octalCode) { } VoxelNode::~VoxelNode() { + notifyDeleteHooks(); + delete[] _octalCode; // delete all of this node's children @@ -387,3 +389,44 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const { float distance = sqrtf(glm::dot(temp, temp)); return distance; } + +VoxelNodeDeleteHook VoxelNode::_hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; +void* VoxelNode::_hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; +int VoxelNode::_hooksInUse = 0; + +int VoxelNode::addDeleteHook(VoxelNodeDeleteHook hook, void* extraData) { + // If first use, initialize the _hooks array + if (_hooksInUse == 0) { + memset(_hooks, 0, sizeof(_hooks)); + memset(_hooksExtraData, 0, sizeof(_hooksExtraData)); + } + // find first available slot + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (!_hooks[i]) { + _hooks[i] = hook; + _hooksExtraData[i] = extraData; + _hooksInUse++; + return i; + } + } + // if we got here, then we're out of room in our hooks, return error + return VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE; +} + +void VoxelNode::removeDeleteHook(int hookID) { + if (_hooks[hookID]) { + _hooks[hookID] = NULL; + _hooksExtraData[hookID] = NULL; + _hooksInUse--; + } +} + +void VoxelNode::notifyDeleteHooks() { + if (_hooksInUse > 0) { + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (_hooks[i]) { + _hooks[i](this, _hooksExtraData[i]); + } + } + } +} diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 8e3b9cb5db..431592c2f9 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -15,33 +15,19 @@ #include "VoxelConstants.h" class VoxelTree; // forward delclaration +class VoxelNode; // forward delclaration typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; typedef unsigned char rgbColor[3]; +// Callback function, for delete hook +typedef void (*VoxelNodeDeleteHook)(VoxelNode* node, void* extraData); +const int VOXEL_NODE_MAX_DELETE_HOOKS = 100; +const int VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE = -1; + + class VoxelNode { -private: - nodeColor _trueColor; -#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color - nodeColor _currentColor; - bool _falseColored; -#endif - glBufferIndex _glBufferIndex; - bool _isDirty; - uint64_t _lastChanged; - bool _shouldRender; - bool _isStagedForDeletion; - AABox _box; - unsigned char* _octalCode; - VoxelNode* _children[8]; - int _childCount; - float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside - - void calculateAABox(); - - void init(unsigned char * octalCode); - public: VoxelNode(); // root node constructor VoxelNode(unsigned char * octalCode); // regular constructor @@ -118,6 +104,33 @@ public: const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _trueColor; }; #endif + + static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL); + static void removeDeleteHook(int hookID); +private: + void calculateAABox(); + void init(unsigned char * octalCode); + void notifyDeleteHooks(); + + nodeColor _trueColor; +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color + nodeColor _currentColor; + bool _falseColored; +#endif + glBufferIndex _glBufferIndex; + bool _isDirty; + uint64_t _lastChanged; + bool _shouldRender; + bool _isStagedForDeletion; + AABox _box; + unsigned char* _octalCode; + VoxelNode* _children[8]; + int _childCount; + float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside + + static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; + static void* _hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; + static int _hooksInUse; }; #endif /* defined(__hifi__VoxelNode__) */ diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 20a469dec8..4f355116e4 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -9,7 +9,15 @@ #include "VoxelNodeBag.h" #include +VoxelNodeBag::VoxelNodeBag() : + _bagElements(NULL), + _elementsInUse(0), + _sizeOfElementsArray(0) { + _hookID = VoxelNode::addDeleteHook(voxelNodeDeleteHook, (void*)this); +}; + VoxelNodeBag::~VoxelNodeBag() { + VoxelNode::removeDeleteHook(_hookID); deleteAll(); } @@ -118,3 +126,9 @@ void VoxelNodeBag::remove(VoxelNode* node) { } } +void VoxelNodeBag::voxelNodeDeleteHook(VoxelNode* node, void* extraData) { + VoxelNodeBag* theBag = (VoxelNodeBag*)extraData; + theBag->remove(node); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() +} + + diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index ee6e5045d0..27bd4e5b60 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -19,11 +19,7 @@ class VoxelNodeBag { public: - VoxelNodeBag() : - _bagElements(NULL), - _elementsInUse(0), - _sizeOfElementsArray(0) {}; - + VoxelNodeBag(); ~VoxelNodeBag(); void insert(VoxelNode* node); // put a node into the bag @@ -36,11 +32,14 @@ public: void deleteAll(); + static void voxelNodeDeleteHook(VoxelNode* node, void* extraData); + private: VoxelNode** _bagElements; int _elementsInUse; int _sizeOfElementsArray; + int _hookID; }; #endif /* defined(__hifi__VoxelNodeBag__) */ diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6ef9f293ee..91a31a6cd1 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1011,12 +1011,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, // How many bytes have we written so far at this level; int bytesWritten = 0; - // These two cases should not ever happen... but if they do, we don't want to crash. - if (!node || !node->getOctalCode()) { - qDebug("VoxelTree::encodeTreeBitstream() BAD VoxelNode! Bailing!"); - return bytesWritten; - } - // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { return bytesWritten; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 5f5befafa6..f171d9b168 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -384,7 +384,6 @@ void attachVoxelNodeDataToNode(Node* newNode) { } int main(int argc, const char * argv[]) { - pthread_mutex_init(&::treeLock, NULL); qInstallMsgHandler(sharedMessageHandler);