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