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