]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSceneManager.cpp
Fix various GCC warnings
[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         // as of yet unused\r
611         case ESNRP_LIGHT:\r
612         case ESNRP_SHADOW:\r
613         case ESNRP_NONE: // ignore this one\r
614                 break;\r
615         }\r
616 \r
617 #ifdef _IRR_SCENEMANAGER_DEBUG\r
618         s32 index = Parameters->findAttribute("calls");\r
619         Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);\r
620 \r
621         if (!taken)\r
622         {\r
623                 index = Parameters->findAttribute("culled");\r
624                 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);\r
625         }\r
626 #endif\r
627 \r
628         return taken;\r
629 }\r
630 \r
631 void CSceneManager::clearAllRegisteredNodesForRendering()\r
632 {\r
633         CameraList.clear();\r
634         SkyBoxList.clear();\r
635         SolidNodeList.clear();\r
636         TransparentNodeList.clear();\r
637         TransparentEffectNodeList.clear();\r
638         GuiNodeList.clear();\r
639 }\r
640 \r
641 //! This method is called just before the rendering process of the whole scene.\r
642 //! draws all scene nodes\r
643 void CSceneManager::drawAll()\r
644 {\r
645         IRR_PROFILE(CProfileScope psAll(EPID_SM_DRAW_ALL);)\r
646 \r
647         if (!Driver)\r
648                 return;\r
649 \r
650 #ifdef _IRR_SCENEMANAGER_DEBUG\r
651         // reset attributes\r
652         Parameters->setAttribute("culled", 0);\r
653         Parameters->setAttribute("calls", 0);\r
654         Parameters->setAttribute("drawn_solid", 0);\r
655         Parameters->setAttribute("drawn_transparent", 0);\r
656         Parameters->setAttribute("drawn_transparent_effect", 0);\r
657 #endif\r
658 \r
659         u32 i; // new ISO for scoping problem in some compilers\r
660 \r
661         // reset all transforms\r
662         Driver->setMaterial(video::SMaterial());\r
663         Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );\r
664         Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );\r
665         Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );\r
666         for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i)\r
667                 Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix );\r
668         // TODO: This should not use an attribute here but a real parameter when necessary (too slow!)\r
669         Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT));\r
670 \r
671         // do animations and other stuff.\r
672         IRR_PROFILE(getProfiler().start(EPID_SM_ANIMATE));\r
673         OnAnimate(os::Timer::getTime());\r
674         IRR_PROFILE(getProfiler().stop(EPID_SM_ANIMATE));\r
675 \r
676         /*!\r
677                 First Scene Node for prerendering should be the active camera\r
678                 consistent Camera is needed for culling\r
679         */\r
680         IRR_PROFILE(getProfiler().start(EPID_SM_RENDER_CAMERAS));\r
681         camWorldPos.set(0,0,0);\r
682         if (ActiveCamera)\r
683         {\r
684                 ActiveCamera->render();\r
685                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
686         }\r
687         IRR_PROFILE(getProfiler().stop(EPID_SM_RENDER_CAMERAS));\r
688 \r
689         // let all nodes register themselves\r
690         OnRegisterSceneNode();\r
691 \r
692         //render camera scenes\r
693         {\r
694                 IRR_PROFILE(CProfileScope psCam(EPID_SM_RENDER_CAMERAS);)\r
695                 CurrentRenderPass = ESNRP_CAMERA;\r
696                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
697 \r
698                 for (i=0; i<CameraList.size(); ++i)\r
699                         CameraList[i]->render();\r
700 \r
701                 CameraList.set_used(0);\r
702         }\r
703         \r
704         // render skyboxes\r
705         {\r
706                 IRR_PROFILE(CProfileScope psSkyBox(EPID_SM_RENDER_SKYBOXES);)\r
707                 CurrentRenderPass = ESNRP_SKY_BOX;\r
708                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
709 \r
710                 for (i=0; i<SkyBoxList.size(); ++i)\r
711                         SkyBoxList[i]->render();\r
712 \r
713                 SkyBoxList.set_used(0);\r
714         }\r
715         \r
716         // render default objects\r
717         {\r
718                 IRR_PROFILE(CProfileScope psDefault(EPID_SM_RENDER_DEFAULT);)\r
719                 CurrentRenderPass = ESNRP_SOLID;\r
720                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
721 \r
722                 SolidNodeList.sort(); // sort by textures\r
723 \r
724                 for (i=0; i<SolidNodeList.size(); ++i)\r
725                         SolidNodeList[i].Node->render();\r
726 \r
727 #ifdef _IRR_SCENEMANAGER_DEBUG\r
728                 Parameters->setAttribute("drawn_solid", (s32) SolidNodeList.size() );\r
729 #endif\r
730                 SolidNodeList.set_used(0);\r
731         }\r
732 \r
733         // render transparent objects.\r
734         {\r
735                 IRR_PROFILE(CProfileScope psTrans(EPID_SM_RENDER_TRANSPARENT);)\r
736                 CurrentRenderPass = ESNRP_TRANSPARENT;\r
737                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
738 \r
739                 TransparentNodeList.sort(); // sort by distance from camera\r
740                 for (i=0; i<TransparentNodeList.size(); ++i)\r
741                         TransparentNodeList[i].Node->render();\r
742 \r
743 #ifdef _IRR_SCENEMANAGER_DEBUG\r
744                 Parameters->setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() );\r
745 #endif\r
746                 TransparentNodeList.set_used(0);\r
747         }\r
748 \r
749         // render transparent effect objects.\r
750         {\r
751                 IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_EFFECT);)\r
752                 CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT;\r
753                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
754 \r
755                 TransparentEffectNodeList.sort(); // sort by distance from camera\r
756 \r
757                 for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
758                         TransparentEffectNodeList[i].Node->render();\r
759 #ifdef _IRR_SCENEMANAGER_DEBUG\r
760                 Parameters->setAttribute("drawn_transparent_effect", (s32) TransparentEffectNodeList.size());\r
761 #endif\r
762                 TransparentEffectNodeList.set_used(0);\r
763         }\r
764 \r
765         // render custom gui nodes\r
766         {\r
767                 IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_GUI_NODES);)\r
768                 CurrentRenderPass = ESNRP_GUI;\r
769                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
770 \r
771                 for (i=0; i<GuiNodeList.size(); ++i)\r
772                         GuiNodeList[i]->render();\r
773 #ifdef _IRR_SCENEMANAGER_DEBUG\r
774                 Parameters->setAttribute("drawn_gui_nodes", (s32) GuiNodeList.size());\r
775 #endif\r
776                 GuiNodeList.set_used(0);\r
777         }\r
778         clearDeletionList();\r
779 \r
780         CurrentRenderPass = ESNRP_NONE;\r
781 }\r
782 \r
783 \r
784 //! Adds an external mesh loader.\r
785 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)\r
786 {\r
787         if (!externalLoader)\r
788                 return;\r
789 \r
790         externalLoader->grab();\r
791         MeshLoaderList.push_back(externalLoader);\r
792 }\r
793 \r
794 \r
795 //! Returns the number of mesh loaders supported by Irrlicht at this time\r
796 u32 CSceneManager::getMeshLoaderCount() const\r
797 {\r
798         return MeshLoaderList.size();\r
799 }\r
800 \r
801 \r
802 //! Retrieve the given mesh loader\r
803 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const\r
804 {\r
805         if (index < MeshLoaderList.size())\r
806                 return MeshLoaderList[index];\r
807         else\r
808                 return 0;\r
809 }\r
810 \r
811 \r
812 //! Adds an external scene loader.\r
813 void CSceneManager::addExternalSceneLoader(ISceneLoader* externalLoader)\r
814 {\r
815         if (!externalLoader)\r
816                 return;\r
817 \r
818         externalLoader->grab();\r
819         SceneLoaderList.push_back(externalLoader);\r
820 }\r
821 \r
822 \r
823 //! Returns the number of scene loaders\r
824 u32 CSceneManager::getSceneLoaderCount() const\r
825 {\r
826         return SceneLoaderList.size();\r
827 }\r
828 \r
829 \r
830 //! Retrieve the given scene loader\r
831 ISceneLoader* CSceneManager::getSceneLoader(u32 index) const\r
832 {\r
833         if (index < SceneLoaderList.size())\r
834                 return SceneLoaderList[index];\r
835         else\r
836                 return 0;\r
837 }\r
838 \r
839 //! Returns a pointer to the scene collision manager.\r
840 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()\r
841 {\r
842         return CollisionManager;\r
843 }\r
844 \r
845 \r
846 //! Returns a pointer to the mesh manipulator.\r
847 IMeshManipulator* CSceneManager::getMeshManipulator()\r
848 {\r
849         return Driver->getMeshManipulator();\r
850 }\r
851 \r
852 \r
853 //! Adds a scene node to the deletion queue.\r
854 void CSceneManager::addToDeletionQueue(ISceneNode* node)\r
855 {\r
856         if (!node)\r
857                 return;\r
858 \r
859         node->grab();\r
860         DeletionList.push_back(node);\r
861 }\r
862 \r
863 \r
864 //! clears the deletion list\r
865 void CSceneManager::clearDeletionList()\r
866 {\r
867         if (DeletionList.empty())\r
868                 return;\r
869 \r
870         for (u32 i=0; i<DeletionList.size(); ++i)\r
871         {\r
872                 DeletionList[i]->remove();\r
873                 DeletionList[i]->drop();\r
874         }\r
875 \r
876         DeletionList.clear();\r
877 }\r
878 \r
879 \r
880 //! Returns the first scene node with the specified name.\r
881 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)\r
882 {\r
883         if (start == 0)\r
884                 start = getRootSceneNode();\r
885 \r
886         if (!strcmp(start->getName(),name))\r
887                 return start;\r
888 \r
889         ISceneNode* node = 0;\r
890 \r
891         const ISceneNodeList& list = start->getChildren();\r
892         ISceneNodeList::ConstIterator it = list.begin();\r
893         for (; it!=list.end(); ++it)\r
894         {\r
895                 node = getSceneNodeFromName(name, *it);\r
896                 if (node)\r
897                         return node;\r
898         }\r
899 \r
900         return 0;\r
901 }\r
902 \r
903 \r
904 //! Returns the first scene node with the specified id.\r
905 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)\r
906 {\r
907         if (start == 0)\r
908                 start = getRootSceneNode();\r
909 \r
910         if (start->getID() == id)\r
911                 return start;\r
912 \r
913         ISceneNode* node = 0;\r
914 \r
915         const ISceneNodeList& list = start->getChildren();\r
916         ISceneNodeList::ConstIterator it = list.begin();\r
917         for (; it!=list.end(); ++it)\r
918         {\r
919                 node = getSceneNodeFromId(id, *it);\r
920                 if (node)\r
921                         return node;\r
922         }\r
923 \r
924         return 0;\r
925 }\r
926 \r
927 \r
928 //! Returns the first scene node with the specified type.\r
929 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)\r
930 {\r
931         if (start == 0)\r
932                 start = getRootSceneNode();\r
933 \r
934         if (start->getType() == type || ESNT_ANY == type)\r
935                 return start;\r
936 \r
937         ISceneNode* node = 0;\r
938 \r
939         const ISceneNodeList& list = start->getChildren();\r
940         ISceneNodeList::ConstIterator it = list.begin();\r
941         for (; it!=list.end(); ++it)\r
942         {\r
943                 node = getSceneNodeFromType(type, *it);\r
944                 if (node)\r
945                         return node;\r
946         }\r
947 \r
948         return 0;\r
949 }\r
950 \r
951 \r
952 //! returns scene nodes by type.\r
953 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)\r
954 {\r
955         if (start == 0)\r
956                 start = getRootSceneNode();\r
957 \r
958         if (start->getType() == type || ESNT_ANY == type)\r
959                 outNodes.push_back(start);\r
960 \r
961         const ISceneNodeList& list = start->getChildren();\r
962         ISceneNodeList::ConstIterator it = list.begin();\r
963 \r
964         for (; it!=list.end(); ++it)\r
965         {\r
966                 getSceneNodesFromType(type, outNodes, *it);\r
967         }\r
968 }\r
969 \r
970 \r
971 //! Posts an input event to the environment. Usually you do not have to\r
972 //! use this method, it is used by the internal engine.\r
973 bool CSceneManager::postEventFromUser(const SEvent& event)\r
974 {\r
975         bool ret = false;\r
976         ICameraSceneNode* cam = getActiveCamera();\r
977         if (cam)\r
978                 ret = cam->OnEvent(event);\r
979 \r
980         return ret;\r
981 }\r
982 \r
983 \r
984 //! Removes all children of this scene node\r
985 void CSceneManager::removeAll()\r
986 {\r
987         ISceneNode::removeAll();\r
988         setActiveCamera(0);\r
989         // Make sure the driver is reset, might need a more complex method at some point\r
990         if (Driver)\r
991                 Driver->setMaterial(video::SMaterial());\r
992 }\r
993 \r
994 \r
995 //! Clears the whole scene. All scene nodes are removed.\r
996 void CSceneManager::clear()\r
997 {\r
998         removeAll();\r
999 }\r
1000 \r
1001 \r
1002 //! Returns interface to the parameters set in this scene.\r
1003 io::IAttributes* CSceneManager::getParameters()\r
1004 {\r
1005         return Parameters;\r
1006 }\r
1007 \r
1008 \r
1009 //! Returns current render pass.\r
1010 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const\r
1011 {\r
1012         return CurrentRenderPass;\r
1013 }\r
1014 \r
1015 \r
1016 //! Returns an interface to the mesh cache which is shared between all existing scene managers.\r
1017 IMeshCache* CSceneManager::getMeshCache()\r
1018 {\r
1019         return MeshCache;\r
1020 }\r
1021 \r
1022 \r
1023 //! Creates a new scene manager.\r
1024 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)\r
1025 {\r
1026         CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment);\r
1027 \r
1028         if (cloneContent)\r
1029                 manager->cloneMembers(this, manager);\r
1030 \r
1031         return manager;\r
1032 }\r
1033 \r
1034 \r
1035 //! Returns the default scene node factory which can create all built in scene nodes\r
1036 ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory()\r
1037 {\r
1038         return getSceneNodeFactory(0);\r
1039 }\r
1040 \r
1041 \r
1042 //! Adds a scene node factory to the scene manager.\r
1043 void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd)\r
1044 {\r
1045         if (factoryToAdd)\r
1046         {\r
1047                 factoryToAdd->grab();\r
1048                 SceneNodeFactoryList.push_back(factoryToAdd);\r
1049         }\r
1050 }\r
1051 \r
1052 \r
1053 //! Returns amount of registered scene node factories.\r
1054 u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const\r
1055 {\r
1056         return SceneNodeFactoryList.size();\r
1057 }\r
1058 \r
1059 \r
1060 //! Returns a scene node factory by index\r
1061 ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index)\r
1062 {\r
1063         if (index < SceneNodeFactoryList.size())\r
1064                 return SceneNodeFactoryList[index];\r
1065 \r
1066         return 0;\r
1067 }\r
1068 \r
1069 //! Saves the current scene into a file.\r
1070 //! \param filename: Name of the file .\r
1071 bool CSceneManager::saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)\r
1072 {\r
1073         bool ret = false;\r
1074         io::IWriteFile* file = FileSystem->createAndWriteFile(filename);\r
1075         if (file)\r
1076         {\r
1077                 ret = saveScene(file, userDataSerializer, node);\r
1078                 file->drop();\r
1079         }\r
1080         else\r
1081                 os::Printer::log("Unable to open file", filename, ELL_ERROR);\r
1082 \r
1083         return ret;\r
1084 }\r
1085 \r
1086 \r
1087 //! Saves the current scene into a file.\r
1088 bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)\r
1089 {\r
1090         return false;\r
1091 }\r
1092 \r
1093 \r
1094 //! Loads a scene.\r
1095 bool CSceneManager::loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)\r
1096 {\r
1097         io::IReadFile* file = FileSystem->createAndOpenFile(filename);\r
1098         if (!file)\r
1099         {\r
1100                 os::Printer::log("Unable to open scene file", filename.c_str(), ELL_ERROR);\r
1101                 return false;\r
1102         }\r
1103 \r
1104         const bool ret = loadScene(file, userDataSerializer, rootNode);\r
1105         file->drop();\r
1106 \r
1107         return ret;\r
1108 }\r
1109 \r
1110 \r
1111 //! Loads a scene. Note that the current scene is not cleared before.\r
1112 bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)\r
1113 {\r
1114         if (!file)\r
1115         {\r
1116                 os::Printer::log("Unable to open scene file", ELL_ERROR);\r
1117                 return false;\r
1118         }\r
1119 \r
1120         bool ret = false;\r
1121 \r
1122         // try scene loaders in reverse order\r
1123         s32 i = SceneLoaderList.size()-1;\r
1124         for (; i >= 0 && !ret; --i)\r
1125                 if (SceneLoaderList[i]->isALoadableFileFormat(file))\r
1126                         ret = SceneLoaderList[i]->loadScene(file, userDataSerializer, rootNode);\r
1127 \r
1128         if (!ret)\r
1129                 os::Printer::log("Could not load scene file, perhaps the format is unsupported: ", file->getFileName().c_str(), ELL_ERROR);\r
1130 \r
1131         return ret;\r
1132 }\r
1133 \r
1134 \r
1135 //! Returns a typename from a scene node type or null if not found\r
1136 const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type)\r
1137 {\r
1138         const char* name = 0;\r
1139 \r
1140         for (s32 i=(s32)SceneNodeFactoryList.size()-1; !name && i>=0; --i)\r
1141                 name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type);\r
1142 \r
1143         return name;\r
1144 }\r
1145 \r
1146 //! Adds a scene node to the scene by name\r
1147 ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent)\r
1148 {\r
1149         ISceneNode* node = 0;\r
1150 \r
1151         for (s32 i=(s32)SceneNodeFactoryList.size()-1; i>=0 && !node; --i)\r
1152                         node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent);\r
1153 \r
1154         return node;\r
1155 }\r
1156 \r
1157 //! Writes attributes of the scene node.\r
1158 void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const\r
1159 {\r
1160         out->addString  ("Name", Name.c_str());\r
1161         out->addInt     ("Id", ID );\r
1162         out->addColorf  ("AmbientLight", AmbientLight);\r
1163 \r
1164         // fog attributes from video driver\r
1165         video::SColor color;\r
1166         video::E_FOG_TYPE fogType;\r
1167         f32 start, end, density;\r
1168         bool pixelFog, rangeFog;\r
1169 \r
1170         Driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog);\r
1171 \r
1172         out->addEnum("FogType", fogType, video::FogTypeNames);\r
1173         out->addColorf("FogColor", color);\r
1174         out->addFloat("FogStart", start);\r
1175         out->addFloat("FogEnd", end);\r
1176         out->addFloat("FogDensity", density);\r
1177         out->addBool("FogPixel", pixelFog);\r
1178         out->addBool("FogRange", rangeFog);\r
1179 }\r
1180 \r
1181 //! Reads attributes of the scene node.\r
1182 void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)\r
1183 {\r
1184         Name = in->getAttributeAsString("Name");\r
1185         ID = in->getAttributeAsInt("Id");\r
1186         AmbientLight = in->getAttributeAsColorf("AmbientLight");\r
1187 \r
1188         // fog attributes\r
1189         video::SColor color;\r
1190         video::E_FOG_TYPE fogType;\r
1191         f32 start, end, density;\r
1192         bool pixelFog, rangeFog;\r
1193         if (in->existsAttribute("FogType"))\r
1194         {\r
1195                 fogType = (video::E_FOG_TYPE) in->getAttributeAsEnumeration("FogType", video::FogTypeNames);\r
1196                 color = in->getAttributeAsColorf("FogColor").toSColor();\r
1197                 start = in->getAttributeAsFloat("FogStart");\r
1198                 end = in->getAttributeAsFloat("FogEnd");\r
1199                 density = in->getAttributeAsFloat("FogDensity");\r
1200                 pixelFog = in->getAttributeAsBool("FogPixel");\r
1201                 rangeFog = in->getAttributeAsBool("FogRange");\r
1202                 Driver->setFog(color, fogType, start, end, density, pixelFog, rangeFog);\r
1203         }\r
1204 \r
1205         RelativeTranslation.set(0,0,0);\r
1206         RelativeRotation.set(0,0,0);\r
1207         RelativeScale.set(1,1,1);\r
1208         IsVisible = true;\r
1209         AutomaticCullingState = scene::EAC_BOX;\r
1210         DebugDataVisible = scene::EDS_OFF;\r
1211         IsDebugObject = false;\r
1212 \r
1213         updateAbsolutePosition();\r
1214 }\r
1215 \r
1216 \r
1217 //! Sets ambient color of the scene\r
1218 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)\r
1219 {\r
1220         AmbientLight = ambientColor;\r
1221 }\r
1222 \r
1223 \r
1224 //! Returns ambient color of the scene\r
1225 const video::SColorf& CSceneManager::getAmbientLight() const\r
1226 {\r
1227         return AmbientLight;\r
1228 }\r
1229 \r
1230 \r
1231 //! Get a skinned mesh, which is not available as header-only code\r
1232 ISkinnedMesh* CSceneManager::createSkinnedMesh()\r
1233 {\r
1234 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_\r
1235         return new CSkinnedMesh();\r
1236 #else\r
1237         return 0;\r
1238 #endif\r
1239 }\r
1240 \r
1241 //! Returns a mesh writer implementation if available\r
1242 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)\r
1243 {\r
1244         switch(type)\r
1245         {\r
1246         case EMWT_IRR_MESH:\r
1247         case EMWT_COLLADA:\r
1248                 return 0;\r
1249         case EMWT_STL:\r
1250 #ifdef _IRR_COMPILE_WITH_STL_WRITER_\r
1251                 return new CSTLMeshWriter(this);\r
1252 #else\r
1253                 return 0;\r
1254 #endif\r
1255         case EMWT_OBJ:\r
1256 #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_\r
1257                 return new COBJMeshWriter(this, FileSystem);\r
1258 #else\r
1259                 return 0;\r
1260 #endif\r
1261 \r
1262         case EMWT_PLY:\r
1263 #ifdef _IRR_COMPILE_WITH_PLY_WRITER_\r
1264                 return new CPLYMeshWriter();\r
1265 #else\r
1266                 return 0;\r
1267 #endif\r
1268 \r
1269         case EMWT_B3D:\r
1270 #ifdef _IRR_COMPILE_WITH_B3D_WRITER_\r
1271                 return new CB3DMeshWriter();\r
1272 #else\r
1273                 return 0;\r
1274 #endif\r
1275         }\r
1276 \r
1277         return 0;\r
1278 }\r
1279 \r
1280 \r
1281 // creates a scenemanager\r
1282 ISceneManager* createSceneManager(video::IVideoDriver* driver,\r
1283                 io::IFileSystem* fs, gui::ICursorControl* cursorcontrol,\r
1284                 gui::IGUIEnvironment *guiEnvironment)\r
1285 {\r
1286         return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment );\r
1287 }\r
1288 \r
1289 \r
1290 } // end namespace scene\r
1291 } // end namespace irr\r
1292 \r