aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/Octree.h
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/Octree.h')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/Octree.h388
1 files changed, 388 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/Octree.h b/libraries/irrlicht-1.8/source/Irrlicht/Octree.h
new file mode 100644
index 0000000..2bb879d
--- /dev/null
+++ b/libraries/irrlicht-1.8/source/Irrlicht/Octree.h
@@ -0,0 +1,388 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#ifndef __C_OCTREE_H_INCLUDED__
6#define __C_OCTREE_H_INCLUDED__
7
8#include "SViewFrustum.h"
9#include "S3DVertex.h"
10#include "aabbox3d.h"
11#include "irrArray.h"
12#include "CMeshBuffer.h"
13
14/**
15 Flags for Octree
16*/
17//! use meshbuffer for drawing, enables VBO usage
18#define OCTREE_USE_HARDWARE false
19//! use visibility information together with VBOs
20#define OCTREE_USE_VISIBILITY true
21//! use bounding box or frustum for calculate polys
22#define OCTREE_BOX_BASED true
23//! bypass full invisible/visible test
24#define OCTREE_PARENTTEST
25
26namespace irr
27{
28
29//! template octree.
30/** T must be a vertex type which has a member
31called .Pos, which is a core::vertex3df position. */
32template <class T>
33class Octree
34{
35public:
36
37 struct SMeshChunk : public scene::CMeshBuffer<T>
38 {
39 SMeshChunk ()
40 : scene::CMeshBuffer<T>(), MaterialId(0)
41 {
42 scene::CMeshBuffer<T>::grab();
43 }
44
45 virtual ~SMeshChunk ()
46 {
47 //removeAllHardwareBuffers
48 }
49
50 s32 MaterialId;
51 };
52
53 struct SIndexChunk
54 {
55 core::array<u16> Indices;
56 s32 MaterialId;
57 };
58
59 struct SIndexData
60 {
61 u16* Indices;
62 s32 CurrentSize;
63 s32 MaxSize;
64 };
65
66
67 //! Constructor
68 Octree(const core::array<SMeshChunk>& meshes, s32 minimalPolysPerNode=128) :
69 IndexData(0), IndexDataCount(meshes.size()), NodeCount(0)
70 {
71 IndexData = new SIndexData[IndexDataCount];
72
73 // construct array of all indices
74
75 core::array<SIndexChunk>* indexChunks = new core::array<SIndexChunk>;
76 indexChunks->reallocate(meshes.size());
77 for (u32 i=0; i!=meshes.size(); ++i)
78 {
79 IndexData[i].CurrentSize = 0;
80 IndexData[i].MaxSize = meshes[i].Indices.size();
81 IndexData[i].Indices = new u16[IndexData[i].MaxSize];
82
83 indexChunks->push_back(SIndexChunk());
84 SIndexChunk& tic = indexChunks->getLast();
85
86 tic.MaterialId = meshes[i].MaterialId;
87 tic.Indices = meshes[i].Indices;
88 }
89
90 // create tree
91 Root = new OctreeNode(NodeCount, 0, meshes, indexChunks, minimalPolysPerNode);
92 }
93
94 //! returns all ids of polygons partially or fully enclosed
95 //! by this bounding box.
96 void calculatePolys(const core::aabbox3d<f32>& box)
97 {
98 for (u32 i=0; i!=IndexDataCount; ++i)
99 IndexData[i].CurrentSize = 0;
100
101 Root->getPolys(box, IndexData, 0);
102 }
103
104 //! returns all ids of polygons partially or fully enclosed
105 //! by a view frustum.
106 void calculatePolys(const scene::SViewFrustum& frustum)
107 {
108 for (u32 i=0; i!=IndexDataCount; ++i)
109 IndexData[i].CurrentSize = 0;
110
111 Root->getPolys(frustum, IndexData, 0);
112 }
113
114 const SIndexData* getIndexData() const
115 {
116 return IndexData;
117 }
118
119 u32 getIndexDataCount() const
120 {
121 return IndexDataCount;
122 }
123
124 u32 getNodeCount() const
125 {
126 return NodeCount;
127 }
128
129 //! for debug purposes only, collects the bounding boxes of the tree
130 void getBoundingBoxes(const core::aabbox3d<f32>& box,
131 core::array< const core::aabbox3d<f32>* >&outBoxes) const
132 {
133 Root->getBoundingBoxes(box, outBoxes);
134 }
135
136 //! destructor
137 ~Octree()
138 {
139 for (u32 i=0; i<IndexDataCount; ++i)
140 delete [] IndexData[i].Indices;
141
142 delete [] IndexData;
143 delete Root;
144 }
145
146private:
147 // private inner class
148 class OctreeNode
149 {
150 public:
151
152 // constructor
153 OctreeNode(u32& nodeCount, u32 currentdepth,
154 const core::array<SMeshChunk>& allmeshdata,
155 core::array<SIndexChunk>* indices,
156 s32 minimalPolysPerNode) : IndexData(0),
157 Depth(currentdepth+1)
158 {
159 ++nodeCount;
160
161 u32 i; // new ISO for scoping problem with different compilers
162
163 for (i=0; i!=8; ++i)
164 Children[i] = 0;
165
166 if (indices->empty())
167 {
168 delete indices;
169 return;
170 }
171
172 bool found = false;
173
174 // find first point for bounding box
175
176 for (i=0; i<indices->size(); ++i)
177 {
178 if (!(*indices)[i].Indices.empty())
179 {
180 Box.reset(allmeshdata[i].Vertices[(*indices)[i].Indices[0]].Pos);
181 found = true;
182 break;
183 }
184 }
185
186 if (!found)
187 {
188 delete indices;
189 return;
190 }
191
192 s32 totalPrimitives = 0;
193
194 // now lets calculate our bounding box
195 for (i=0; i<indices->size(); ++i)
196 {
197 totalPrimitives += (*indices)[i].Indices.size();
198 for (u32 j=0; j<(*indices)[i].Indices.size(); ++j)
199 Box.addInternalPoint(allmeshdata[i].Vertices[(*indices)[i].Indices[j]].Pos);
200 }
201
202 core::vector3df middle = Box.getCenter();
203 core::vector3df edges[8];
204 Box.getEdges(edges);
205
206 // calculate all children
207 core::aabbox3d<f32> box;
208 core::array<u16> keepIndices;
209
210 if (totalPrimitives > minimalPolysPerNode && !Box.isEmpty())
211 for (u32 ch=0; ch!=8; ++ch)
212 {
213 box.reset(middle);
214 box.addInternalPoint(edges[ch]);
215
216 // create indices for child
217 bool added = false;
218 core::array<SIndexChunk>* cindexChunks = new core::array<SIndexChunk>;
219 cindexChunks->reallocate(allmeshdata.size());
220 for (i=0; i<allmeshdata.size(); ++i)
221 {
222 cindexChunks->push_back(SIndexChunk());
223 SIndexChunk& tic = cindexChunks->getLast();
224 tic.MaterialId = allmeshdata[i].MaterialId;
225
226 for (u32 t=0; t<(*indices)[i].Indices.size(); t+=3)
227 {
228 if (box.isPointInside(allmeshdata[i].Vertices[(*indices)[i].Indices[t]].Pos) &&
229 box.isPointInside(allmeshdata[i].Vertices[(*indices)[i].Indices[t+1]].Pos) &&
230 box.isPointInside(allmeshdata[i].Vertices[(*indices)[i].Indices[t+2]].Pos))
231 {
232 tic.Indices.push_back((*indices)[i].Indices[t]);
233 tic.Indices.push_back((*indices)[i].Indices[t+1]);
234 tic.Indices.push_back((*indices)[i].Indices[t+2]);
235
236 added = true;
237 }
238 else
239 {
240 keepIndices.push_back((*indices)[i].Indices[t]);
241 keepIndices.push_back((*indices)[i].Indices[t+1]);
242 keepIndices.push_back((*indices)[i].Indices[t+2]);
243 }
244 }
245
246 (*indices)[i].Indices.set_used(keepIndices.size());
247 memcpy( (*indices)[i].Indices.pointer(), keepIndices.pointer(), keepIndices.size()*sizeof(u16));
248 keepIndices.set_used(0);
249 }
250
251 if (added)
252 Children[ch] = new OctreeNode(nodeCount, Depth,
253 allmeshdata, cindexChunks, minimalPolysPerNode);
254 else
255 delete cindexChunks;
256
257 } // end for all possible children
258
259 IndexData = indices;
260 }
261
262 // destructor
263 ~OctreeNode()
264 {
265 delete IndexData;
266
267 for (u32 i=0; i<8; ++i)
268 delete Children[i];
269 }
270
271 // returns all ids of polygons partially or full enclosed
272 // by this bounding box.
273 void getPolys(const core::aabbox3d<f32>& box, SIndexData* idxdata, u32 parentTest ) const
274 {
275#if defined (OCTREE_PARENTTEST )
276 // if not full inside
277 if ( parentTest != 2 )
278 {
279 // partially inside ?
280 if (!Box.intersectsWithBox(box))
281 return;
282
283 // fully inside ?
284 parentTest = Box.isFullInside(box)?2:1;
285 }
286#else
287 if (Box.intersectsWithBox(box))
288#endif
289 {
290 const u32 cnt = IndexData->size();
291 u32 i; // new ISO for scoping problem in some compilers
292
293 for (i=0; i<cnt; ++i)
294 {
295 const s32 idxcnt = (*IndexData)[i].Indices.size();
296
297 if (idxcnt)
298 {
299 memcpy(&idxdata[i].Indices[idxdata[i].CurrentSize],
300 &(*IndexData)[i].Indices[0], idxcnt * sizeof(s16));
301 idxdata[i].CurrentSize += idxcnt;
302 }
303 }
304
305 for (i=0; i!=8; ++i)
306 if (Children[i])
307 Children[i]->getPolys(box, idxdata,parentTest);
308 }
309 }
310
311 // returns all ids of polygons partially or full enclosed
312 // by the view frustum.
313 void getPolys(const scene::SViewFrustum& frustum, SIndexData* idxdata,u32 parentTest) const
314 {
315 u32 i; // new ISO for scoping problem in some compilers
316
317 // if parent is fully inside, no further check for the children is needed
318#if defined (OCTREE_PARENTTEST )
319 if ( parentTest != 2 )
320#endif
321 {
322#if defined (OCTREE_PARENTTEST )
323 parentTest = 2;
324#endif
325 for (i=0; i!=scene::SViewFrustum::VF_PLANE_COUNT; ++i)
326 {
327 core::EIntersectionRelation3D r = Box.classifyPlaneRelation(frustum.planes[i]);
328 if ( r == core::ISREL3D_FRONT )
329 return;
330#if defined (OCTREE_PARENTTEST )
331 if ( r == core::ISREL3D_CLIPPED )
332 parentTest = 1; // must still check children
333#endif
334 }
335 }
336
337
338 const u32 cnt = IndexData->size();
339
340 for (i=0; i!=cnt; ++i)
341 {
342 s32 idxcnt = (*IndexData)[i].Indices.size();
343
344 if (idxcnt)
345 {
346 memcpy(&idxdata[i].Indices[idxdata[i].CurrentSize],
347 &(*IndexData)[i].Indices[0], idxcnt * sizeof(s16));
348 idxdata[i].CurrentSize += idxcnt;
349 }
350 }
351
352 for (i=0; i!=8; ++i)
353 if (Children[i])
354 Children[i]->getPolys(frustum, idxdata,parentTest);
355 }
356
357 //! for debug purposes only, collects the bounding boxes of the node
358 void getBoundingBoxes(const core::aabbox3d<f32>& box,
359 core::array< const core::aabbox3d<f32>* >&outBoxes) const
360 {
361 if (Box.intersectsWithBox(box))
362 {
363 outBoxes.push_back(&Box);
364
365 for (u32 i=0; i!=8; ++i)
366 if (Children[i])
367 Children[i]->getBoundingBoxes(box, outBoxes);
368 }
369 }
370
371 private:
372
373 core::aabbox3df Box;
374 core::array<SIndexChunk>* IndexData;
375 OctreeNode* Children[8];
376 u32 Depth;
377 };
378
379 OctreeNode* Root;
380 SIndexData* IndexData;
381 u32 IndexDataCount;
382 u32 NodeCount;
383};
384
385} // end namespace
386
387#endif
388