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