Quellcode durchsuchen

Added aabb_tree.h to the main branch.

undefined
Benjamin ‘Touky’ Huet Sam Hocevar <sam@hocevar.net> vor 10 Jahren
Ursprung
Commit
04dff54084
4 geänderte Dateien mit 366 neuen und 2 gelöschten Zeilen
  1. +359
    -0
      src/lol/algorithm/aabb_tree.h
  2. +1
    -0
      src/lol/algorithm/all.h
  3. +2
    -1
      src/lolcore.vcxproj
  4. +4
    -1
      src/lolcore.vcxproj.filters

+ 359
- 0
src/lol/algorithm/aabb_tree.h Datei anzeigen

@@ -0,0 +1,359 @@
//
// Lol Engine
//
// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
// (c) 2013-2014 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

#if !defined __LOL_SPACE_PARTITIONING_H__
#define __LOL_SPACE_PARTITIONING_H__

#include <lol/base/array.h>

namespace lol
{

//------ AABB TREE SYSTEM -----
template <typename TE, typename TV, typename TB, size_t child_nb>
class AABBTree
{
struct NodeLeaf
{
int m_parent;
//Children pos in the list
int m_children[child_nb];
//Element list
Array<int> m_elements;

NodeLeaf(int parent)
{
m_parent = parent;
for (int i = 0; i < child_nb; i++)
m_children[i] = 0;
}
};

struct TreeElement
{
TE* m_element;
Array<int> m_leaves;

inline bool operator==(const TE*& element) { return m_element == element; }
};

public:
AABBTree()
{
m_max_depth = 1;
m_max_element = 1;
AddLeaf(0);
}
~AABBTree()
{
}

private:
//--
bool CleanupEmptyLeaves(int leaf=0)
{
int empty_children = 0;
for (int i = 0; i < child_nb; i++)
{
bool child_empty = false;
if (m_tree[leaf].m_children[i] != 0)
child_empty = CleanupEmptyLeaves(m_tree[leaf].m_children[i]);
empty_children += (int)(m_tree[leaf].m_children[i] == 0 || child_empty);
}
if (empty_children == 4 && leaf != 0)
{
for (int i = 0; i < child_nb; i++)
{
int old_leaf = m_tree[leaf].m_children[i];
if (old_leaf != 0)
m_free_leaves << old_leaf;
m_tree[leaf].m_children[i] = 0;
}
return true;
}
return false;
}
//--
void RemoveElement(TE* element)
{
int idx = INDEX_NONE;
for (int i = 0; i < m_elements.Count(); ++i)
if (m_elements[i].m_element == element)
idx = i;

if (idx == INDEX_NONE)
return;

//Remove item from tree leaves
for (int i = 0; i < m_elements[idx].m_leaves.Count(); i++)
m_tree[m_elements[idx].m_leaves[i]].m_elements.RemoveItem(idx);

//Try leaves cleanup
CleanupEmptyLeaves();
}
//--
int AddElement(TE* element)
{
for (int i = 0; i < m_elements.Count(); ++i)
if (m_elements[i].m_element == element)
return i;

TreeElement new_element;
new_element.m_element = element;
new_element.m_leaves = Array<int>();
m_elements << new_element;
return m_elements.Count() - 1;
}
//--
int AddLeaf(int parent)
{
int idx = m_tree.Count();
if (m_free_leaves.Count())
{
idx = m_free_leaves.Pop();
m_tree[idx] = NodeLeaf(parent);
}
else
m_tree << NodeLeaf(parent);
return idx;
}

//--
virtual TV GetSubOffset(int sub) = 0;
virtual TB GetAABB() { return TB(-m_size * .5f, m_size * .5f); }
virtual TB GetSubAABB(const TB& bbox, int sub)
{
TV v(GetSubOffset(sub));
TV half_vec = (bbox.B - bbox.A) * .5f;
return TB(bbox.A + half_vec * v,
bbox.A + half_vec * (v + TV::one));
}
//--
bool TestLeaf(int leaf, const TB& leaf_bb, const TB& test_bb, Array<TE*>& elements)
{
bool result = false;
if (TestAABBVsAABB(leaf_bb, test_bb))
{
NodeLeaf& node = m_tree[leaf];
for (int i = 0; i < child_nb; i++)
{
if (node.m_children[i] != 0)
{
TB sub_aabb = GetSubAABB(leaf_bb, i);
result = result | TestLeaf(node.m_children[i], sub_aabb, test_bb, elements);
}
else
{
for (int j = 0; j < node.m_elements.Count(); j++)
elements.PushUnique(m_elements[node.m_elements[j]].m_element);
result = true;
}
}
}
return result;
}
//--
bool RegisterElement(TE* element, int leaf, TB leaf_bb, int depth)
{
if (TestAABBVsAABB(leaf_bb, element->GetAABB()))
{
bool found_child = false;
for (int i = 0; i < child_nb; i++)
{
TB child_bb = GetSubAABB(leaf_bb, i);
int child_leaf = m_tree[leaf].m_children[i];
//there is a child, go further down
if (child_leaf != 0)
found_child = found_child | RegisterElement(element, child_leaf, child_bb, depth + 1);
}
if (found_child)
return true;

//Too much elements, we need to re-dispatch the elements
if (m_tree[leaf].m_elements.Count() + 1 > m_max_element &&
depth < m_max_depth)
{
//Extract elements
Array<int> elements = m_tree[leaf].m_elements;
elements.PushUnique(AddElement(element));
m_tree[leaf].m_elements.Empty();
//Add children
for (int j = 0; j < child_nb; j++)
m_tree[leaf].m_children[j] = AddLeaf(leaf);
//Re-run extracted elements
while (elements.Count())
{
RegisterElement(m_elements[elements[0]].m_element, leaf, leaf_bb, depth);
elements.Remove(0);
}
}
//else add to list.
else
{
int idx = AddElement(element);
m_elements[idx].m_leaves.PushUnique(leaf);
m_tree[leaf].m_elements.PushUnique(idx);
}
return true;
}
return false;
}

public:
void RegisterElement(TE* element) { RegisterElement(element, 0, GetAABB(), 0); }
void UnregisterElement(TE* element) { RemoveElement(element); }
bool FindElements(const TB& bbox, Array<TE*>& elements) { return TestLeaf(0, GetAABB(), bbox, elements); }
void Clear()
{
m_tree.Empty();
m_elements.Empty();
}

void SetSize(TV size) { m_size = size; }
void SetMaxDepth(int max_depth) { m_max_depth = max_depth; }

#if LOL_BUILD_DEBUG
//DEBUG DRAW
virtual void DebugDraw(vec4 color)
{
Array<int, TB> leaves;
Array<TB, vec4> boxes;
Array<TE*, int, vec4> elements;
boxes.Push(GetAABB(), vec4::one);
leaves.Push(0, boxes.Last().m1);
while (leaves.Count() > 0)
{
for (int j = 0; j < m_tree[leaves[0].m1].m_elements.Count(); j++)
{
bool done = false;
for (int k = 0; k < elements.Count(); k++)
{
if (elements[k].m1 == m_elements[m_tree[leaves[0].m1].m_elements[j]].m_element)
{
elements[k].m2++;
done = true;
break;
}
}
if (!done)
elements.Push(m_elements[m_tree[leaves[0].m1].m_elements[j]].m_element, 1, vec4::v1001);
}

for (int i = 0; i < child_nb; i++)
{
if (m_tree[leaves[0].m1].m_children[i] != 0)
{
TB bbox = GetSubAABB(leaves[0].m2, i);
leaves.Push(m_tree[leaves[0].m1].m_children[i], bbox);
boxes.Push(bbox, color);
}
}
leaves.Remove(0);
}
DebugDrawBoxes(boxes, elements);
}
protected:
//DEBUG DRAW
virtual void DebugDrawBoxes(Array<TB, vec4> boxes, Array<TE*, int, vec4> elements) = 0;
#endif //LOL_BUILD_DEBUG

protected:
Array<NodeLeaf> m_tree; //actual tree
Array<TreeElement> m_elements; //elements to leaves
Array<int> m_free_leaves; //leaves removed from tree
TV m_size; //Main tree size
int m_max_depth; //Maximum depth possible
int m_max_element; //Maximum element per leaf
};

template <typename TE>
class QuadTree : public AABBTree<TE, vec2, box2, 4>
{
public:
QuadTree()
{
#if LOL_BUILD_DEBUG
m_debug_y_offset = 0;
#endif //LOL_BUILD_DEBUG
}
#if LOL_BUILD_DEBUG
public:
float m_debug_y_offset;
protected:
virtual void DebugDrawBoxes(Array<box2, vec4> boxes, Array<TE*, int, vec4> elements)
{
vec3 off = vec3::v010 * .1f;
vec3 add = vec3::v010 * .1f;
while (boxes.Count() > 0)
{
Debug::DrawBox(vec3(boxes[0].m1.A.x, m_debug_y_offset, boxes[0].m1.A.y),
vec3(boxes[0].m1.B.x, m_debug_y_offset, boxes[0].m1.B.y),
boxes[0].m2);
boxes.Remove(0);
}
while (elements.Count() > 0)
{
while (elements[0].m2 > 0)
{
Debug::DrawBox(vec3(elements[0].m1->GetAABB().A.x, m_debug_y_offset, elements[0].m1->GetAABB().A.y) + off * (float)elements[0].m2,
vec3(elements[0].m1->GetAABB().B.x, m_debug_y_offset, elements[0].m1->GetAABB().B.y) + off * (float)elements[0].m2,
elements[0].m3);
elements[0].m2--;
}
elements.Remove(0);
}
}
#endif //LOL_BUILD_DEBUG
protected:
virtual vec2 GetSubOffset(int sub) { return vec2(ivec2(sub % 2, sub / 2)); }
};

template <typename TE>
class OcTree : public AABBTree<TE, vec3, box3, 8>
{
public:
virtual ~OcTree() {}

protected:
#if LOL_BUILD_DEBUG
virtual void DebugDrawBoxes(Array<box3, vec4> boxes, Array<TE*, int, vec4> elements)
{
vec3 off = vec3::v010 * .1f;
vec3 add = vec3::v010 * .1f;
while (boxes.Count() > 0)
{
float size = boxes[0].m1.B.x - boxes[0].m1.A.x;
Debug::DrawBox(vec3(boxes[0].m1.A.x, boxes[0].m1.A.y, boxes[0].m1.A.z) /* + off * (m_size.x / size) */,
vec3(boxes[0].m1.B.x, boxes[0].m1.B.y, boxes[0].m1.B.z) /* + off * (m_size.x / size) */,
boxes[0].m2);
//off += add;
boxes.Remove(0);
}
while (elements.Count() > 0)
{
while (elements[0].m2 > 0)
{
Debug::DrawBox(vec3(elements[0].m1->GetAABB().A.x, elements[0].m1->GetAABB().A.y, elements[0].m1->GetAABB().A.z) + off * (float)elements[0].m2,
vec3(elements[0].m1->GetAABB().B.x, elements[0].m1->GetAABB().B.y, elements[0].m1->GetAABB().B.z) + off * (float)elements[0].m2,
elements[0].m3);
elements[0].m2--;
}
elements.Remove(0);
}
}
#endif //LOL_BUILD_DEBUG
virtual vec3 GetSubOffset(int sub) { return vec3(ivec3(sub % 2, sub / 4, (sub % 4) / 2)); }
};

} /* namespace lol */

