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