234 lines
6.4 KiB
C++
234 lines
6.4 KiB
C++
#pragma warning(disable:4996)
|
|
#include "Node.h"
|
|
|
|
#include <fstream>
|
|
#include <functional>
|
|
//#include "../PropertyLoader.h"
|
|
//#include "../Renderer.h"
|
|
#include "../../core/IntersectTests.h"
|
|
#include "BaseTree.h"
|
|
|
|
//************************************
|
|
// Should only be called on a root node from outside this class
|
|
//************************************
|
|
Node::Node(const BaseTree* tree, unsigned8 level) :
|
|
mLevel(level),
|
|
mChildMask(ChildMask(0)),
|
|
#ifdef USE_DYNAMIC_ARRAY
|
|
mChildren(SmallDynamicArray<unsigned32>()),
|
|
#else
|
|
mChildren(std::vector<unsigned32>()),
|
|
#endif
|
|
mTree(tree != NULL ? tree->GetTreeIndex() : 0)
|
|
{}
|
|
|
|
//Node::Node(const Node& node) :
|
|
// mIndex(node.mIndex),
|
|
// mLevel(node.mLevel),
|
|
// mTree(node.mTree)
|
|
//{
|
|
// SetChildren(node.mChildMask, node.GetChildren());
|
|
//}
|
|
|
|
//Node::Node(Node&& node) :
|
|
// mChildren(std::move(node.mChildren)),
|
|
// mIndex(std::move(node.mIndex)),
|
|
// mChildMask(std::move(node.mChildMask)),
|
|
// mLevel(std::move(node.mLevel)),
|
|
// mTree(std::move(node.mTree))
|
|
//{
|
|
//}
|
|
//
|
|
//Node& Node::operator=(Node&& node)
|
|
//{
|
|
// mChildren = std::move(node.mChildren);
|
|
// mIndex = std::move(node.mIndex);
|
|
// mChildMask = std::move(node.mChildMask);
|
|
// mLevel = std::move(node.mLevel);
|
|
// mTree = std::move(node.mTree);
|
|
//}
|
|
|
|
//************************************
|
|
// Destroys the current node
|
|
//************************************
|
|
Node::~Node() {
|
|
//printf("Help I'm being killed!\n");
|
|
}
|
|
|
|
void Node::Traverse(const std::function<void(const Node*)>& f) const
|
|
{
|
|
f.operator()(this);
|
|
|
|
unsigned8 childCount = GetChildCount();
|
|
for (unsigned8 i = 0; i < childCount; i++)
|
|
BaseTree::Get(mTree)->GetNode(mChildren[i])->Traverse(f);
|
|
}
|
|
|
|
unsigned64 Node::GetOctreeNodeCount(bool (*f)(const Node*)) const
|
|
{
|
|
unsigned8 childCount = GetChildCount();
|
|
unsigned64 nodeCount = f(this) ? 1 : 0;
|
|
for (unsigned i = 0; i < childCount; i++)
|
|
nodeCount += BaseTree::Get(mTree)->GetNode(mChildren[i])->GetOctreeNodeCount(f);
|
|
return nodeCount;
|
|
}
|
|
unsigned64 Node::GetLeafVoxelCount() const
|
|
{
|
|
if (mChildMask.mask == 0 || mLevel == BaseTree::Get(mTree)->GetMaxLevel()) // This is e a leaf node!
|
|
return 1;
|
|
|
|
unsigned long long res = 0;
|
|
unsigned8 childCount = mChildMask.GetSetBefore(8);
|
|
for (unsigned i = 0; i < childCount; i++)
|
|
res += BaseTree::Get(mTree)->GetNode(mChildren[i])->GetLeafVoxelCount();
|
|
return res;
|
|
}
|
|
|
|
Node* Node::AddChild(const ChildIndex index) {
|
|
Node* curChild = GetChild(index);
|
|
if (curChild == NULL) {
|
|
curChild = BaseTree::Get(mTree)->Create(mLevel + 1);
|
|
SetChild(index, curChild);
|
|
}
|
|
return curChild;
|
|
}
|
|
|
|
Node* Node::GetChild(const ChildIndex index) const
|
|
{
|
|
if (!HasChild(index))
|
|
return NULL;
|
|
ChildIndex vIndex = mChildMask.GetSetBefore(index);
|
|
return BaseTree::Get(mTree)->GetNode(mChildren[vIndex]);
|
|
}
|
|
|
|
void Node::SetChild(const ChildIndex index, Node* child)
|
|
{
|
|
SetChildIndex(index, child->GetIndex());
|
|
}
|
|
|
|
void Node::SetChildIndex(const ChildIndex c, const unsigned32 index)
|
|
{
|
|
bool isNew = !HasChild(c);
|
|
unsigned8 oldChildCount = mChildMask.GetSet();
|
|
mChildMask.Set(c, true);
|
|
ChildIndex vIndex = mChildMask.GetSetBefore(c);
|
|
if (isNew)
|
|
{
|
|
#ifdef USE_DYNAMIC_ARRAY
|
|
mChildren.Insert(vIndex, index, oldChildCount);
|
|
#else
|
|
mChildren.insert(mChildren.begin() + vIndex, index);
|
|
#endif
|
|
}
|
|
else
|
|
mChildren[vIndex] = index;
|
|
}
|
|
|
|
void Node::SetChildren(ChildMask mask, const unsigned* children)
|
|
{
|
|
unsigned8 oldChildCount = mChildMask.GetSet();
|
|
unsigned8 newChildCount = mask.GetSet();
|
|
mChildMask = mask;
|
|
#ifdef USE_DYNAMIC_ARRAY
|
|
if (oldChildCount != newChildCount)
|
|
mChildren.Resize(oldChildCount, newChildCount);
|
|
mChildren.SetRange(children, 0, newChildCount);
|
|
#else
|
|
mChildren.resize(newChildCount);
|
|
for (ChildIndex c = 0; c < newChildCount; c++)
|
|
mChildren[c] = children[c];
|
|
#endif
|
|
}
|
|
|
|
void Node::MoveToTree(BaseTree* tree)
|
|
{
|
|
assert(typeid(*(BaseTree::Get(mTree))) == typeid(*tree));
|
|
mTree = tree->GetTreeIndex();
|
|
}
|
|
|
|
|
|
//************************************
|
|
// Adds the given node at the given coordinates: recursively adds parents in top-down fashion
|
|
//************************************
|
|
Node* Node::AddNode(glm::uvec3 coordinates, const unsigned8 level) {
|
|
if (GetLevel() >= level)
|
|
{
|
|
if (coordinates.x != 0 || coordinates.y != 0 || coordinates.z != 0)
|
|
printf("Unexpected root coordinate (%d, %d, %d)\n", coordinates.x, coordinates.y, coordinates.z);
|
|
return this;
|
|
}
|
|
|
|
ChildIndex child = GetChildIndex(coordinates, level);
|
|
unsigned32 mask = BitHelper::GetLSMask<unsigned32>(0, level - GetLevel() - 1);
|
|
coordinates.x &= mask;
|
|
coordinates.y &= mask;
|
|
coordinates.z &= mask;
|
|
return AddChild(child)->AddNode(coordinates, level);
|
|
}
|
|
|
|
bool Node::HasNode(glm::uvec3 coord, const unsigned8 level) const
|
|
{
|
|
// If we reached a node at the wanted level, return true
|
|
if (mLevel >= level) return true;
|
|
|
|
// Get the wanted child
|
|
ChildIndex child = GetChildIndex(coord, level);
|
|
if (HasChild(child))
|
|
{
|
|
unsigned32 mask = BitHelper::GetLSMask<unsigned32>(0, level - this->GetLevel() - 1);
|
|
coord.x &= mask;
|
|
coord.y &= mask;
|
|
coord.z &= mask;
|
|
return GetChild(child)->HasNode(coord, level);
|
|
}
|
|
else return false;
|
|
}
|
|
|
|
ChildIndex Node::GetChildIndex(const glm::uvec3 coord, const unsigned8 level) const
|
|
{
|
|
unsigned range = 1 << (level - this->GetLevel() - 1);
|
|
return (coord.x < range ? 0 : 1)
|
|
+ (coord.y < range ? 0 : 2)
|
|
+ (coord.z < range ? 0 : 4);
|
|
}
|
|
|
|
void Node::WriteProperties(std::ostream& file) {}
|
|
void Node::ReadProperties(std::istream& file) {}
|
|
void Node::CopyProperties(Node* source) {}
|
|
|
|
bool Node::Compare(const Node& node) const
|
|
{
|
|
// Then on childmask
|
|
unsigned8 nodeMask = node.GetChildmask().mask;
|
|
if (mChildMask.mask != nodeMask)
|
|
// This is equal to returning false if the highest significant bit in the other childmask is more significant than the highest significant bit in this childmask
|
|
return mChildMask.mask < nodeMask;
|
|
|
|
// Then on child pointer values
|
|
unsigned8 childCount = mChildMask.GetSet();
|
|
for (unsigned8 i = 0; i < childCount; i++)
|
|
{
|
|
// Cast pointer to unsigned number
|
|
auto aPtr = this->mChildren[i];
|
|
auto bPtr = node.mChildren[i];
|
|
if (aPtr != bPtr) return aPtr < bPtr;
|
|
}
|
|
|
|
// Apparently the nodes are equal
|
|
return false;
|
|
}
|
|
|
|
bool Node::Equals(const Node& node) const
|
|
{
|
|
if (this == &node) // Same address == same node
|
|
return true;
|
|
if (this->GetLevel() != node.GetLevel() || this->GetChildmask().mask != node.GetChildmask().mask)
|
|
return false;
|
|
unsigned8 childCount = mChildMask.GetSet();
|
|
for (unsigned8 i = 0; i < childCount; i++)
|
|
{
|
|
if (this->mChildren[i] != node.mChildren[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
} |