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