Nebula
Loading...
Searching...
No Matches
occupancyquadtree.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
9//------------------------------------------------------------------------------
10#include "core/types.h"
11#include "math/scalar.h"
12#include "util/fixedarray.h"
14#include "imgui.h"
15
16namespace Terrain
17{
18
20{
21public:
26
28 void Setup(uint worldSize, uint maxSize, uint minSize);
32 bool Deallocate(const Math::uint2 coord, uint size);
34 bool IsOccupied(const Math::uint2 coord, uint size);
36 void Clear();
37
39 void DebugRender(ImDrawList* drawList, ImVec2 offset, float scale);
40
41private:
42 struct Node
43 {
45 : topLeft(nullptr)
46 , topRight(nullptr)
47 , bottomLeft(nullptr)
48 , bottomRight(nullptr)
49 , occupied(false)
51 , size(1)
52 , x(UINT32_MAX)
53 , y(UINT32_MAX)
54 {}
63 };
64
66 bool RecursiveAllocate(Node* node, uint size, Math::uint2& outCoord);
68 bool RecursiveDeallocate(Node* node, Math::uint2 coord, uint size);
70 bool RecursiveSearch(Node* node, Math::uint2 coord, uint size);
71
73 void RecursiveDebugRender(Node* node, ImDrawList* drawList, ImVec2 offset, float scale);
74
78};
79
80//------------------------------------------------------------------------------
83inline
88
89//------------------------------------------------------------------------------
92inline
97
98//------------------------------------------------------------------------------
101inline void
103{
104 this->minSize = minSize;
105 uint numNodes = worldSize / maxSize;
106 this->topLevelNodes.Resize(numNodes);
107 for (uint x = 0; x < numNodes; x++)
108 {
109 this->topLevelNodes[x].Resize(numNodes);
110 for (uint y = 0; y < numNodes; y++)
111 {
112 this->topLevelNodes[x][y].x = x * maxSize;
113 this->topLevelNodes[x][y].y = y * maxSize;
114 this->topLevelNodes[x][y].size = maxSize;
115 this->topLevelNodes[x][y].occupied = false;
116 this->topLevelNodes[x][y].occupancyCounter = 0;
117 this->topLevelNodes[x][y].topLeft = nullptr;
118 this->topLevelNodes[x][y].topRight = nullptr;
119 this->topLevelNodes[x][y].bottomLeft = nullptr;
120 this->topLevelNodes[x][y].bottomRight = nullptr;
121 }
122 }
123}
124
125//------------------------------------------------------------------------------
128inline bool
130{
131 // if the node is not occupied, proceed
132 if (!node->occupied)
133 {
134 // if size matches and no children are used, return
135 if (node->size == size && node->occupancyCounter == 0)
136 {
137 n_assert(node->occupied == false);
138 outCoord = Math::uint2{ node->x, node->y };
139 node->occupied = true;
140 return true;
141 }
142 else if (node->size > size && node->size != this->minSize)
143 {
144 // if the size of the node is bigger than the requested size, visit the children
145 if (node->topLeft == nullptr)
146 {
147 // initialize children, topleft is the origin point
148 const uint halfNodeSize = node->size / 2;
149 node->topLeft = this->allocator.Alloc<Node>();
150 node->topLeft->x = node->x;
151 node->topLeft->y = node->y;
152 node->topLeft->size = halfNodeSize;
153
154 node->topRight = this->allocator.Alloc<Node>();
155 node->topRight->x = node->x + halfNodeSize;
156 node->topRight->y = node->y;
157 node->topRight->size = halfNodeSize;
158
159 node->bottomLeft = this->allocator.Alloc<Node>();
160 node->bottomLeft->x = node->x;
161 node->bottomLeft->y = node->y + halfNodeSize;
162 node->bottomLeft->size = halfNodeSize;
163
164 node->bottomRight = this->allocator.Alloc<Node>();
165 node->bottomRight->x = node->x + halfNodeSize;
166 node->bottomRight->y = node->y + halfNodeSize;
167 node->bottomRight->size = halfNodeSize;
168 }
169
170 if (RecursiveAllocate(node->topLeft, size, outCoord))
171 {
172 node->occupancyCounter++;
173 return true;
174 }
175 if (RecursiveAllocate(node->topRight, size, outCoord))
176 {
177 node->occupancyCounter++;
178 return true;
179 }
180 if (RecursiveAllocate(node->bottomLeft, size, outCoord))
181 {
182 node->occupancyCounter++;
183 return true;
184 }
185 if (RecursiveAllocate(node->bottomRight, size, outCoord))
186 {
187 node->occupancyCounter++;
188 return true;
189 }
190 }
191 }
192
193 return false;
194}
195
196//------------------------------------------------------------------------------
199inline Math::uint2
201{
202 Math::uint2 ret{ UINT32_MAX, UINT32_MAX };
203 for (int x = 0; x < this->topLevelNodes.Size(); x++)
204 {
205 for (int y = 0; y < this->topLevelNodes[x].Size(); y++)
206 {
207 // try to allocate node in this subtree, if failed, just skip to the next top-level node
208 if (RecursiveAllocate(&this->topLevelNodes[x][y], size, ret))
209 return ret;
210 }
211 }
212 return ret;
213}
214
215//------------------------------------------------------------------------------
218inline bool
220{
221 // if node matches size, look for the coordinate
222 if (node->size == size)
223 {
224 if (node->x == coord.x && node->y == coord.y)
225 {
226 node->occupied = false;
227 return true;
228 }
229 }
230 else if (node->size > size)
231 {
232 // if node size is bigger than the requested size, visit children and unset the bits
233 if (node->topLeft == nullptr)
234 return false;
235
236 if (RecursiveDeallocate(node->topLeft, coord, size))
237 {
238 node->occupancyCounter--;
239 return true;
240 }
241 if (RecursiveDeallocate(node->topRight, coord, size))
242 {
243 node->occupancyCounter--;
244 return true;
245 }
246 if (RecursiveDeallocate(node->bottomLeft, coord, size))
247 {
248 node->occupancyCounter--;
249 return true;
250 }
251 if (RecursiveDeallocate(node->bottomRight, coord, size))
252 {
253 node->occupancyCounter--;
254 return true;
255 }
256 }
257
258 return false;
259}
260
261
262//------------------------------------------------------------------------------
265inline bool
267{
268 // find root node where the coord belongs
269 for (int x = 0; x < this->topLevelNodes.Size(); x++)
270 {
271 for (int y = 0; y < this->topLevelNodes[x].Size(); y++)
272 {
273 Node& node = this->topLevelNodes[x][y];
274 if (RecursiveDeallocate(&node, coord, size))
275 return true;
276 }
277 }
278 return false;
279}
280
281//------------------------------------------------------------------------------
284inline bool
286{
287 // if node matches size, look for the coordinate
288 if (node->size == size)
289 {
290 if (node->x == coord.x && node->y == coord.y)
291 {
292 return node->occupied;
293 }
294 }
295 else if (node->size > size)
296 {
297 // if node size is bigger than the requested size, visit children and unset the bits
298 if (node->topLeft == nullptr)
299 return false;
300
301 if (RecursiveDeallocate(node->topLeft, coord, size))
302 {
303 return true;
304 }
305 if (RecursiveDeallocate(node->topRight, coord, size))
306 {
307 return true;
308 }
309 if (RecursiveDeallocate(node->bottomLeft, coord, size))
310 {
311 return true;
312 }
313 if (RecursiveDeallocate(node->bottomRight, coord, size))
314 {
315 return true;
316 }
317 }
318
319 return false;
320}
321
322//------------------------------------------------------------------------------
325inline void
327{
328 this->allocator.Release();
329 for (uint x = 0; x < this->topLevelNodes.Size(); x++)
330 {
331 for (uint y = 0; y < this->topLevelNodes[x].Size(); y++)
332 {
333 this->topLevelNodes[x][y].topLeft = nullptr;
334 this->topLevelNodes[x][y].topRight = nullptr;
335 this->topLevelNodes[x][y].bottomLeft = nullptr;
336 this->topLevelNodes[x][y].bottomRight = nullptr;
337 this->topLevelNodes[x][y].occupied = false;
338 this->topLevelNodes[x][y].occupancyCounter = 0;
339 }
340 }
341}
342
343//------------------------------------------------------------------------------
346inline bool
348{
349 // find root node where the coord belongs
350 for (int x = 0; x < this->topLevelNodes.Size(); x++)
351 {
352 for (int y = 0; y < this->topLevelNodes[x].Size(); y++)
353 {
354 Node& node = this->topLevelNodes[x][y];
355 if (RecursiveSearch(&node, coord, size))
356 return true;
357 }
358 }
359 return false;
360}
361
362static uint colorIndex = 0;
363
364//------------------------------------------------------------------------------
367inline void
368OccupancyQuadTree::RecursiveDebugRender(Node* node, ImDrawList* drawList, ImVec2 offset, float scale)
369{
370 static ImU32 colors[] =
371 {
372 IM_COL32(128, 0, 0, 128),
373 IM_COL32(0, 128, 0, 128),
374 IM_COL32(0, 0, 128, 128),
375 IM_COL32(128, 0, 128, 128),
376 IM_COL32(128, 128, 0, 128),
377 IM_COL32(0, 128, 128, 128),
378 };
379
380 if (node->occupied)
381 {
382 colorIndex = (colorIndex + 1) % 5;
383
384 ImVec2 min{ (float)offset.x + node->x * scale, (float)offset.y + node->y * scale };
385 ImVec2 max{ (float)offset.x + (node->x + node->size) * scale, (float)offset.y + (node->y + node->size) * scale };
386 drawList->AddRectFilled(min, max, colors[colorIndex]);
387 }
388 else if (node->topLeft)
389 {
390 RecursiveDebugRender(node->topLeft, drawList, offset, scale);
391 RecursiveDebugRender(node->topRight, drawList, offset, scale);
392 RecursiveDebugRender(node->bottomLeft, drawList, offset, scale);
393 RecursiveDebugRender(node->bottomRight, drawList, offset, scale);
394 }
395}
396
397//------------------------------------------------------------------------------
400inline void
401OccupancyQuadTree::DebugRender(ImDrawList* drawList, ImVec2 offset, float scale)
402{
403 colorIndex = 0;
404
405 // find root node where the coord belongs
406 for (int x = 0; x < this->topLevelNodes.Size(); x++)
407 {
408 for (int y = 0; y < this->topLevelNodes[x].Size(); y++)
409 {
410 RecursiveDebugRender(&this->topLevelNodes[x][y], drawList, offset, scale);
411 }
412 }
413}
414
415} // namespace Terrain
Allocates memory in chunks.
Definition arenaallocator.h:36
Math::uint2 Allocate(uint size)
allocate a region, return region
Definition occupancyquadtree.h:200
bool RecursiveDeallocate(Node *node, Math::uint2 coord, uint size)
recursively traverse tree and deallocate
Definition occupancyquadtree.h:219
Memory::ArenaAllocator< sizeof(Node) *64 > allocator
Definition occupancyquadtree.h:75
void RecursiveDebugRender(Node *node, ImDrawList *drawList, ImVec2 offset, float scale)
recursively debug render
Definition occupancyquadtree.h:368
uint minSize
Definition occupancyquadtree.h:77
Util::FixedArray< Util::FixedArray< Node > > topLevelNodes
Definition occupancyquadtree.h:76
bool IsOccupied(const Math::uint2 coord, uint size)
check if region is alloced
Definition occupancyquadtree.h:347
void DebugRender(ImDrawList *drawList, ImVec2 offset, float scale)
debug render
Definition occupancyquadtree.h:401
bool RecursiveSearch(Node *node, Math::uint2 coord, uint size)
recursively traverse tree and find if allocated
Definition occupancyquadtree.h:285
void Setup(uint worldSize, uint maxSize, uint minSize)
setup with a world size and a biggest allocation size
Definition occupancyquadtree.h:102
bool RecursiveAllocate(Node *node, uint size, Math::uint2 &outCoord)
recursively traverse tree to allocate node from tree
Definition occupancyquadtree.h:129
~OccupancyQuadTree()
destructor
Definition occupancyquadtree.h:93
OccupancyQuadTree()
constructor
Definition occupancyquadtree.h:84
void Clear()
Clear the tree.
Definition occupancyquadtree.h:326
bool Deallocate(const Math::uint2 coord, uint size)
deallocate region
Definition occupancyquadtree.h:266
Implements a fixed size one-dimensional array.
Definition fixedarray.h:20
#define n_assert(exp)
Definition debug.h:50
The occupancy quad tree implements a tree which allows for a quick search.
Definition occupancyquadtree.h:17
static uint colorIndex
Definition occupancyquadtree.h:362
Nebula's scalar datatype.
scalar x
Definition scalar.h:61
scalar y
Definition scalar.h:61
Definition scalar.h:112
unsigned int x
Definition scalar.h:115
unsigned int y
Definition scalar.h:115
Definition occupancyquadtree.h:43
Node()
Definition occupancyquadtree.h:44
Node * bottomRight
Definition occupancyquadtree.h:58
uint size
Definition occupancyquadtree.h:61
Node * bottomLeft
Definition occupancyquadtree.h:57
Node * topLeft
Definition occupancyquadtree.h:55
uint x
Definition occupancyquadtree.h:62
bool occupied
Definition occupancyquadtree.h:59
uint y
Definition occupancyquadtree.h:62
Node * topRight
Definition occupancyquadtree.h:56
uint occupancyCounter
Definition occupancyquadtree.h:60
unsigned int uint
Definition types.h:33