aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp636
1 files changed, 636 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp
new file mode 100644
index 0000000..226f6f6
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp
@@ -0,0 +1,636 @@
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#include "COctreeSceneNode.h"
6#include "Octree.h"
7#include "ISceneManager.h"
8#include "IVideoDriver.h"
9#include "ICameraSceneNode.h"
10#include "IMeshCache.h"
11#include "IAnimatedMesh.h"
12#include "IMaterialRenderer.h"
13#include "os.h"
14#include "CShadowVolumeSceneNode.h"
15
16namespace irr
17{
18namespace scene
19{
20
21
22//! constructor
23COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr,
24 s32 id, s32 minimalPolysPerNode)
25 : IMeshSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0),
26 TangentsOctree(0), VertexType((video::E_VERTEX_TYPE)-1),
27 MinimalPolysPerNode(minimalPolysPerNode), Mesh(0), Shadow(0),
28 UseVBOs(OCTREE_USE_HARDWARE), UseVisibilityAndVBOs(OCTREE_USE_VISIBILITY),
29 BoxBased(OCTREE_BOX_BASED)
30{
31#ifdef _DEBUG
32 setDebugName("COctreeSceneNode");
33#endif
34}
35
36
37//! destructor
38COctreeSceneNode::~COctreeSceneNode()
39{
40 if (Shadow)
41 Shadow->drop();
42 deleteTree();
43}
44
45
46void COctreeSceneNode::OnRegisterSceneNode()
47{
48 if (IsVisible)
49 {
50 // because this node supports rendering of mixed mode meshes consisting of
51 // transparent and solid material at the same time, we need to go through all
52 // materials, check of what type they are and register this node for the right
53 // render pass according to that.
54
55 video::IVideoDriver* driver = SceneManager->getVideoDriver();
56
57 PassCount = 0;
58 u32 transparentCount = 0;
59 u32 solidCount = 0;
60
61 // count transparent and solid materials in this scene node
62 for (u32 i=0; i<Materials.size(); ++i)
63 {
64 const video::IMaterialRenderer* const rnd =
65 driver->getMaterialRenderer(Materials[i].MaterialType);
66
67 if (rnd && rnd->isTransparent())
68 ++transparentCount;
69 else
70 ++solidCount;
71
72 if (solidCount && transparentCount)
73 break;
74 }
75
76 // register according to material types counted
77
78 if (solidCount)
79 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
80
81 if (transparentCount)
82 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
83
84 ISceneNode::OnRegisterSceneNode();
85 }
86}
87
88
89//! renders the node.
90void COctreeSceneNode::render()
91{
92 video::IVideoDriver* driver = SceneManager->getVideoDriver();
93
94 if (VertexType == -1 || !driver)
95 return;
96
97 ICameraSceneNode* camera = SceneManager->getActiveCamera();
98 if (!camera)
99 return;
100
101 bool isTransparentPass =
102 SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT;
103 ++PassCount;
104
105 driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
106
107 if (Shadow)
108 Shadow->updateShadowVolumes();
109
110 SViewFrustum frust = *camera->getViewFrustum();
111
112 //transform the frustum to the current absolute transformation
113 if ( !AbsoluteTransformation.isIdentity() )
114 {
115 core::matrix4 invTrans(AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE);
116 frust.transform(invTrans);
117 }
118
119 const core::aabbox3d<float> &box = frust.getBoundingBox();
120
121 switch (VertexType)
122 {
123 case video::EVT_STANDARD:
124 {
125 if (BoxBased)
126 StdOctree->calculatePolys(box);
127 else
128 StdOctree->calculatePolys(frust);
129
130 const Octree<video::S3DVertex>::SIndexData* d = StdOctree->getIndexData();
131
132 for (u32 i=0; i<Materials.size(); ++i)
133 {
134 if ( 0 == d[i].CurrentSize )
135 continue;
136
137 const video::IMaterialRenderer* const rnd = driver->getMaterialRenderer(Materials[i].MaterialType);
138 const bool transparent = (rnd && rnd->isTransparent());
139
140 // only render transparent buffer if this is the transparent render pass
141 // and solid only in solid pass
142 if (transparent == isTransparentPass)
143 {
144 driver->setMaterial(Materials[i]);
145 driver->drawIndexedTriangleList(
146 &StdMeshes[i].Vertices[0], StdMeshes[i].Vertices.size(),
147 d[i].Indices, d[i].CurrentSize / 3);
148 }
149 }
150
151 // for debug purposes only
152 if (DebugDataVisible && !Materials.empty() && PassCount==1)
153 {
154 const core::aabbox3df& box = frust.getBoundingBox();
155 core::array< const core::aabbox3d<f32>* > boxes;
156 video::SMaterial m;
157 m.Lighting = false;
158 driver->setMaterial(m);
159 if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS )
160 {
161 StdOctree->getBoundingBoxes(box, boxes);
162 for (u32 b=0; b!=boxes.size(); ++b)
163 driver->draw3DBox(*boxes[b]);
164 }
165
166 if ( DebugDataVisible & scene::EDS_BBOX )
167 driver->draw3DBox(Box,video::SColor(0,255,0,0));
168 }
169 }
170 break;
171 case video::EVT_2TCOORDS:
172 {
173 if (BoxBased)
174 LightMapOctree->calculatePolys(box);
175 else
176 LightMapOctree->calculatePolys(frust);
177
178 const Octree<video::S3DVertex2TCoords>::SIndexData* d = LightMapOctree->getIndexData();
179
180 for (u32 i=0; i<Materials.size(); ++i)
181 {
182 if ( 0 == d[i].CurrentSize )
183 continue;
184
185 const video::IMaterialRenderer* const rnd = driver->getMaterialRenderer(Materials[i].MaterialType);
186 const bool transparent = (rnd && rnd->isTransparent());
187
188 // only render transparent buffer if this is the transparent render pass
189 // and solid only in solid pass
190 if (transparent == isTransparentPass)
191 {
192 driver->setMaterial(Materials[i]);
193 if (UseVBOs)
194 {
195 if (UseVisibilityAndVBOs)
196 {
197 u16* oldPointer = LightMapMeshes[i].Indices.pointer();
198 const u32 oldSize = LightMapMeshes[i].Indices.size();
199 LightMapMeshes[i].Indices.set_free_when_destroyed(false);
200 LightMapMeshes[i].Indices.set_pointer(d[i].Indices, d[i].CurrentSize, false, false);
201 LightMapMeshes[i].setDirty(scene::EBT_INDEX);
202 driver->drawMeshBuffer ( &LightMapMeshes[i] );
203 LightMapMeshes[i].Indices.set_pointer(oldPointer, oldSize);
204 LightMapMeshes[i].setDirty(scene::EBT_INDEX);
205 }
206 else
207 driver->drawMeshBuffer ( &LightMapMeshes[i] );
208 }
209 else
210 driver->drawIndexedTriangleList(
211 &LightMapMeshes[i].Vertices[0],
212 LightMapMeshes[i].Vertices.size(),
213 d[i].Indices, d[i].CurrentSize / 3);
214 }
215 }
216
217 // for debug purposes only
218 if (DebugDataVisible && !Materials.empty() && PassCount==1)
219 {
220 const core::aabbox3d<float> &box = frust.getBoundingBox();
221 core::array< const core::aabbox3d<f32>* > boxes;
222 video::SMaterial m;
223 m.Lighting = false;
224 driver->setMaterial(m);
225 if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS )
226 {
227 LightMapOctree->getBoundingBoxes(box, boxes);
228 for (u32 b=0; b<boxes.size(); ++b)
229 driver->draw3DBox(*boxes[b]);
230 }
231
232 if ( DebugDataVisible & scene::EDS_BBOX )
233 driver->draw3DBox(Box,video::SColor(0,255,0,0));
234 }
235 }
236 break;
237 case video::EVT_TANGENTS:
238 {
239 if (BoxBased)
240 TangentsOctree->calculatePolys(box);
241 else
242 TangentsOctree->calculatePolys(frust);
243
244 const Octree<video::S3DVertexTangents>::SIndexData* d = TangentsOctree->getIndexData();
245
246 for (u32 i=0; i<Materials.size(); ++i)
247 {
248 if ( 0 == d[i].CurrentSize )
249 continue;
250
251 const video::IMaterialRenderer* const rnd = driver->getMaterialRenderer(Materials[i].MaterialType);
252 const bool transparent = (rnd && rnd->isTransparent());
253
254 // only render transparent buffer if this is the transparent render pass
255 // and solid only in solid pass
256 if (transparent == isTransparentPass)
257 {
258 driver->setMaterial(Materials[i]);
259 driver->drawIndexedTriangleList(
260 &TangentsMeshes[i].Vertices[0], TangentsMeshes[i].Vertices.size(),
261 d[i].Indices, d[i].CurrentSize / 3);
262 }
263 }
264
265 // for debug purposes only
266 if (DebugDataVisible && !Materials.empty() && PassCount==1)
267 {
268 const core::aabbox3d<float> &box = frust.getBoundingBox();
269 core::array< const core::aabbox3d<f32>* > boxes;
270 video::SMaterial m;
271 m.Lighting = false;
272 driver->setMaterial(m);
273 if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS )
274 {
275 TangentsOctree->getBoundingBoxes(box, boxes);
276 for (u32 b=0; b<boxes.size(); ++b)
277 driver->draw3DBox(*boxes[b]);
278 }
279
280 if ( DebugDataVisible & scene::EDS_BBOX )
281 driver->draw3DBox(Box,video::SColor(0,255,0,0));
282 }
283 }
284 break;
285 }
286}
287
288
289//! Removes a child from this scene node.
290//! Implemented here, to be able to remove the shadow properly, if there is one,
291//! or to remove attached childs.
292bool COctreeSceneNode::removeChild(ISceneNode* child)
293{
294 if (child && Shadow == child)
295 {
296 Shadow->drop();
297 Shadow = 0;
298 }
299
300 return ISceneNode::removeChild(child);
301}
302
303
304//! Creates shadow volume scene node as child of this node
305//! and returns a pointer to it.
306IShadowVolumeSceneNode* COctreeSceneNode::addShadowVolumeSceneNode(
307 const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity)
308{
309 if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER))
310 return 0;
311
312 if (!shadowMesh)
313 shadowMesh = Mesh; // if null is given, use the mesh of node
314
315 if (Shadow)
316 Shadow->drop();
317
318 Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity);
319 return Shadow;
320}
321
322
323//! returns the axis aligned bounding box of this node
324const core::aabbox3d<f32>& COctreeSceneNode::getBoundingBox() const
325{
326 return Box;
327}
328
329
330//! creates the tree
331/* This method has a lot of duplication and overhead. Moreover, the tangents mesh conversion does not really work. I think we need a a proper mesh implementation for octrees, which handle all vertex types internally. Converting all structures to just one vertex type is always problematic.
332Thanks to Auria for fixing major parts of this method. */
333bool COctreeSceneNode::createTree(IMesh* mesh)
334{
335 if (!mesh)
336 return false;
337
338 MeshName = SceneManager->getMeshCache()->getMeshName(mesh);
339
340 mesh->grab();
341 deleteTree();
342
343 Mesh = mesh;
344
345 const u32 beginTime = os::Timer::getRealTime();
346
347 u32 nodeCount = 0;
348 u32 polyCount = 0;
349 u32 i;
350
351 Box = mesh->getBoundingBox();
352
353 if (mesh->getMeshBufferCount())
354 {
355 // check for "larger" buffer types
356 VertexType = video::EVT_STANDARD;
357 u32 meshReserve = 0;
358 for (i=0; i<mesh->getMeshBufferCount(); ++i)
359 {
360 const IMeshBuffer* b = mesh->getMeshBuffer(i);
361 if (b->getVertexCount() && b->getIndexCount())
362 {
363 ++meshReserve;
364 if (b->getVertexType() == video::EVT_2TCOORDS)
365 VertexType = video::EVT_2TCOORDS;
366 else if (b->getVertexType() == video::EVT_TANGENTS)
367 VertexType = video::EVT_TANGENTS;
368 }
369 }
370 Materials.reallocate(Materials.size()+meshReserve);
371
372 switch(VertexType)
373 {
374 case video::EVT_STANDARD:
375 {
376 StdMeshes.reallocate(StdMeshes.size() + meshReserve);
377 for (i=0; i<mesh->getMeshBufferCount(); ++i)
378 {
379 IMeshBuffer* b = mesh->getMeshBuffer(i);
380
381 if (b->getVertexCount() && b->getIndexCount())
382 {
383 Materials.push_back(b->getMaterial());
384
385 StdMeshes.push_back(Octree<video::S3DVertex>::SMeshChunk());
386 Octree<video::S3DVertex>::SMeshChunk &nchunk = StdMeshes.getLast();
387 nchunk.MaterialId = Materials.size() - 1;
388
389 u32 v;
390 nchunk.Vertices.reallocate(b->getVertexCount());
391 switch (b->getVertexType())
392 {
393 case video::EVT_STANDARD:
394 for (v=0; v<b->getVertexCount(); ++v)
395 nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
396 break;
397 case video::EVT_2TCOORDS:
398 for (v=0; v<b->getVertexCount(); ++v)
399 nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
400 break;
401 case video::EVT_TANGENTS:
402 for (v=0; v<b->getVertexCount(); ++v)
403 nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
404 break;
405 }
406
407 polyCount += b->getIndexCount();
408
409 nchunk.Indices.reallocate(b->getIndexCount());
410 for (v=0; v<b->getIndexCount(); ++v)
411 nchunk.Indices.push_back(b->getIndices()[v]);
412 }
413 }
414
415 StdOctree = new Octree<video::S3DVertex>(StdMeshes, MinimalPolysPerNode);
416 nodeCount = StdOctree->getNodeCount();
417 }
418 break;
419 case video::EVT_2TCOORDS:
420 {
421 LightMapMeshes.reallocate(LightMapMeshes.size() + meshReserve);
422
423 for ( i=0; i < mesh->getMeshBufferCount(); ++i)
424 {
425 IMeshBuffer* b = mesh->getMeshBuffer(i);
426
427 if (b->getVertexCount() && b->getIndexCount())
428 {
429 Materials.push_back(b->getMaterial());
430 LightMapMeshes.push_back(Octree<video::S3DVertex2TCoords>::SMeshChunk());
431 Octree<video::S3DVertex2TCoords>::SMeshChunk& nchunk = LightMapMeshes.getLast();
432 nchunk.MaterialId = Materials.size() - 1;
433
434 if (UseVisibilityAndVBOs)
435 {
436 nchunk.setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX);
437 nchunk.setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX);
438 }
439 else
440 nchunk.setHardwareMappingHint(scene::EHM_STATIC);
441
442 u32 v;
443 nchunk.Vertices.reallocate(b->getVertexCount());
444 switch (b->getVertexType())
445 {
446 case video::EVT_STANDARD:
447 for (v=0; v<b->getVertexCount(); ++v)
448 nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]);
449 break;
450 case video::EVT_2TCOORDS:
451 for (v=0; v<b->getVertexCount(); ++v)
452 nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]);
453 break;
454 case video::EVT_TANGENTS:
455 for (v=0; v<b->getVertexCount(); ++v)
456 nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
457 break;
458 }
459
460 polyCount += b->getIndexCount();
461 nchunk.Indices.reallocate(b->getIndexCount());
462 for (v=0; v<b->getIndexCount(); ++v)
463 nchunk.Indices.push_back(b->getIndices()[v]);
464 }
465 }
466
467 LightMapOctree = new Octree<video::S3DVertex2TCoords>(LightMapMeshes, MinimalPolysPerNode);
468 nodeCount = LightMapOctree->getNodeCount();
469 }
470 break;
471 case video::EVT_TANGENTS:
472 {
473 TangentsMeshes.reallocate(TangentsMeshes.size() + meshReserve);
474
475 for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
476 {
477 IMeshBuffer* b = mesh->getMeshBuffer(i);
478
479 if (b->getVertexCount() && b->getIndexCount())
480 {
481 Materials.push_back(b->getMaterial());
482 TangentsMeshes.push_back(Octree<video::S3DVertexTangents>::SMeshChunk());
483 Octree<video::S3DVertexTangents>::SMeshChunk& nchunk = TangentsMeshes.getLast();
484 nchunk.MaterialId = Materials.size() - 1;
485
486 u32 v;
487 nchunk.Vertices.reallocate(b->getVertexCount());
488 switch (b->getVertexType())
489 {
490 case video::EVT_STANDARD:
491 for (v=0; v<b->getVertexCount(); ++v)
492 {
493 const video::S3DVertex& tmpV = ((video::S3DVertex*)b->getVertices())[v];
494 nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords));
495 }
496 break;
497 case video::EVT_2TCOORDS:
498 for (v=0; v<b->getVertexCount(); ++v)
499 {
500 const video::S3DVertex2TCoords& tmpV = ((video::S3DVertex2TCoords*)b->getVertices())[v];
501 nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords));
502 }
503 break;
504 case video::EVT_TANGENTS:
505 for (v=0; v<b->getVertexCount(); ++v)
506 nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]);
507 break;
508 }
509
510 polyCount += b->getIndexCount();
511 nchunk.Indices.reallocate(b->getIndexCount());
512 for (v=0; v<b->getIndexCount(); ++v)
513 nchunk.Indices.push_back(b->getIndices()[v]);
514 }
515 }
516
517 TangentsOctree = new Octree<video::S3DVertexTangents>(TangentsMeshes, MinimalPolysPerNode);
518 nodeCount = TangentsOctree->getNodeCount();
519 }
520 break;
521 }
522 }
523
524 const u32 endTime = os::Timer::getRealTime();
525 c8 tmp[255];
526 sprintf(tmp, "Needed %ums to create Octree SceneNode.(%u nodes, %u polys)",
527 endTime - beginTime, nodeCount, polyCount/3);
528 os::Printer::log(tmp, ELL_INFORMATION);
529
530 return true;
531}
532
533
534//! returns the material based on the zero based index i. To get the amount
535//! of materials used by this scene node, use getMaterialCount().
536//! This function is needed for inserting the node into the scene hirachy on a
537//! optimal position for minimizing renderstate changes, but can also be used
538//! to directly modify the material of a scene node.
539video::SMaterial& COctreeSceneNode::getMaterial(u32 i)
540{
541 if ( i >= Materials.size() )
542 return ISceneNode::getMaterial(i);
543
544 return Materials[i];
545}
546
547
548//! returns amount of materials used by this scene node.
549u32 COctreeSceneNode::getMaterialCount() const
550{
551 return Materials.size();
552}
553
554
555//! Writes attributes of the scene node.
556void COctreeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
557{
558 ISceneNode::serializeAttributes(out, options);
559
560 out->addInt("MinimalPolysPerNode", MinimalPolysPerNode);
561 out->addString("Mesh", MeshName.c_str());
562}
563
564
565//! Reads attributes of the scene node.
566void COctreeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
567{
568 const s32 oldMinimal = MinimalPolysPerNode;
569
570 MinimalPolysPerNode = in->getAttributeAsInt("MinimalPolysPerNode");
571 io::path newMeshStr = in->getAttributeAsString("Mesh");
572
573 IMesh* newMesh = 0;
574
575 if (newMeshStr == "")
576 newMeshStr = MeshName;
577
578 IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str());
579
580 if (newAnimatedMesh)
581 newMesh = newAnimatedMesh->getMesh(0);
582
583 if (newMesh && ((MeshName != newMeshStr) || (MinimalPolysPerNode != oldMinimal)))
584 {
585 // recalculate tree
586 createTree(newMesh);
587 }
588
589 ISceneNode::deserializeAttributes(in, options);
590}
591
592
593void COctreeSceneNode::deleteTree()
594{
595 delete StdOctree;
596 StdOctree = 0;
597 StdMeshes.clear();
598
599 delete LightMapOctree;
600 LightMapOctree = 0;
601 LightMapMeshes.clear();
602
603 delete TangentsOctree;
604 TangentsOctree = 0;
605 TangentsMeshes.clear();
606
607 Materials.clear();
608
609 if(Mesh)
610 Mesh->drop();
611}
612
613void COctreeSceneNode::setMesh(IMesh* mesh)
614{
615 createTree(mesh);
616}
617
618IMesh* COctreeSceneNode::getMesh(void)
619{
620 return Mesh;
621}
622
623void COctreeSceneNode::setReadOnlyMaterials(bool readonly)
624{
625 // Do nothing
626}
627
628bool COctreeSceneNode::isReadOnlyMaterials() const
629{
630 return false;
631}
632
633
634} // end namespace scene
635} // end namespace irr
636