#endif // __LOL_SPACE_PARTITIONING_H__


+ 1
- 0
src/lol/algorithm/all.h Datei anzeigen

@@ -12,6 +12,7 @@
#define __LOL_ALGORITHM_ALL_H__

#include <lol/algorithm/sort.h>
#include <lol/algorithm/aabb_tree.h>

#endif // __LOL_ALGORITHM_ALL_H__


+ 2
- 1
src/lolcore.vcxproj Datei anzeigen

@@ -269,6 +269,7 @@
<ClInclude Include="light.h" />
<ClInclude Include="loldebug.h" />
<ClInclude Include="lolgl.h" />
<ClInclude Include="lol\algorithm\aabb_tree.h" />
<ClInclude Include="lol\algorithm\all.h" />
<ClInclude Include="lol\algorithm\sort.h" />
<ClInclude Include="lol\base\all.h" />
@@ -422,4 +423,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="$(SolutionDir)\Lol.Fx.targets" />
</ImportGroup>
</Project>
</Project>

+ 4
- 1
src/lolcore.vcxproj.filters Datei anzeigen

@@ -676,6 +676,9 @@
<ClInclude Include="easymesh\easymeshbuild.h">
<Filter>easymesh</Filter>
</ClInclude>
<ClInclude Include="lol\algorithm\aabb_tree.h">
<Filter>lol\algorithm</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<LolFxCompile Include="gpu\emptymaterial.lolfx">
@@ -733,4 +736,4 @@
</None>
<None Include="Makefile.am" />
</ItemGroup>
</Project>
</Project>

Laden…
Abbrechen
Speichern