]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSceneManager.cpp
6882a5b36790a273c6ec0c0746882bc8cdd340ca
[irrlicht.git] / source / Irrlicht / CSceneManager.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 "CSceneManager.h"\r
6 #include "IVideoDriver.h"\r
7 #include "IFileSystem.h"\r
8 #include "SAnimatedMesh.h"\r
9 #include "CMeshCache.h"\r
10 #include "IGUIEnvironment.h"\r
11 #include "IMaterialRenderer.h"\r
12 #include "IReadFile.h"\r
13 #include "IWriteFile.h"\r
14 \r
15 #include "os.h"\r
16 \r
17 #include "CSkinnedMesh.h"\r
18 #include "CXMeshFileLoader.h"\r
19 #include "COBJMeshFileLoader.h"\r
20 #include "CB3DMeshFileLoader.h"\r
21 #include "CBillboardSceneNode.h"\r
22 #include "CAnimatedMeshSceneNode.h"\r
23 #include "CCameraSceneNode.h"\r
24 #include "CLightSceneNode.h"\r
25 #include "CMeshSceneNode.h"\r
26 \r
27 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
28 #include "CShadowVolumeSceneNode.h"\r
29 #else\r
30 #include "IShadowVolumeSceneNode.h"\r
31 #endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
32 \r
33 #include "CDummyTransformationSceneNode.h"\r
34 #include "CEmptySceneNode.h"\r
35 \r
36 #include "CSceneCollisionManager.h"\r
37 \r
38 namespace irr\r
39 {\r
40 namespace scene\r
41 {\r
42 \r
43 //! constructor\r
44 CSceneManager::CSceneManager(video::IVideoDriver* driver,\r
45                 gui::ICursorControl* cursorControl, IMeshCache* cache)\r
46 : ISceneNode(0, 0), Driver(driver),\r
47         CursorControl(cursorControl),\r
48         ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), Parameters(0),\r
49         MeshCache(cache), CurrentRenderPass(ESNRP_NONE)\r
50 {\r
51         #ifdef _DEBUG\r
52         ISceneManager::setDebugName("CSceneManager ISceneManager");\r
53         ISceneNode::setDebugName("CSceneManager ISceneNode");\r
54         #endif\r
55 \r
56         // root node's scene manager\r
57         SceneManager = this;\r
58 \r
59         if (Driver)\r
60                 Driver->grab();\r
61 \r
62         if (CursorControl)\r
63                 CursorControl->grab();\r
64 \r
65         // create mesh cache if not there already\r
66         if (!MeshCache)\r
67                 MeshCache = new CMeshCache();\r
68         else\r
69                 MeshCache->grab();\r
70 \r
71         // set scene parameters\r
72         Parameters = new io::CAttributes();\r
73 \r
74         // create collision manager\r
75         CollisionManager = new CSceneCollisionManager(this, Driver);\r
76 \r
77         // add file format loaders. add the least commonly used ones first,\r
78         // as these are checked last\r
79 \r
80         // TODO: now that we have multiple scene managers, these should be\r
81         // shallow copies from the previous manager if there is one.\r
82 \r
83         MeshLoaderList.push_back(new CXMeshFileLoader(this));\r
84         MeshLoaderList.push_back(new COBJMeshFileLoader(this));\r
85         MeshLoaderList.push_back(new CB3DMeshFileLoader(this));\r
86 }\r
87 \r
88 \r
89 //! destructor\r
90 CSceneManager::~CSceneManager()\r
91 {\r
92         clearDeletionList();\r
93 \r
94         //! force to remove hardwareTextures from the driver\r
95         //! because Scenes may hold internally data bounded to sceneNodes\r
96         //! which may be destroyed twice\r
97         if (Driver)\r
98                 Driver->removeAllHardwareBuffers();\r
99 \r
100         if (CursorControl)\r
101                 CursorControl->drop();\r
102 \r
103         if (CollisionManager)\r
104                 CollisionManager->drop();\r
105 \r
106         u32 i;\r
107         for (i=0; i<MeshLoaderList.size(); ++i)\r
108                 MeshLoaderList[i]->drop();\r
109 \r
110         if (ActiveCamera)\r
111                 ActiveCamera->drop();\r
112         ActiveCamera = 0;\r
113 \r
114         if (MeshCache)\r
115                 MeshCache->drop();\r
116 \r
117         if (Parameters)\r
118                 Parameters->drop();\r
119 \r
120         // remove all nodes before dropping the driver\r
121         // as render targets may be destroyed twice\r
122 \r
123         removeAll();\r
124 \r
125         if (Driver)\r
126                 Driver->drop();\r
127 }\r
128 \r
129 \r
130 //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped.\r
131 IAnimatedMesh* CSceneManager::getMesh(io::IReadFile* file)\r
132 {\r
133         if (!file)\r
134                 return 0;\r
135 \r
136         io::path name = file->getFileName();\r
137         IAnimatedMesh* msh = MeshCache->getMeshByName(name);\r
138         if (msh)\r
139                 return msh;\r
140 \r
141         msh = getUncachedMesh(file, name, name);\r
142 \r
143         return msh;\r
144 }\r
145 \r
146 // load and create a mesh which we know already isn't in the cache and put it in there\r
147 IAnimatedMesh* CSceneManager::getUncachedMesh(io::IReadFile* file, const io::path& filename, const io::path& cachename)\r
148 {\r
149         IAnimatedMesh* msh = 0;\r
150 \r
151         // iterate the list in reverse order so user-added loaders can override the built-in ones\r
152         s32 count = MeshLoaderList.size();\r
153         for (s32 i=count-1; i>=0; --i)\r
154         {\r
155                 if (MeshLoaderList[i]->isALoadableFileExtension(filename))\r
156                 {\r
157                         // reset file to avoid side effects of previous calls to createMesh\r
158                         file->seek(0);\r
159                         msh = MeshLoaderList[i]->createMesh(file);\r
160                         if (msh)\r
161                         {\r
162                                 MeshCache->addMesh(cachename, msh);\r
163                                 msh->drop();\r
164                                 break;\r
165                         }\r
166                 }\r
167         }\r
168 \r
169         if (!msh)\r
170                 os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR);\r
171         else\r
172                 os::Printer::log("Loaded mesh", filename, ELL_DEBUG);\r
173 \r
174         return msh;\r
175 }\r
176 \r
177 //! returns the video driver\r
178 video::IVideoDriver* CSceneManager::getVideoDriver()\r
179 {\r
180         return Driver;\r
181 }\r
182 \r
183 \r
184 //! adds a scene node for rendering a static mesh\r
185 //! the returned pointer must not be dropped.\r
186 IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id,\r
187         const core::vector3df& position, const core::vector3df& rotation,\r
188         const core::vector3df& scale, bool alsoAddIfMeshPointerZero)\r
189 {\r
190         if (!alsoAddIfMeshPointerZero && !mesh)\r
191                 return 0;\r
192 \r
193         if (!parent)\r
194                 parent = this;\r
195 \r
196         IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale);\r
197         node->drop();\r
198 \r
199         return node;\r
200 }\r
201 \r
202 \r
203 //! adds a scene node for rendering an animated mesh model\r
204 IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id,\r
205         const core::vector3df& position, const core::vector3df& rotation,\r
206         const core::vector3df& scale, bool alsoAddIfMeshPointerZero)\r
207 {\r
208         if (!alsoAddIfMeshPointerZero && !mesh)\r
209                 return 0;\r
210 \r
211         if (!parent)\r
212                 parent = this;\r
213 \r
214         IAnimatedMeshSceneNode* node =\r
215                 new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale);\r
216         node->drop();\r
217 \r
218         return node;\r
219 }\r
220 \r
221 \r
222 //! Adds a camera scene node to the tree and sets it as active camera.\r
223 //! \param position: Position of the space relative to its parent where the camera will be placed.\r
224 //! \param lookat: Position where the camera will look at. Also known as target.\r
225 //! \param parent: Parent scene node of the camera. Can be null. If the parent moves,\r
226 //! the camera will move too.\r
227 //! \return Returns pointer to interface to camera\r
228 ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent,\r
229         const core::vector3df& position, const core::vector3df& lookat, s32 id,\r
230         bool makeActive)\r
231 {\r
232         if (!parent)\r
233                 parent = this;\r
234 \r
235         ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat);\r
236 \r
237         if (makeActive)\r
238                 setActiveCamera(node);\r
239         node->drop();\r
240 \r
241         return node;\r
242 }\r
243 \r
244 \r
245 //! Adds a dynamic light scene node. The light will cast dynamic light on all\r
246 //! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING\r
247 //! turned on. (This is the default setting in most scene nodes).\r
248 ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent,\r
249         const core::vector3df& position, video::SColorf color, f32 range, s32 id)\r
250 {\r
251         if (!parent)\r
252                 parent = this;\r
253 \r
254         ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range);\r
255         node->drop();\r
256 \r
257         return node;\r
258 }\r
259 \r
260 \r
261 //! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element,\r
262 //! which always looks to the camera. It is usually used for things like explosions, fire,\r
263 //! lensflares and things like that.\r
264 IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent,\r
265         const core::dimension2d<f32>& size, const core::vector3df& position, s32 id,\r
266         video::SColor colorTop, video::SColor colorBottom\r
267         )\r
268 {\r
269         if (!parent)\r
270                 parent = this;\r
271 \r
272         IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size,\r
273                 colorTop, colorBottom);\r
274         node->drop();\r
275 \r
276         return node;\r
277 }\r
278 \r
279 \r
280 //! Adds an empty scene node.\r
281 ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id)\r
282 {\r
283         if (!parent)\r
284                 parent = this;\r
285 \r
286         ISceneNode* node = new CEmptySceneNode(parent, this, id);\r
287         node->drop();\r
288 \r
289         return node;\r
290 }\r
291 \r
292 \r
293 //! Adds a dummy transformation scene node to the scene graph.\r
294 IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode(\r
295         ISceneNode* parent, s32 id)\r
296 {\r
297         if (!parent)\r
298                 parent = this;\r
299 \r
300         IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode(\r
301                 parent, this, id);\r
302         node->drop();\r
303 \r
304         return node;\r
305 }\r
306 \r
307 \r
308 //! Returns the root scene node. This is the scene node which is parent\r
309 //! of all scene nodes. The root scene node is a special scene node which\r
310 //! only exists to manage all scene nodes. It is not rendered and cannot\r
311 //! be removed from the scene.\r
312 //! \return Returns a pointer to the root scene node.\r
313 ISceneNode* CSceneManager::getRootSceneNode()\r
314 {\r
315         return this;\r
316 }\r
317 \r
318 \r
319 //! Returns the current active camera.\r
320 //! \return The active camera is returned. Note that this can be NULL, if there\r
321 //! was no camera created yet.\r
322 ICameraSceneNode* CSceneManager::getActiveCamera() const\r
323 {\r
324         return ActiveCamera;\r
325 }\r
326 \r
327 \r
328 //! Sets the active camera. The previous active camera will be deactivated.\r
329 //! \param camera: The new camera which should be active.\r
330 void CSceneManager::setActiveCamera(ICameraSceneNode* camera)\r
331 {\r
332         if (camera)\r
333                 camera->grab();\r
334         if (ActiveCamera)\r
335                 ActiveCamera->drop();\r
336 \r
337         ActiveCamera = camera;\r
338 }\r
339 \r
340 \r
341 //! renders the node.\r
342 void CSceneManager::render()\r
343 {\r
344 }\r
345 \r
346 \r
347 //! returns the axis aligned bounding box of this node\r
348 const core::aabbox3d<f32>& CSceneManager::getBoundingBox() const\r
349 {\r
350         _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.\r
351 \r
352         static const core::aabbox3d<f32> dummy;\r
353         return dummy;\r
354 }\r
355 \r
356 \r
357 //! returns if node is culled\r
358 bool CSceneManager::isCulled(const ISceneNode* node) const\r
359 {\r
360         const ICameraSceneNode* cam = getActiveCamera();\r
361         if (!cam)\r
362         {\r
363                 return false;\r
364         }\r
365         bool result = false;\r
366 \r
367         // has occlusion query information\r
368         if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY)\r
369         {\r
370                 result = (Driver->getOcclusionQueryResult(const_cast<ISceneNode*>(node))==0);\r
371         }\r
372 \r
373         // can be seen by a bounding box ?\r
374         if (!result && (node->getAutomaticCulling() & scene::EAC_BOX))\r
375         {\r
376                 core::aabbox3d<f32> tbox = node->getBoundingBox();\r
377                 node->getAbsoluteTransformation().transformBoxEx(tbox);\r
378                 result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() ));\r
379         }\r
380 \r
381         // can be seen by a bounding sphere\r
382         if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE))\r
383         {\r
384                 const core::aabbox3df nbox = node->getTransformedBoundingBox();\r
385                 const float rad = nbox.getRadius();\r
386                 const core::vector3df center = nbox.getCenter();\r
387 \r
388                 const float camrad = cam->getViewFrustum()->getBoundingRadius();\r
389                 const core::vector3df camcenter = cam->getViewFrustum()->getBoundingCenter();\r
390 \r
391                 const float dist = (center - camcenter).getLengthSQ();\r
392                 const float maxdist = (rad + camrad) * (rad + camrad);\r
393 \r
394                 result = dist > maxdist;\r
395         }\r
396 \r
397         // can be seen by cam pyramid planes ?\r
398         if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX))\r
399         {\r
400                 SViewFrustum frust = *cam->getViewFrustum();\r
401 \r
402                 //transform the frustum to the node's current absolute transformation\r
403                 core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE);\r
404                 //invTrans.makeInverse();\r
405                 frust.transform(invTrans);\r
406 \r
407                 core::vector3df edges[8];\r
408                 node->getBoundingBox().getEdges(edges);\r
409 \r
410                 for (s32 i=0; i<scene::SViewFrustum::VF_PLANE_COUNT; ++i)\r
411                 {\r
412                         bool boxInFrustum=false;\r
413                         for (u32 j=0; j<8; ++j)\r
414                         {\r
415                                 if (frust.planes[i].classifyPointRelation(edges[j]) != core::ISREL3D_FRONT)\r
416                                 {\r
417                                         boxInFrustum=true;\r
418                                         break;\r
419                                 }\r
420                         }\r
421 \r
422                         if (!boxInFrustum)\r
423                         {\r
424                                 result = true;\r
425                                 break;\r
426                         }\r
427                 }\r
428         }\r
429 \r
430         return result;\r
431 }\r
432 \r
433 \r
434 //! registers a node for rendering it at a specific time.\r
435 u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass)\r
436 {\r
437         u32 taken = 0;\r
438 \r
439         switch(pass)\r
440         {\r
441                 // take camera if it is not already registered\r
442         case ESNRP_CAMERA:\r
443                 {\r
444                         taken = 1;\r
445                         for (u32 i = 0; i != CameraList.size(); ++i)\r
446                         {\r
447                                 if (CameraList[i] == node)\r
448                                 {\r
449                                         taken = 0;\r
450                                         break;\r
451                                 }\r
452                         }\r
453                         if (taken)\r
454                         {\r
455                                 CameraList.push_back(node);\r
456                         }\r
457                 }\r
458                 break;\r
459         case ESNRP_LIGHT:\r
460                 // TODO: Point Light culling..\r
461                 // Lighting model in irrlicht has to be redone..\r
462                 //if (!isCulled(node))\r
463                 {\r
464                         LightList.push_back(node);\r
465                         taken = 1;\r
466                 }\r
467                 break;\r
468         case ESNRP_SKY_BOX:\r
469                 SkyBoxList.push_back(node);\r
470                 taken = 1;\r
471                 break;\r
472         case ESNRP_SOLID:\r
473                 if (!isCulled(node))\r
474                 {\r
475                         SolidNodeList.push_back(node);\r
476                         taken = 1;\r
477                 }\r
478                 break;\r
479         case ESNRP_TRANSPARENT:\r
480                 if (!isCulled(node))\r
481                 {\r
482                         TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos));\r
483                         taken = 1;\r
484                 }\r
485                 break;\r
486         case ESNRP_TRANSPARENT_EFFECT:\r
487                 if (!isCulled(node))\r
488                 {\r
489                         TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos));\r
490                         taken = 1;\r
491                 }\r
492                 break;\r
493         case ESNRP_AUTOMATIC:\r
494                 if (!isCulled(node))\r
495                 {\r
496                         const u32 count = node->getMaterialCount();\r
497 \r
498                         taken = 0;\r
499                         for (u32 i=0; i<count; ++i)\r
500                         {\r
501                                 if (Driver->needsTransparentRenderPass(node->getMaterial(i)))\r
502                                 {\r
503                                         // register as transparent node\r
504                                         TransparentNodeEntry e(node, camWorldPos);\r
505                                         TransparentNodeList.push_back(e);\r
506                                         taken = 1;\r
507                                         break;\r
508                                 }\r
509                         }\r
510 \r
511                         // not transparent, register as solid\r
512                         if (!taken)\r
513                         {\r
514                                 SolidNodeList.push_back(node);\r
515                                 taken = 1;\r
516                         }\r
517                 }\r
518                 break;\r
519         case ESNRP_SHADOW:\r
520                 if (!isCulled(node))\r
521                 {\r
522                         ShadowNodeList.push_back(node);\r
523                         taken = 1;\r
524                 }\r
525                 break;\r
526         case ESNRP_GUI:\r
527                 if (!isCulled(node))\r
528                 {\r
529                         GuiNodeList.push_back(node);\r
530                         taken = 1;\r
531                 }\r
532 \r
533         case ESNRP_NONE: // ignore this one\r
534                 break;\r
535         }\r
536 \r
537         return taken;\r
538 }\r
539 \r
540 void CSceneManager::clearAllRegisteredNodesForRendering()\r
541 {\r
542         CameraList.clear();\r
543         LightList.clear();\r
544         SkyBoxList.clear();\r
545         SolidNodeList.clear();\r
546         TransparentNodeList.clear();\r
547         TransparentEffectNodeList.clear();\r
548         ShadowNodeList.clear();\r
549         GuiNodeList.clear();\r
550 }\r
551 \r
552 //! This method is called just before the rendering process of the whole scene.\r
553 //! draws all scene nodes\r
554 void CSceneManager::drawAll()\r
555 {\r
556         if (!Driver)\r
557                 return;\r
558 \r
559         u32 i; // new ISO for scoping problem in some compilers\r
560 \r
561         // reset all transforms\r
562         Driver->setMaterial(video::SMaterial());\r
563         Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );\r
564         Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );\r
565         Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );\r
566         for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i)\r
567                 Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix );\r
568         // TODO: This should not use an attribute here but a real parameter when necessary (too slow!)\r
569         Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT));\r
570 \r
571         // do animations and other stuff.\r
572         OnAnimate(os::Timer::getTime());\r
573 \r
574         /*!\r
575                 First Scene Node for prerendering should be the active camera\r
576                 consistent Camera is needed for culling\r
577         */\r
578         camWorldPos.set(0,0,0);\r
579         if (ActiveCamera)\r
580         {\r
581                 ActiveCamera->render();\r
582                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
583         }\r
584 \r
585         // let all nodes register themselves\r
586         OnRegisterSceneNode();\r
587 \r
588         //render camera scenes\r
589         {\r
590                 CurrentRenderPass = ESNRP_CAMERA;\r
591                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
592 \r
593                 for (i=0; i<CameraList.size(); ++i)\r
594                         CameraList[i]->render();\r
595 \r
596                 CameraList.set_used(0);\r
597         }\r
598 \r
599         //render lights scenes\r
600         {\r
601                 CurrentRenderPass = ESNRP_LIGHT;\r
602                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
603 \r
604                 core::vector3df camWorldPos(0, 0, 0);\r
605                 if (ActiveCamera)\r
606                         camWorldPos = ActiveCamera->getAbsolutePosition();\r
607 \r
608                 core::array<DistanceNodeEntry> SortedLights;\r
609                 SortedLights.set_used(LightList.size());\r
610                 for (s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
611                         SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos);\r
612 \r
613                 SortedLights.set_sorted(false);\r
614                 SortedLights.sort();\r
615 \r
616                 for(s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
617                         LightList[light] = SortedLights[light].Node;\r
618 \r
619                 Driver->deleteAllDynamicLights();\r
620 \r
621                 Driver->setAmbientLight(AmbientLight);\r
622 \r
623                 u32 maxLights = LightList.size();\r
624 \r
625                 for (i=0; i< maxLights; ++i)\r
626                         LightList[i]->render();\r
627         }\r
628 \r
629         // render skyboxes\r
630         {\r
631                 CurrentRenderPass = ESNRP_SKY_BOX;\r
632                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
633 \r
634                 for (i=0; i<SkyBoxList.size(); ++i)\r
635                         SkyBoxList[i]->render();\r
636 \r
637                 SkyBoxList.set_used(0);\r
638         }\r
639 \r
640         // render default objects\r
641         {\r
642                 CurrentRenderPass = ESNRP_SOLID;\r
643                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
644 \r
645                 SolidNodeList.sort(); // sort by textures\r
646 \r
647                 for (i=0; i<SolidNodeList.size(); ++i)\r
648                         SolidNodeList[i].Node->render();\r
649 \r
650                 SolidNodeList.set_used(0);\r
651         }\r
652 \r
653         // render shadows\r
654         {\r
655                 CurrentRenderPass = ESNRP_SHADOW;\r
656                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
657 \r
658                 for (i=0; i<ShadowNodeList.size(); ++i)\r
659                         ShadowNodeList[i]->render();\r
660 \r
661                 if (!ShadowNodeList.empty())\r
662                         Driver->drawStencilShadow(true,ShadowColor, ShadowColor,\r
663                                 ShadowColor, ShadowColor);\r
664 \r
665                 ShadowNodeList.set_used(0);\r
666         }\r
667 \r
668         // render transparent objects.\r
669         {\r
670                 CurrentRenderPass = ESNRP_TRANSPARENT;\r
671                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
672 \r
673                 TransparentNodeList.sort(); // sort by distance from camera\r
674                 for (i=0; i<TransparentNodeList.size(); ++i)\r
675                         TransparentNodeList[i].Node->render();\r
676 \r
677                 TransparentNodeList.set_used(0);\r
678         }\r
679 \r
680         // render transparent effect objects.\r
681         {\r
682                 CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT;\r
683                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
684 \r
685                 TransparentEffectNodeList.sort(); // sort by distance from camera\r
686 \r
687                 for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
688                         TransparentEffectNodeList[i].Node->render();\r
689 \r
690                 TransparentEffectNodeList.set_used(0);\r
691         }\r
692 \r
693         // render custom gui nodes\r
694         {\r
695                 CurrentRenderPass = ESNRP_GUI;\r
696                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
697 \r
698                 for (i=0; i<GuiNodeList.size(); ++i)\r
699                         GuiNodeList[i]->render();\r
700 \r
701                 GuiNodeList.set_used(0);\r
702         }\r
703 \r
704         LightList.set_used(0);\r
705         clearDeletionList();\r
706 \r
707         CurrentRenderPass = ESNRP_NONE;\r
708 }\r
709 \r
710 \r
711 //! Sets the color of stencil buffers shadows drawn by the scene manager.\r
712 void CSceneManager::setShadowColor(video::SColor color)\r
713 {\r
714         ShadowColor = color;\r
715 }\r
716 \r
717 \r
718 //! Returns the current color of shadows.\r
719 video::SColor CSceneManager::getShadowColor() const\r
720 {\r
721         return ShadowColor;\r
722 }\r
723 \r
724 IShadowVolumeSceneNode* CSceneManager::createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity)\r
725 {\r
726 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
727         return new CShadowVolumeSceneNode(shadowMesh, parent, this, id, zfailmethod, infinity);\r
728 #else\r
729         return 0;\r
730 #endif\r
731 }\r
732 \r
733 \r
734 \r
735 //! Adds an external mesh loader.\r
736 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)\r
737 {\r
738         if (!externalLoader)\r
739                 return;\r
740 \r
741         externalLoader->grab();\r
742         MeshLoaderList.push_back(externalLoader);\r
743 }\r
744 \r
745 \r
746 //! Returns the number of mesh loaders supported by Irrlicht at this time\r
747 u32 CSceneManager::getMeshLoaderCount() const\r
748 {\r
749         return MeshLoaderList.size();\r
750 }\r
751 \r
752 \r
753 //! Retrieve the given mesh loader\r
754 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const\r
755 {\r
756         if (index < MeshLoaderList.size())\r
757                 return MeshLoaderList[index];\r
758         else\r
759                 return 0;\r
760 }\r
761 \r
762 \r
763 //! Returns a pointer to the scene collision manager.\r
764 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()\r
765 {\r
766         return CollisionManager;\r
767 }\r
768 \r
769 \r
770 //! Returns a pointer to the mesh manipulator.\r
771 IMeshManipulator* CSceneManager::getMeshManipulator()\r
772 {\r
773         return Driver->getMeshManipulator();\r
774 }\r
775 \r
776 \r
777 //! Adds a scene node to the deletion queue.\r
778 void CSceneManager::addToDeletionQueue(ISceneNode* node)\r
779 {\r
780         if (!node)\r
781                 return;\r
782 \r
783         node->grab();\r
784         DeletionList.push_back(node);\r
785 }\r
786 \r
787 \r
788 //! clears the deletion list\r
789 void CSceneManager::clearDeletionList()\r
790 {\r
791         if (DeletionList.empty())\r
792                 return;\r
793 \r
794         for (u32 i=0; i<DeletionList.size(); ++i)\r
795         {\r
796                 DeletionList[i]->remove();\r
797                 DeletionList[i]->drop();\r
798         }\r
799 \r
800         DeletionList.clear();\r
801 }\r
802 \r
803 \r
804 //! Returns the first scene node with the specified name.\r
805 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)\r
806 {\r
807         if (start == 0)\r
808                 start = getRootSceneNode();\r
809 \r
810         if (!strcmp(start->getName(),name))\r
811                 return start;\r
812 \r
813         ISceneNode* node = 0;\r
814 \r
815         const ISceneNodeList& list = start->getChildren();\r
816         ISceneNodeList::const_iterator it = list.begin();\r
817         for (; it!=list.end(); ++it)\r
818         {\r
819                 node = getSceneNodeFromName(name, *it);\r
820                 if (node)\r
821                         return node;\r
822         }\r
823 \r
824         return 0;\r
825 }\r
826 \r
827 \r
828 //! Returns the first scene node with the specified id.\r
829 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)\r
830 {\r
831         if (start == 0)\r
832                 start = getRootSceneNode();\r
833 \r
834         if (start->getID() == id)\r
835                 return start;\r
836 \r
837         ISceneNode* node = 0;\r
838 \r
839         const ISceneNodeList& list = start->getChildren();\r
840         ISceneNodeList::const_iterator it = list.begin();\r
841         for (; it!=list.end(); ++it)\r
842         {\r
843                 node = getSceneNodeFromId(id, *it);\r
844                 if (node)\r
845                         return node;\r
846         }\r
847 \r
848         return 0;\r
849 }\r
850 \r
851 \r
852 //! Returns the first scene node with the specified type.\r
853 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)\r
854 {\r
855         if (start == 0)\r
856                 start = getRootSceneNode();\r
857 \r
858         if (start->getType() == type || ESNT_ANY == type)\r
859                 return start;\r
860 \r
861         ISceneNode* node = 0;\r
862 \r
863         const ISceneNodeList& list = start->getChildren();\r
864         ISceneNodeList::const_iterator it = list.begin();\r
865         for (; it!=list.end(); ++it)\r
866         {\r
867                 node = getSceneNodeFromType(type, *it);\r
868                 if (node)\r
869                         return node;\r
870         }\r
871 \r
872         return 0;\r
873 }\r
874 \r
875 \r
876 //! returns scene nodes by type.\r
877 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)\r
878 {\r
879         if (start == 0)\r
880                 start = getRootSceneNode();\r
881 \r
882         if (start->getType() == type || ESNT_ANY == type)\r
883                 outNodes.push_back(start);\r
884 \r
885         const ISceneNodeList& list = start->getChildren();\r
886         ISceneNodeList::const_iterator it = list.begin();\r
887 \r
888         for (; it!=list.end(); ++it)\r
889         {\r
890                 getSceneNodesFromType(type, outNodes, *it);\r
891         }\r
892 }\r
893 \r
894 \r
895 //! Posts an input event to the environment. Usually you do not have to\r
896 //! use this method, it is used by the internal engine.\r
897 bool CSceneManager::postEventFromUser(const SEvent& event)\r
898 {\r
899         bool ret = false;\r
900         ICameraSceneNode* cam = getActiveCamera();\r
901         if (cam)\r
902                 ret = cam->OnEvent(event);\r
903 \r
904         return ret;\r
905 }\r
906 \r
907 \r
908 //! Removes all children of this scene node\r
909 void CSceneManager::removeAll()\r
910 {\r
911         ISceneNode::removeAll();\r
912         setActiveCamera(0);\r
913         // Make sure the driver is reset, might need a more complex method at some point\r
914         if (Driver)\r
915                 Driver->setMaterial(video::SMaterial());\r
916 }\r
917 \r
918 \r
919 //! Clears the whole scene. All scene nodes are removed.\r
920 void CSceneManager::clear()\r
921 {\r
922         removeAll();\r
923 }\r
924 \r
925 \r
926 //! Returns interface to the parameters set in this scene.\r
927 io::IAttributes* CSceneManager::getParameters()\r
928 {\r
929         return Parameters;\r
930 }\r
931 \r
932 \r
933 //! Returns current render pass.\r
934 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const\r
935 {\r
936         return CurrentRenderPass;\r
937 }\r
938 \r
939 \r
940 //! Returns an interface to the mesh cache which is shared between all existing scene managers.\r
941 IMeshCache* CSceneManager::getMeshCache()\r
942 {\r
943         return MeshCache;\r
944 }\r
945 \r
946 \r
947 //! Creates a new scene manager.\r
948 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)\r
949 {\r
950         CSceneManager* manager = new CSceneManager(Driver, CursorControl, MeshCache);\r
951 \r
952         if (cloneContent)\r
953                 manager->cloneMembers(this, manager);\r
954 \r
955         return manager;\r
956 }\r
957 \r
958 \r
959 //! Sets ambient color of the scene\r
960 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)\r
961 {\r
962         AmbientLight = ambientColor;\r
963 }\r
964 \r
965 \r
966 //! Returns ambient color of the scene\r
967 const video::SColorf& CSceneManager::getAmbientLight() const\r
968 {\r
969         return AmbientLight;\r
970 }\r
971 \r
972 \r
973 //! Get a skinned mesh, which is not available as header-only code\r
974 ISkinnedMesh* CSceneManager::createSkinnedMesh()\r
975 {\r
976         return new CSkinnedMesh();\r
977 }\r
978 \r
979 //! Returns a mesh writer implementation if available\r
980 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)\r
981 {\r
982         return 0;\r
983 }\r
984 \r
985 \r
986 // creates a scenemanager\r
987 ISceneManager* createSceneManager(video::IVideoDriver* driver, gui::ICursorControl* cursorcontrol)\r
988 {\r
989         return new CSceneManager(driver, cursorcontrol, nullptr);\r
990 }\r
991 \r
992 \r
993 } // end namespace scene\r
994 } // end namespace irr\r
995 \r