#pragma once #include #include #include #include #include #include #include #include #include #include "BaseTree.h" #include "../../inc/tbb/parallel_sort.h" #include "../../inc/tbb/parallel_for_each.h" #include "../../inc/tbb/concurrent_queue.h" #include "../../core/Defines.h" #include "../../core/CollectionHelper.h" #include "../../core/Serializer.h" #include "../../core/Util/BoolArray.h" #include "../../core/Util/ObjectPool.h" template class Tree : public BaseTree { public: Tree(unsigned8 maxLevel) : BaseTree(), mLeafNode(0), mLeafsAreEqual(true), // Default tree nodes are equal. Override the root for trees that don't have this property mMaxLevel(maxLevel), mNodePool(ObjectPool(/*1000000*/)), mSortedOnLevel(true) { // Create the root Create(0); } ~Tree() override { Clear(); } const Node* GetNode(const unsigned32 index) const override { return mNodePool[index]; } Node* GetNode(const unsigned32 index) override { return mNodePool[index]; } inline const NodeType* GetTypedNode(const unsigned32 index) const { return mNodePool[index]; } inline NodeType* GetTypedNode(const unsigned32 index) { return mNodePool[index]; } inline const NodeType* GetRoot() const { return mNodePool[0]; /*The first node in the nodepool is ALWAYS the root.*/ } inline NodeType* GetRoot() { return mNodePool[0]; } inline unsigned8 GetMaxLevel() const override { return mMaxLevel; } unsigned32 GetNodeCount() const override { return (unsigned32)mNodePool.Size(); } inline bool IsEmpty() const override { return !GetRoot()->HasChildren(); } bool HasLeaf(const glm::uvec3& coord) const { return HasNode(coord, GetMaxLevel()); } NodeType* AddLeafNode(const glm::uvec3& coord) { return AddNode(coord, GetMaxLevel()); } bool HasNode(const glm::uvec3& coord, const unsigned8 level) const { return GetRoot()->HasNode(coord, level); } NodeType* AddNode(const glm::uvec3& coord, const unsigned8 level) { NodeType* root = GetRoot(); return (NodeType*)(root->AddNode(coord, level)); } void Traverse(const std::function& f) const { GetRoot()->Traverse(f); } std::vector GetNodesPerLevel() const override { std::vector nodesPerLevel; nodesPerLevel.resize(GetMaxLevel() + 1, 0); for (unsigned32 i = 0; i < GetNodeCount(); i++) nodesPerLevel[GetTypedNode(i)->GetLevel()]++; return nodesPerLevel; } size_t GetNodesInLevel(const unsigned8 level) const { size_t res = 0; for (unsigned32 i = 0; i < GetNodeCount(); i++) if (GetTypedNode(i)->GetLevel() == level) res++; return res; } virtual std::vector GetOctreeNodesPerLevel() const override { std::vector octreeNodesPerLevel(GetMaxLevel() + 1); std::function nodeCounter = [&octreeNodesPerLevel](const Node* node) -> void { octreeNodesPerLevel[node->GetLevel()]++; }; this->Traverse(nodeCounter); return octreeNodesPerLevel; } virtual unsigned64 GetPointerCount() const override { unsigned64 res = 0; for (unsigned32 i = 0; i < GetNodeCount(); i++) res += GetTypedNode(i)->GetChildCount(); return res; } // Returns a map with for each node who it's parents are (O(N)). To find the parents of a node, use it's index (node->GetIndex()) std::vector>> GetParentMap() const { std::vector>> parentMap(GetNodeCount(), std::vector>()); for (unsigned32 i = 0; i < GetNodeCount(); i++) { NodeType* node = GetTypedNode(i); for (ChildIndex c = 0; c < 8; c++) if (node->HasChild(c)) parentMap[node->GetChildIndex(c)].push_back(std::make_pair(i, c)); } return parentMap; } // Counts the number of parents each node has (e.g. how many pointers there are to each node). For a regular octree, this will be 1, but for a DAG it isn't necessarily. std::vector GetParentCounts() const override { std::vector parentCounts(GetNodeCount(), 0); for (unsigned32 i = 0; i < GetNodeCount(); i++) { const NodeType* node = GetTypedNode(i); unsigned32* children = node->GetChildren(); for (ChildIndex c = 0; c < node->GetChildCount(); c++) parentCounts[children[c]]++; } return parentCounts; } unsigned64 GetLeafVoxelCount() const { std::vector leafCountTable(GetNodeCount(), 1); for (unsigned8 level = GetMaxLevel(); level-- > 0;) { for (unsigned32 i = 0; i < GetNodeCount(); i++) { const NodeType* node = GetTypedNode(i); if (node->GetLevel() == level) { unsigned64 sum = 0; unsigned32* children = node->GetChildren(); for (ChildIndex c = 0; c < node->GetChildCount(); c++) sum += leafCountTable[children[c]]; leafCountTable[i] = sum; } } } return leafCountTable[0]; } bool ReadTree(const char* fileName) override { std::string binFileName = GetOctreeFileName(fileName); std::ifstream treeInFile(binFileName, std::ios::binary); if (treeInFile.good()) { bool succes = Deserialize(treeInFile); // Finished reading treeInFile.close(); return succes; } return false; } bool WriteTree(const char* fileName) override { std::string binFileName = GetOctreeFileName(fileName); std::ofstream treeOutFile(binFileName, std::ios::binary); bool succes = Serialize(treeOutFile); treeOutFile.close(); return succes; } bool VerifyTree(const char* fileName) override { std::string binFileName = GetOctreeFileName(fileName); std::ifstream treeInFile(binFileName, std::ios::binary); if (treeInFile.good()) { // Read the maximum level in the tree unsigned8 maxLevel; Serializer::Deserialize(maxLevel, treeInFile); this->mMaxLevel = maxLevel; // Read the nodes per level std::vector nodesPerLevel(maxLevel + 1); Serializer::Deserialize(&nodesPerLevel[0], mMaxLevel + 1, treeInFile); // Sum the nodes per level to get the total number of nodes size_t nodeCount = std::accumulate(nodesPerLevel.begin(), nodesPerLevel.end(), 0); printf("."); // Read the childmasks for all nodes (needed to know which pointers exist) std::vector childmasks(nodeCount); Serializer::Deserialize(&childmasks[0], nodeCount, treeInFile); printf("."); // Read all pointers unsigned* newChildren = new unsigned[8]; for (ChildMask mask : childmasks) { if (treeInFile.eof()) return false; ChildIndex childCount = mask.GetSet(); Serializer::Deserialize(newChildren, childCount, treeInFile); for (ChildIndex i = 0; i < childCount; i++) { if (newChildren[i] >= nodeCount) { printf("Node index out of bounds: %u", newChildren[i]); delete[] newChildren; return false; } } } delete[] newChildren; printf(".."); // Finished reading treeInFile.close(); return true; } return false; } bool Serialize(std::ostream& treeOutFile) { auto levelIndices = SortOnLevel(); // Write the total number of levels in the tree unsigned maxLevel = GetMaxLevel(); Serializer::Serialize(maxLevel, treeOutFile); // Write the nodes per level unsigned nodesThisLevel; for (unsigned8 level = 0; level < maxLevel + 1; level++) { nodesThisLevel = (unsigned)(levelIndices[level + 1] - levelIndices[level]); Serializer::Serialize(nodesThisLevel, treeOutFile); } // Gather the child masks for all nodes: std::vector childMasks(GetNodeCount()); tbb::parallel_for((unsigned32)0, GetNodeCount(), [&](unsigned32 i) { childMasks[i] = GetTypedNode(i)->GetChildmask(); }); Serializer::Serialize(&childMasks[0], childMasks.size(), treeOutFile); // Write child pointers of all nodes for (unsigned32 i = 0; i < GetNodeCount(); i++) { NodeType* node = GetTypedNode(i); ChildMask mask = node->GetChildmask(); unsigned32* children = node->GetChildren(); Serializer::Serialize(children, mask.GetSet(), treeOutFile); } // Hack: first write the root properties, then the tree properties, then the rest of the nodes // This is done to be compliant with old files of previous versions GetRoot()->WriteProperties(treeOutFile); WriteProperties(treeOutFile); // Write extra properties per node for (unsigned32 i = 1; i < GetNodeCount(); i++) GetTypedNode(i)->WriteProperties(treeOutFile); return true; } bool Deserialize(std::istream& treeInFile) { this->Clear(); this->InitializeReadTree(); // Read the maximum level in the tree Serializer::Deserialize(mMaxLevel, treeInFile); // Read the nodes per level std::vector nodesPerLevel(mMaxLevel + 1); Serializer::Deserialize(&nodesPerLevel[0], mMaxLevel + 1, treeInFile); // Sum the nodes per level to get the total number of nodes unsigned32 nodeCount = std::accumulate(nodesPerLevel.begin(), nodesPerLevel.end(), 0); printf("."); // Read the childmasks for all nodes (needed to know which pointers exist) std::vector childmasks(nodeCount); Serializer::Deserialize(&childmasks[0], nodeCount, treeInFile); for (unsigned8 level = 0; level <= mMaxLevel; level++) for (unsigned i = 0; i < nodesPerLevel[level]; i++) // Create the node. Creating them in order also adds them to the node pool in order. Create(level); printf("."); // Read all pointers unsigned* newChildren = new unsigned[8]; for (unsigned32 i = 0; i < nodeCount; i++) { ChildMask mask = childmasks[i]; Serializer::Deserialize(newChildren, mask.GetSet(), treeInFile); GetTypedNode(i)->SetChildren(mask, newChildren); } delete[] newChildren; printf("."); GetRoot()->ReadProperties(treeInFile); ReadProperties(treeInFile); // Read extra properties per node for (unsigned32 i = 1; i < GetNodeCount(); i++) { if (treeInFile.eof()) { printf("Something is wrong..."); return false; } GetTypedNode(i)->ReadProperties(treeInFile); } printf("."); this->FinalizeReadTree(); return true; } static std::string GetOctreeFileName(const char* fileName) { return std::string(fileName) + ".oct"; } static std::string GetAdditionalPoolFileName(const char* fileName) { return std::string(fileName) + ".additional.pool"; } virtual void ReadProperties(std::istream& file) {} virtual void WriteProperties(std::ostream& file) {} unsigned8 GetAdditionalTreeInfoSize() const override { return 0; } std::vector GetAdditionalTreeInfo(const std::vector& nodePointers) const override { return std::vector(); } unsigned8 GetAdditionalBytesPerNode(unsigned8 level) const override { return 0; } std::vector GetAdditionalNodeBytes(const Node* node) const override { return std::vector(); } bool LastChildHasAdditionalBytes() const override { return true; } unsigned8 GetAdditionalBytesPerPointer(unsigned8 level) const override { return 0; } std::vector GetAdditionalPointerBytes(const Node* node, ChildIndex child) const override { return std::vector(); } // Reads the node pool and stores it in this tree bool ReadAdditionalPool(const char* fileName) override { if (!HasAdditionalPool()) return true; std::string binFileName = GetAdditionalPoolFileName(fileName); std::ifstream additionalPoolInFile(binFileName, std::ios::binary); if (additionalPoolInFile.good()) { // Destroy whole current node pool ReadAdditionalPoolProperties(additionalPoolInFile); additionalPoolInFile.close(); return true; } return false; } // Writes the node pool bool WriteAdditionalPool(const char* fileName) override { if (!HasAdditionalPool()) return true; std::string binFileName = GetAdditionalPoolFileName(fileName); std::ofstream additionalPoolOutFile(binFileName, std::ios::binary); WriteAdditionalPoolProperties(additionalPoolOutFile); additionalPoolOutFile.close(); return true; } virtual bool HasAdditionalPool() const { return false; } // Clears the whole tree, including the root! virtual void Clear() override { mNodePool.Clear(); } // Removed all nodes marked for deletion and updates the indices. void Clean() { unsigned32 oldNodeCount = GetNodeCount(); mNodePool.Clean(); UpdateNodeIndices(oldNodeCount); } NodeType* Create(unsigned8 level) override { // Make sure only one leaf node is created (memory, performance) if (mLeafsAreEqual && level == GetMaxLevel() && mLeafNode != 0) return GetTypedNode(mLeafNode); // Otherwise, create a new node NodeType* res = mNodePool.Create(this, level); mSortedOnLevel = false; res->SetIndex(GetNodeCount() - 1); if (mLeafsAreEqual && level == GetMaxLevel() && mLeafNode == 0) mLeafNode = res->GetIndex(); return res; } void Append(glm::uvec3 coordinates, unsigned8 level, Tree* tree) { // Let some possible inhereting class do preprocessing on the current tree before append AppendPreProcess(coordinates, level, tree); // First create/get the node that acts as the root of the tree to append std::vector equivalents(tree->GetNodeCount()); NodeType* treeRoot = AddNode(coordinates, level); equivalents[0] = treeRoot->GetIndex(); // Make copies of all nodes in tree, and add them to our own nodepool (with the correct level and root) for (unsigned32 i = 1; i < tree->GetNodeCount(); i++) { NodeType* node = tree->GetTypedNode(i); NodeType* copy = this->Create(node->GetLevel() + level); equivalents[i] = copy->GetIndex(); } unsigned32* newChildren = new unsigned32[8]; // Restore all child pointers for (unsigned32 i = 0; i < tree->GetNodeCount(); i++) { NodeType* node = tree->GetTypedNode(i); unsigned32* children = node->GetChildren(); unsigned8 childCount = node->GetChildCount(); for (ChildIndex c = 0; c < childCount; c++) newChildren[c] = equivalents[children[c]]; NodeType* copy = this->GetTypedNode(equivalents[i]); copy->SetChildren(node->GetChildmask(), newChildren); } delete[] newChildren; // Copy properties tbb::parallel_for((unsigned32)0, tree->GetNodeCount(), [&](unsigned i) { NodeType* source = tree->GetTypedNode(i); GetTypedNode(equivalents[i])->CopyProperties(source); }); // Let some possible inhereting class do postprocessing on the added nodes AppendPostProcess(coordinates, level, tree); } // Appends the given tree to this tree. The nodes in the original tree will be moved to this tree. // During the appending, nodes are automatically merged when possible to keep memory usage low. // Note that this DOES NOT call AppendPostProcess, so trees that depend on this cannot be build using this method void AppendAndMerge(glm::uvec3 coordinates, unsigned8 appendLevel, Tree* tree) { // Let some possible inhereting class do preprocessing on the current tree before append AppendPreProcess(coordinates, appendLevel, tree); this->SortNodes(); std::vector levelIndices = this->SortOnLevel(); std::vector appendedTreeLevelIndices = tree->SortOnLevel(); // First create/get the node that acts as the root of the tree to append NodeType* treeRoot = this->AddNode(coordinates, appendLevel); // Contains at the index of the node in the tree that is to be appended, the index of the replacement node in the pool std::vector replacementMap(tree->GetNodeCount(), 0); replacementMap[0] = treeRoot->GetIndex(); for (unsigned8 level = GetMaxLevel(); level > appendLevel; level--) { // Sort all the nodes in the current level of the other tree unsigned32 levelStart = levelIndices[level]; unsigned32 levelEnd = levelIndices[level + 1]; unsigned32 appendedLevelStart = appendedTreeLevelIndices[level - appendLevel]; unsigned32 appendedLevelEnd = appendedTreeLevelIndices[level - appendLevel + 1]; //std::vector existingNodes(levelEnd - levelStart); //for (unsigned32 i = levelStart; i < levelEnd; i++) existingNodes[i - levelStart] = GetTypedNode(i); //tbb::parallel_sort(existingNodes.begin(), existingNodes.end(), NodeComparer()); // Vector of all nodes that need to be appended std::vector toAppend(appendedLevelEnd - appendedLevelStart); for (unsigned32 i = appendedLevelStart; i < appendedLevelEnd; i++) toAppend[i - appendedLevelStart] = i; tbb::parallel_for_each(toAppend.begin(), toAppend.end(), [&](const unsigned32 i) { NodeType* node = tree->GetTypedNode(i); unsigned32* children = node->GetChildren(); ChildIndex childCount = node->GetChildCount(); // Make sure the node looks exactly like how it would look if it was in the current tree: for (ChildIndex c = 0; c < childCount; c++) children[c] = replacementMap[children[c]]; node->SetLevel(level); node->MoveToTree(this); }); // Sort the nodes in the same way the existing nodes are sorted //NodeComparer comparer(); tbb::parallel_sort(toAppend.begin(), toAppend.end(), [&](const unsigned32 i1, const unsigned32 i2) { NodeType* node1 = tree->GetTypedNode(i1); NodeType* node2 = tree->GetTypedNode(i2); return node1->Compare(*node2); }); // Go through the nodes in this order. unsigned32 existingIndex = 0; for (const unsigned32 i : toAppend) { NodeType* node = tree->GetTypedNode(i); // Scan the existing nodes until they are no longer smaller than the current node while (existingIndex < (levelEnd - levelStart) && GetTypedNode(levelStart + existingIndex)->Compare(*node)) existingIndex++; // If the node at that position is equal to the current node, then delete the current node if (existingIndex < (levelEnd - levelStart) && GetTypedNode(levelStart + existingIndex)->Equals(*node)) { replacementMap[node->GetIndex()] = levelStart + existingIndex; tree->Destroy(node); } else // Otherwise, add this node to the pool { // Create a copy of the node node = mNodePool.Add(node); tree->Destroy(node->GetIndex()); unsigned32 newNodeIndex = GetNodeCount() - 1; replacementMap[node->GetIndex()] = newNodeIndex; node->SetIndex(newNodeIndex); mSortedOnLevel = false; } } } // Reconnect the children of the replacement root unsigned8 childCount = tree->GetRoot()->GetChildCount(); unsigned32* children = tree->GetRoot()->GetChildren(); for (ChildIndex c = 0; c < childCount; c++) children[c] = replacementMap[children[c]]; treeRoot->SetChildren(tree->GetRoot()->GetChildmask(), children); tree->Clear(); } // Moves the given tree to the this tree, replacing the contents of the this try by that of the given tree. // Note that all nodes are recreated, because a tree with a different subclass of node may be moved to this one. // This means that all properties of the original tree will be lost! void MoveShallow(BaseTree* tree) { // Update the current tree to be similar to the source tree Clear(); this->mMaxLevel = tree->GetMaxLevel(); // Create copies of the old tree and put them in the new tree, with correct childpointers for (unsigned32 i = 0; i < tree->GetNodeCount(); i++) { Node* original = tree->GetNode(i); NodeType* replacer = mNodePool.Create(this, original->GetLevel()); replacer->SetChildren(original->GetChildmask(), original->GetChildren()); //tree->Destroy(i); } // Clear the original tree tree->Clear(); } // Sorts the nodes on their level, and returns a list of start indices per level std::vector SortOnLevel() override { // Sort nodes on level (ignore the root = first node in pool) if (!mSortedOnLevel) { //mNodePool.Sort(NodeComparer()); mNodePool.Sort(1, GetNodeCount(), [](const NodeType& a, const NodeType& b) { return a.GetLevel() < b.GetLevel(); }); //tbb::parallel_sort(mNodePool.begin() + 1, mNodePool.end(), [](NodeType* a, NodeType* b) { return a->GetLevel() < b->GetLevel(); }); UpdateNodeIndices(GetNodeCount()); mSortedOnLevel = true; } // Find the start indices of all levels in the node pool std::vector levelIndices(GetMaxLevel() + 1); unsigned8 curLevel = 255; for (unsigned32 i = 0; i < GetNodeCount(); i++) { NodeType* node = GetTypedNode(i); if (node->GetLevel() != curLevel) { curLevel = node->GetLevel(); levelIndices[curLevel] = node->GetIndex(); } } // If for some reason, there are no nodes on every level, fill the rest of the level offsets as if there were these nodes... for (unsigned8 level = curLevel + 1; level <= GetMaxLevel(); level++) levelIndices[level] = GetNodeCount(); // Add a dummy value at the end levelIndices.push_back(GetNodeCount()); return levelIndices; } void SortNodes() { std::vector levelIndices = SortOnLevel(); for (unsigned8 level = 1; level <= GetMaxLevel(); level++) this->SortBetween(levelIndices[level], levelIndices[level + 1], NodeComparer()); UpdateNodeIndices(GetNodeCount()); } void ToDAG(unsigned8 fromLevel = 0, bool verbose = true) { if (this->GetNodeCount() == 1) return; // Empty tree = DAG // Sort the nodes on level (for quick access of nodes within a level). // Note that we can't sort on the node comparer just yet, as the nodes will change during the ToDAG process. auto levelIndices = SortOnLevel(); mMaxLevel = (unsigned8)(levelIndices.size() - 2); if (fromLevel > GetMaxLevel()) return; unsigned32 maxOldIndex = GetNodeCount() - 1; // Run through the layers in reverse order and compress them bottom up for (unsigned8 level = GetMaxLevel(); level > fromLevel; --level) { if (verbose) printf("."); // Initialize some variables needed unsigned32 levelStartIndex = levelIndices[level]; unsigned32 levelEndIndex = levelIndices[level + 1]; unsigned32 parentLevelStartIndex = levelIndices[level - 1]; unsigned32 levelNodeCount = levelEndIndex - levelStartIndex; unsigned32 deletedCount = 0; bool fullRead = !mLeafsAreEqual || level != GetMaxLevel(); if (fullRead) { // Sort nodes using the node comparer mNodePool.Sort(levelStartIndex, levelEndIndex, NodeComparer()); if (verbose) printf("."); // Find unique nodes and store which node duplicates which NodeType* cur = NULL; std::vector replacements(levelNodeCount); size_t uniqueNodes = 0; for (unsigned32 i = levelStartIndex; i < levelEndIndex; i++) { NodeType* node = GetTypedNode(i); if (cur == NULL || !node->Equals(*cur)) { uniqueNodes++; cur = node; } replacements[node->GetIndex() - levelStartIndex] = cur->GetIndex(); } if (verbose) printf("."); // Point all parents of nodes to the new replacement node // Note that this is only necessary if some nodes are replaced by others if (uniqueNodes < levelNodeCount) { tbb::parallel_for(parentLevelStartIndex, levelStartIndex, [&](const unsigned32 i) { Node* parent = GetTypedNode(i); unsigned32* children = parent->GetChildren(); unsigned8 childCount = parent->GetChildCount(); for (ChildIndex c = 0; c < childCount; c++) children[c] = replacements[children[c] - levelStartIndex]; }); if (verbose) printf("."); for (unsigned32 i = levelStartIndex; i < levelEndIndex; i++) { unsigned32 nodeIndex = GetTypedNode(i)->GetIndex(); // If the node is not replaced by it's own index, then delete it if (replacements[nodeIndex - levelStartIndex] != nodeIndex) { Destroy(i); deletedCount++; } } } else if (verbose) printf("."); } else { if (verbose) printf("."); // For the leaf nodes (e.g. !fullRead), just add the first leaf node in the DAGNodePool, and replace the rest by it. NodeType* replacer = GetTypedNode(levelStartIndex); if (verbose) printf("."); if (levelNodeCount > 1) { tbb::parallel_for(parentLevelStartIndex, levelStartIndex, [&](const unsigned32 i) { NodeType* parent = GetTypedNode(i); unsigned32* children = parent->GetChildren(); unsigned8 childCount = parent->GetChildCount(); for (ChildIndex c = 0; c < childCount; c++) children[c] = levelStartIndex; }); if (verbose) printf("."); for (unsigned32 i = levelStartIndex + 1; i < levelEndIndex; i++) { Destroy(i); deletedCount++; } } else if (verbose) printf("."); } if (verbose) printf(" Layer %2u compressed, %7u out of %7u nodes left\n", level, levelNodeCount - deletedCount, levelNodeCount); } Clean(); } void ToOctree(unsigned8 fromLevel = 0) { auto levelIndices = SortOnLevel(); BoolArray usedNodes(GetNodeCount(), false); unsigned32 newLevelStart = GetNodeCount(); unsigned32 newLevelEnd = GetNodeCount(); for (auto level = fromLevel; level < GetMaxLevel(); level++) { // Update start and end index of the nodes that were created during the last iteration newLevelStart = newLevelEnd; newLevelEnd = GetNodeCount(); // Find indices of existing nodes for each level unsigned32 levelStart = levelIndices[level]; unsigned32 levelEnd = levelIndices[level + 1]; // Process all nodes for (unsigned32 i = levelStart; i < newLevelEnd; i++) { // Skip nodes of other levels if (i == levelEnd) i = newLevelStart; NodeType* node = GetTypedNode(i); unsigned32* children = node->GetChildren(); unsigned8 childCount = node->GetChildCount(); for (ChildIndex c = 0; c < childCount; c++) { if (!usedNodes[children[c]]) { // If this node wasn't used yet, we can keep the same child. usedNodes.Set(children[c], true); } else { // If this node was used before, we need to create a new one auto oldNode = GetTypedNode(children[c]); auto newNode = Create(level + 1); newNode->SetChildren(oldNode->GetChildmask(), oldNode->GetChildren()); newNode->CopyProperties(oldNode); children[c] = newNode->GetIndex(); } } } } } void ClearOrphans() { BoolArray orphans(GetNodeCount(), true); orphans.Set(0, false); size_t orphansCleared = 0; bool firstPass = true; while (orphans.Any()) { // Assume all nodes (except the root) are orphans orphans.SetRange(1, GetNodeCount(), true); for (unsigned32 i = 0; i < GetNodeCount(); i++) { NodeType* node = GetTypedNode(i); if (node == NULL) // Empty nodes are not orphans orphans.Set(i, false); else { // Roots are not orphans (by definition, they're just roots) if (node->GetLevel() == 0) orphans.Set(i, false); // All the nodes that are children of this node can not be orphans (since this node still lives) for (ChildIndex child = 0; child < node->GetChildCount(); child++) orphans.Set(node->GetChildren()[child], false); } } // Delete nodes that are orphans. Note that this might cause other nodes to be orphaned as well // In other words: if you're Batman's child, and Batman gets killed, then you are an orphan as well ;) for (unsigned32 i = 1; i < GetNodeCount(); i++) if (orphans.Get(i)) { orphansCleared++; Destroy(i); } } printf("%llu orphans have been removed.\n", (unsigned64)orphansCleared); // Clean the nodepool to really remove all orphans Clean(); } // Finds all parent of a node (O(N)). std::vector> FindParents(const NodeType* node) const { tbb::concurrent_queue> parents; unsigned32 childToFind = node->GetIndex(); unsigned8 parentLevel = node->GetLevel() - 1; tbb::parallel_for((unsigned32)0, GetNodeCount(), [&](const unsigned32 i) { NodeType* node = GetTypedNode(i); if (node->GetLevel() == parentLevel) { for (ChildIndex child = 0; child < 8; child++) if (node->HasChild(child) && node->GetChildIndex(child) == childToFind) parents.push(std::pair(node, child)); } }); std::vector> res; for (auto parent = parents.unsafe_begin(); parent != parents.unsafe_end(); parent++) res.push_back(*parent); return res; } // Cuts off all nodes that have a level higher than depth. void Shave(unsigned8 depth) override { if (depth >= GetMaxLevel()) return; auto levelIndices = SortOnLevel(); // Make sure all nodes at level "depth" have no children (since we're gonna shave them off) const unsigned* emptyChildren = new unsigned[0]; tbb::parallel_for(levelIndices[depth], levelIndices[depth + 1], [&](const unsigned32 i) { GetTypedNode(i)->SetChildren(ChildMask(0), emptyChildren); }); delete emptyChildren; // Delete all nodes that have a higher level than depth for (unsigned32 i = levelIndices[depth + 1]; i < GetNodeCount(); i++) Destroy(i); // Resize the node pool so that no reference to the destroyed nodes exist mNodePool.Clean(); mMaxLevel = depth; } virtual void PrintDebugInfo() const { printf("NodeCount: %u\n", GetNodeCount()); unsigned64 leafVoxelCount = GetLeafVoxelCount(); printf("Leaf voxel count: %llu\n", leafVoxelCount); } protected: void Destroy(unsigned32 index) override { mNodePool.Delete(index); } virtual void Destroy(NodeType* node) { // Assert that we are actually deleting the correct node if (node->GetIndex() < GetNodeCount() && GetTypedNode(node->GetIndex()) == node) mNodePool.Delete(node->GetIndex()); else printf("Error: Can't delete, node with ID %u not located at that position", node->GetIndex()); } virtual void InitializeReadTree() {} virtual void FinalizeReadTree() {} virtual void AppendPreProcess(glm::uvec3 coordinates, unsigned8 level, Tree* tree) {} virtual void AppendPostProcess(glm::uvec3 coordinates, unsigned8 level, Tree* tree) {} // Sorts a subset of the nodes, but DOES NOT update the indices! Make sure to call UpdateNodeIndices at some point! template void SortBetween(unsigned32 startIndex, unsigned32 endIndex, const Comparer& comparer = NodeComparer()) { if (startIndex >= endIndex || startIndex >= GetNodeCount()) return; // Nothing to sort mNodePool.Sort(startIndex, endIndex, comparer); // Check if the given range is monotonically increasing, to make sure the ndoes are still sorted on level (if they were before) if (mSortedOnLevel) { unsigned8 wantedLevel = GetTypedNode(startIndex)->GetLevel(); for (unsigned32 i = startIndex; i < endIndex; i++) { unsigned8 level = GetTypedNode(i)->GetLevel(); if (level != wantedLevel) { if (level > wantedLevel) wantedLevel = level; else { mSortedOnLevel = false; break; } } } } } //std::vector GetNodePoolCopy() const //{ // std::vector nodePoolCopy(mNodePool.size()); // std::copy(mNodePool.begin(), mNodePool.end(), nodePoolCopy.begin()); // return nodePoolCopy; //} // Updates the current index value of all nodes to the value prescribed by the current nodepool. // oldMaxIndex is needed to know the size of the map that maps old to new indices. // If oldMaxIndex is not provided or 0, it will be calculated, requiring an additional pass // through the nodes void UpdateNodeIndices(unsigned32 oldMaxIndex = 0) { if (oldMaxIndex == 0) { // oldMaxIndex = max(oldIndices) for (unsigned32 i = 0; i < GetNodeCount(); i++) if (GetTypedNode(i)->GetIndex() > oldMaxIndex) oldMaxIndex = GetTypedNode(i)->GetIndex(); oldMaxIndex++; } // Update the indices in all nodes, store a map of where nodes have been moved std::vector indexMap(oldMaxIndex + 1); tbb::parallel_for((unsigned32)0, GetNodeCount(), [&](const unsigned32 i) { NodeType* node = GetTypedNode(i); if (node != NULL) { indexMap[node->GetIndex()] = i; node->SetIndex(i); } }); // Update the child indices based on the node movement map //tbb::parallel_for((unsigned32)0, GetNodeCount(), [&](const unsigned32 i) for (unsigned32 i = 0; i < GetNodeCount(); i++) { NodeType* node = GetTypedNode(i); if (node != NULL) { const unsigned8 nodeChildCount = node->GetChildCount(); unsigned32* children = node->GetChildren(); for (ChildIndex c = 0; c < nodeChildCount; c++) children[c] = indexMap[children[c]]; } }//); UpdateLocalReferences(indexMap); } virtual void UpdateLocalReferences(const std::vector& indexMap) { if (mLeafsAreEqual) mLeafNode = indexMap[mLeafNode]; } struct NodeComparer { bool operator()(const NodeType& a, const NodeType& b) const { return a.Compare(b); } }; virtual void WriteAdditionalPoolProperties(std::ostream& file) {} virtual void ReadAdditionalPoolProperties(std::istream& file) {} unsigned32 mLeafNode; bool mLeafsAreEqual; unsigned8 mMaxLevel; // size of the texture in which the node pool will be stored private: ObjectPool mNodePool; // the node pool containing all nodes bool mSortedOnLevel; //ObjectPool* mNodeObjectPool; // The Node ObjectPool, used to reuse nodes instead of new and delete all the time };