Files
CDAG/Research/scene/Octree/Node.cpp

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;
}