]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSceneManager.cpp
Drop obsolete configuration macros
[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 #ifdef _IRR_SCENEMANAGER_DEBUG\r
553         s32 index = Parameters->findAttribute("calls");\r
554         Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);\r
555 \r
556         if (!taken)\r
557         {\r
558                 index = Parameters->findAttribute("culled");\r
559                 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);\r
560         }\r
561 #endif\r
562 \r
563         return taken;\r
564 }\r
565 \r
566 void CSceneManager::clearAllRegisteredNodesForRendering()\r
567 {\r
568         CameraList.clear();\r
569         SkyBoxList.clear();\r
570         SolidNodeList.clear();\r
571         TransparentNodeList.clear();\r
572         TransparentEffectNodeList.clear();\r
573         GuiNodeList.clear();\r
574 }\r
575 \r
576 //! This method is called just before the rendering process of the whole scene.\r
577 //! draws all scene nodes\r
578 void CSceneManager::drawAll()\r
579 {\r
580         if (!Driver)\r
581                 return;\r
582 \r
583 #ifdef _IRR_SCENEMANAGER_DEBUG\r
584         // reset attributes\r
585         Parameters->setAttribute("culled", 0);\r
586         Parameters->setAttribute("calls", 0);\r
587         Parameters->setAttribute("drawn_solid", 0);\r
588         Parameters->setAttribute("drawn_transparent", 0);\r
589         Parameters->setAttribute("drawn_transparent_effect", 0);\r
590 #endif\r
591 \r
592         u32 i; // new ISO for scoping problem in some compilers\r
593 \r
594         // reset all transforms\r
595         Driver->setMaterial(video::SMaterial());\r
596         Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );\r
597         Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );\r
598         Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );\r
599         for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i)\r
600                 Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix );\r
601         // TODO: This should not use an attribute here but a real parameter when necessary (too slow!)\r
602         Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT));\r
603 \r
604         // do animations and other stuff.\r
605         OnAnimate(os::Timer::getTime());\r
606 \r
607         /*!\r
608                 First Scene Node for prerendering should be the active camera\r
609                 consistent Camera is needed for culling\r
610         */\r
611         camWorldPos.set(0,0,0);\r
612         if (ActiveCamera)\r
613         {\r
614                 ActiveCamera->render();\r
615                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
616         }\r
617 \r
618         // let all nodes register themselves\r
619         OnRegisterSceneNode();\r
620 \r
621         //render camera scenes\r
622         {\r
623                 CurrentRenderPass = ESNRP_CAMERA;\r
624                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
625 \r
626                 for (i=0; i<CameraList.size(); ++i)\r
627                         CameraList[i]->render();\r
628 \r
629                 CameraList.set_used(0);\r
630         }\r
631 \r
632         // render skyboxes\r
633         {\r
634                 CurrentRenderPass = ESNRP_SKY_BOX;\r
635                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
636 \r
637                 for (i=0; i<SkyBoxList.size(); ++i)\r
638                         SkyBoxList[i]->render();\r
639 \r
640                 SkyBoxList.set_used(0);\r
641         }\r
642 \r
643         // render default objects\r
644         {\r
645                 CurrentRenderPass = ESNRP_SOLID;\r
646                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
647 \r
648                 SolidNodeList.sort(); // sort by textures\r
649 \r
650                 for (i=0; i<SolidNodeList.size(); ++i)\r
651                         SolidNodeList[i].Node->render();\r
652 \r
653 #ifdef _IRR_SCENEMANAGER_DEBUG\r
654                 Parameters->setAttribute("drawn_solid", (s32) SolidNodeList.size() );\r
655 #endif\r
656                 SolidNodeList.set_used(0);\r
657         }\r
658 \r
659         // render transparent objects.\r
660         {\r
661                 CurrentRenderPass = ESNRP_TRANSPARENT;\r
662                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
663 \r
664                 TransparentNodeList.sort(); // sort by distance from camera\r
665                 for (i=0; i<TransparentNodeList.size(); ++i)\r
666                         TransparentNodeList[i].Node->render();\r
667 \r
668 #ifdef _IRR_SCENEMANAGER_DEBUG\r
669                 Parameters->setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() );\r
670 #endif\r
671                 TransparentNodeList.set_used(0);\r
672         }\r
673 \r
674         // render transparent effect objects.\r
675         {\r
676                 CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT;\r
677                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
678 \r
679                 TransparentEffectNodeList.sort(); // sort by distance from camera\r
680 \r
681                 for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
682                         TransparentEffectNodeList[i].Node->render();\r
683 #ifdef _IRR_SCENEMANAGER_DEBUG\r
684                 Parameters->setAttribute("drawn_transparent_effect", (s32) TransparentEffectNodeList.size());\r
685 #endif\r
686                 TransparentEffectNodeList.set_used(0);\r
687         }\r
688 \r
689         // render custom gui nodes\r
690         {\r
691                 CurrentRenderPass = ESNRP_GUI;\r
692                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
693 \r
694                 for (i=0; i<GuiNodeList.size(); ++i)\r
695                         GuiNodeList[i]->render();\r
696 #ifdef _IRR_SCENEMANAGER_DEBUG\r
697                 Parameters->setAttribute("drawn_gui_nodes", (s32) GuiNodeList.size());\r
698 #endif\r
699                 GuiNodeList.set_used(0);\r
700         }\r
701         clearDeletionList();\r
702 \r
703         CurrentRenderPass = ESNRP_NONE;\r
704 }\r
705 \r
706 \r
707 //! Adds an external mesh loader.\r
708 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)\r
709 {\r
710         if (!externalLoader)\r
711                 return;\r
712 \r
713         externalLoader->grab();\r
714         MeshLoaderList.push_back(externalLoader);\r
715 }\r
716 \r
717 \r
718 //! Returns the number of mesh loaders supported by Irrlicht at this time\r
719 u32 CSceneManager::getMeshLoaderCount() const\r
720 {\r
721         return MeshLoaderList.size();\r
722 }\r
723 \r
724 \r
725 //! Retrieve the given mesh loader\r
726 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const\r
727 {\r
728         if (index < MeshLoaderList.size())\r
729                 return MeshLoaderList[index];\r
730         else\r
731                 return 0;\r
732 }\r
733 \r
734 \r
735 //! Returns a pointer to the scene collision manager.\r
736 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()\r
737 {\r
738         return CollisionManager;\r
739 }\r
740 \r
741 \r
742 //! Returns a pointer to the mesh manipulator.\r
743 IMeshManipulator* CSceneManager::getMeshManipulator()\r
744 {\r
745         return Driver->getMeshManipulator();\r
746 }\r
747 \r
748 \r
749 //! Adds a scene node to the deletion queue.\r
750 void CSceneManager::addToDeletionQueue(ISceneNode* node)\r
751 {\r
752         if (!node)\r
753                 return;\r
754 \r
755         node->grab();\r
756         DeletionList.push_back(node);\r
757 }\r
758 \r
759 \r
760 //! clears the deletion list\r
761 void CSceneManager::clearDeletionList()\r
762 {\r
763         if (DeletionList.empty())\r
764                 return;\r
765 \r
766         for (u32 i=0; i<DeletionList.size(); ++i)\r
767         {\r
768                 DeletionList[i]->remove();\r
769                 DeletionList[i]->drop();\r
770         }\r
771 \r
772         DeletionList.clear();\r
773 }\r
774 \r
775 \r
776 //! Returns the first scene node with the specified name.\r
777 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)\r
778 {\r
779         if (start == 0)\r
780                 start = getRootSceneNode();\r
781 \r
782         if (!strcmp(start->getName(),name))\r
783                 return start;\r
784 \r
785         ISceneNode* node = 0;\r
786 \r
787         const ISceneNodeList& list = start->getChildren();\r
788         ISceneNodeList::const_iterator it = list.begin();\r
789         for (; it!=list.end(); ++it)\r
790         {\r
791                 node = getSceneNodeFromName(name, *it);\r
792                 if (node)\r
793                         return node;\r
794         }\r
795 \r
796         return 0;\r
797 }\r
798 \r
799 \r
800 //! Returns the first scene node with the specified id.\r
801 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)\r
802 {\r
803         if (start == 0)\r
804                 start = getRootSceneNode();\r
805 \r
806         if (start->getID() == id)\r
807                 return start;\r
808 \r
809         ISceneNode* node = 0;\r
810 \r
811         const ISceneNodeList& list = start->getChildren();\r
812         ISceneNodeList::const_iterator it = list.begin();\r
813         for (; it!=list.end(); ++it)\r
814         {\r
815                 node = getSceneNodeFromId(id, *it);\r
816                 if (node)\r
817                         return node;\r
818         }\r
819 \r
820         return 0;\r
821 }\r
822 \r
823 \r
824 //! Returns the first scene node with the specified type.\r
825 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)\r
826 {\r
827         if (start == 0)\r
828                 start = getRootSceneNode();\r
829 \r
830         if (start->getType() == type || ESNT_ANY == type)\r
831                 return start;\r
832 \r
833         ISceneNode* node = 0;\r
834 \r
835         const ISceneNodeList& list = start->getChildren();\r
836         ISceneNodeList::const_iterator it = list.begin();\r
837         for (; it!=list.end(); ++it)\r
838         {\r
839                 node = getSceneNodeFromType(type, *it);\r
840                 if (node)\r
841                         return node;\r
842         }\r
843 \r
844         return 0;\r
845 }\r
846 \r
847 \r
848 //! returns scene nodes by type.\r
849 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)\r
850 {\r
851         if (start == 0)\r
852                 start = getRootSceneNode();\r
853 \r
854         if (start->getType() == type || ESNT_ANY == type)\r
855                 outNodes.push_back(start);\r
856 \r
857         const ISceneNodeList& list = start->getChildren();\r
858         ISceneNodeList::const_iterator it = list.begin();\r
859 \r
860         for (; it!=list.end(); ++it)\r
861         {\r
862                 getSceneNodesFromType(type, outNodes, *it);\r
863         }\r
864 }\r
865 \r
866 \r
867 //! Posts an input event to the environment. Usually you do not have to\r
868 //! use this method, it is used by the internal engine.\r
869 bool CSceneManager::postEventFromUser(const SEvent& event)\r
870 {\r
871         bool ret = false;\r
872         ICameraSceneNode* cam = getActiveCamera();\r
873         if (cam)\r
874                 ret = cam->OnEvent(event);\r
875 \r
876         return ret;\r
877 }\r
878 \r
879 \r
880 //! Removes all children of this scene node\r
881 void CSceneManager::removeAll()\r
882 {\r
883         ISceneNode::removeAll();\r
884         setActiveCamera(0);\r
885         // Make sure the driver is reset, might need a more complex method at some point\r
886         if (Driver)\r
887                 Driver->setMaterial(video::SMaterial());\r
888 }\r
889 \r
890 \r
891 //! Clears the whole scene. All scene nodes are removed.\r
892 void CSceneManager::clear()\r
893 {\r
894         removeAll();\r
895 }\r
896 \r
897 \r
898 //! Returns interface to the parameters set in this scene.\r
899 io::IAttributes* CSceneManager::getParameters()\r
900 {\r
901         return Parameters;\r
902 }\r
903 \r
904 \r
905 //! Returns current render pass.\r
906 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const\r
907 {\r
908         return CurrentRenderPass;\r
909 }\r
910 \r
911 \r
912 //! Returns an interface to the mesh cache which is shared between all existing scene managers.\r
913 IMeshCache* CSceneManager::getMeshCache()\r
914 {\r
915         return MeshCache;\r
916 }\r
917 \r
918 \r
919 //! Creates a new scene manager.\r
920 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)\r
921 {\r
922         CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment);\r
923 \r
924         if (cloneContent)\r
925                 manager->cloneMembers(this, manager);\r
926 \r
927         return manager;\r
928 }\r
929 \r
930 \r
931 //! Sets ambient color of the scene\r
932 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)\r
933 {\r
934         AmbientLight = ambientColor;\r
935 }\r
936 \r
937 \r
938 //! Returns ambient color of the scene\r
939 const video::SColorf& CSceneManager::getAmbientLight() const\r
940 {\r
941         return AmbientLight;\r
942 }\r
943 \r
944 \r
945 //! Get a skinned mesh, which is not available as header-only code\r
946 ISkinnedMesh* CSceneManager::createSkinnedMesh()\r
947 {\r
948         return new CSkinnedMesh();\r
949 }\r
950 \r
951 //! Returns a mesh writer implementation if available\r
952 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)\r
953 {\r
954         return 0;\r
955 }\r
956 \r
957 \r
958 // creates a scenemanager\r
959 ISceneManager* createSceneManager(video::IVideoDriver* driver,\r
960                 io::IFileSystem* fs, gui::ICursorControl* cursorcontrol,\r
961                 gui::IGUIEnvironment *guiEnvironment)\r
962 {\r
963         return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment );\r
964 }\r
965 \r
966 \r
967 } // end namespace scene\r
968 } // end namespace irr\r
969 \r