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