diff options
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/Octree.h')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/Octree.h | 388 |
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 | |||
26 | namespace irr | ||
27 | { | ||
28 | |||
29 | //! template octree. | ||
30 | /** T must be a vertex type which has a member | ||
31 | called .Pos, which is a core::vertex3df position. */ | ||
32 | template <class T> | ||
33 | class Octree | ||
34 | { | ||
35 | public: | ||
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 | |||
146 | private: | ||
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 | |||