]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSceneManager.cpp
Merging r6107 through r6116 from trunk to ogl-es branch
[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 "IXMLWriter.h"\r
12 #include "ISceneUserDataSerializer.h"\r
13 #include "IGUIEnvironment.h"\r
14 #include "IMaterialRenderer.h"\r
15 #include "IReadFile.h"\r
16 #include "IWriteFile.h"\r
17 #include "ISceneLoader.h"\r
18 #include "EProfileIDs.h"\r
19 #include "IProfiler.h"\r
20 \r
21 #include "os.h"\r
22 \r
23 // We need this include for the case of skinned mesh support without\r
24 // any such loader\r
25 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_\r
26 #include "CSkinnedMesh.h"\r
27 #endif\r
28 \r
29 #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_\r
30 #include "CIrrMeshFileLoader.h"\r
31 #endif\r
32 \r
33 #ifdef _IRR_COMPILE_WITH_BSP_LOADER_\r
34 #include "CBSPMeshFileLoader.h"\r
35 #endif\r
36 \r
37 #ifdef _IRR_COMPILE_WITH_MD2_LOADER_\r
38 #include "CMD2MeshFileLoader.h"\r
39 #endif\r
40 \r
41 #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_\r
42 #include "CAnimatedMeshHalfLife.h"\r
43 #endif\r
44 \r
45 #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_\r
46 #include "CMS3DMeshFileLoader.h"\r
47 #endif\r
48 \r
49 #ifdef _IRR_COMPILE_WITH_3DS_LOADER_\r
50 #include "C3DSMeshFileLoader.h"\r
51 #endif\r
52 \r
53 #ifdef _IRR_COMPILE_WITH_X_LOADER_\r
54 #include "CXMeshFileLoader.h"\r
55 #endif\r
56 \r
57 #ifdef _IRR_COMPILE_WITH_OCT_LOADER_\r
58 #include "COCTLoader.h"\r
59 #endif\r
60 \r
61 #ifdef _IRR_COMPILE_WITH_CSM_LOADER_\r
62 #include "CCSMLoader.h"\r
63 #endif\r
64 \r
65 #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_\r
66 #include "CLMTSMeshFileLoader.h"\r
67 #endif\r
68 \r
69 #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_\r
70 #include "CMY3DMeshFileLoader.h"\r
71 #endif\r
72 \r
73 #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_\r
74 #include "CColladaFileLoader.h"\r
75 #endif\r
76 \r
77 #ifdef _IRR_COMPILE_WITH_DMF_LOADER_\r
78 #include "CDMFLoader.h"\r
79 #endif\r
80 \r
81 #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_\r
82 #include "COgreMeshFileLoader.h"\r
83 #endif\r
84 \r
85 #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_\r
86 #include "COBJMeshFileLoader.h"\r
87 #endif\r
88 \r
89 #ifdef _IRR_COMPILE_WITH_MD3_LOADER_\r
90 #include "CMD3MeshFileLoader.h"\r
91 #endif\r
92 \r
93 #ifdef _IRR_COMPILE_WITH_B3D_LOADER_\r
94 #include "CB3DMeshFileLoader.h"\r
95 #endif\r
96 \r
97 #ifdef _IRR_COMPILE_WITH_LWO_LOADER_\r
98 #include "CLWOMeshFileLoader.h"\r
99 #endif\r
100 \r
101 #ifdef _IRR_COMPILE_WITH_STL_LOADER_\r
102 #include "CSTLMeshFileLoader.h"\r
103 #endif\r
104 \r
105 #ifdef _IRR_COMPILE_WITH_PLY_LOADER_\r
106 #include "CPLYMeshFileLoader.h"\r
107 #endif\r
108 \r
109 #ifdef _IRR_COMPILE_WITH_SMF_LOADER_\r
110 #include "CSMFMeshFileLoader.h"\r
111 #endif\r
112 \r
113 #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_\r
114 #include "CSceneLoaderIrr.h"\r
115 #endif\r
116 \r
117 #ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_\r
118 #include "CColladaMeshWriter.h"\r
119 #endif\r
120 \r
121 #ifdef _IRR_COMPILE_WITH_IRR_WRITER_\r
122 #include "CIrrMeshWriter.h"\r
123 #endif\r
124 \r
125 #ifdef _IRR_COMPILE_WITH_STL_WRITER_\r
126 #include "CSTLMeshWriter.h"\r
127 #endif\r
128 \r
129 #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_\r
130 #include "COBJMeshWriter.h"\r
131 #endif\r
132 \r
133 #ifdef _IRR_COMPILE_WITH_PLY_WRITER_\r
134 #include "CPLYMeshWriter.h"\r
135 #endif\r
136 \r
137 #ifdef _IRR_COMPILE_WITH_B3D_WRITER_\r
138 #include "CB3DMeshWriter.h"\r
139 #endif\r
140 \r
141 #ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_\r
142 #include "CCubeSceneNode.h"\r
143 #endif // _IRR_COMPILE_WITH_CUBE_SCENENODE_\r
144 #ifdef _IRR_COMPILE_WITH_SPHERE_SCENENODE_\r
145 #include "CSphereSceneNode.h"\r
146 #endif\r
147 #include "CAnimatedMeshSceneNode.h"\r
148 #ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_\r
149 #include "COctreeSceneNode.h"\r
150 #endif // #ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_\r
151 #include "CCameraSceneNode.h"\r
152 #include "CLightSceneNode.h"\r
153 #ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_\r
154 #include "CBillboardSceneNode.h"\r
155 #endif // _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_\r
156 #include "CMeshSceneNode.h"\r
157 #include "CSkyBoxSceneNode.h"\r
158 #ifdef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_\r
159 #include "CSkyDomeSceneNode.h"\r
160 #endif // _IRR_COMPILE_WITH_SKYDOME_SCENENODE_\r
161 \r
162 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
163 #include "CShadowVolumeSceneNode.h"\r
164 #else\r
165 #include "IShadowVolumeSceneNode.h"\r
166 #endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
167 \r
168 #ifdef _IRR_COMPILE_WITH_PARTICLES_\r
169 #include "CParticleSystemSceneNode.h"\r
170 #endif // _IRR_COMPILE_WITH_PARTICLES_\r
171 \r
172 #include "CDummyTransformationSceneNode.h"\r
173 #ifdef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_\r
174 #include "CWaterSurfaceSceneNode.h"\r
175 #endif // _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_\r
176 #ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
177 #include "CTerrainSceneNode.h"\r
178 #endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
179 #include "CEmptySceneNode.h"\r
180 #include "CTextSceneNode.h"\r
181 #include "CQuake3ShaderSceneNode.h"\r
182 #include "CVolumeLightSceneNode.h"\r
183 \r
184 #include "CDefaultSceneNodeFactory.h"\r
185 \r
186 #include "CSceneCollisionManager.h"\r
187 #include "CTriangleSelector.h"\r
188 #include "COctreeTriangleSelector.h"\r
189 #include "CTriangleBBSelector.h"\r
190 #include "CMetaTriangleSelector.h"\r
191 #ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
192 #include "CTerrainTriangleSelector.h"\r
193 #endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
194 \r
195 #include "CSceneNodeAnimatorRotation.h"\r
196 #include "CSceneNodeAnimatorFlyCircle.h"\r
197 #include "CSceneNodeAnimatorFlyStraight.h"\r
198 #include "CSceneNodeAnimatorTexture.h"\r
199 #include "CSceneNodeAnimatorCollisionResponse.h"\r
200 #include "CSceneNodeAnimatorDelete.h"\r
201 #include "CSceneNodeAnimatorFollowSpline.h"\r
202 #include "CSceneNodeAnimatorCameraFPS.h"\r
203 #include "CSceneNodeAnimatorCameraMaya.h"\r
204 #include "CDefaultSceneNodeAnimatorFactory.h"\r
205 \r
206 #include "CGeometryCreator.h"\r
207 \r
208 #include <locale.h>\r
209 \r
210 namespace irr\r
211 {\r
212 namespace scene\r
213 {\r
214 \r
215 //! constructor\r
216 CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs,\r
217                 gui::ICursorControl* cursorControl, IMeshCache* cache,\r
218                 gui::IGUIEnvironment* gui)\r
219 : ISceneNode(0, 0), Driver(driver), FileSystem(fs), GUIEnvironment(gui),\r
220         CursorControl(cursorControl), CollisionManager(0),\r
221         ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), Parameters(0),\r
222         MeshCache(cache), CurrentRenderPass(ESNRP_NONE), LightManager(0),\r
223         IRR_XML_FORMAT_SCENE(L"irr_scene"), IRR_XML_FORMAT_NODE(L"node"), IRR_XML_FORMAT_NODE_ATTR_TYPE(L"type")\r
224 {\r
225         #ifdef _DEBUG\r
226         ISceneManager::setDebugName("CSceneManager ISceneManager");\r
227         ISceneNode::setDebugName("CSceneManager ISceneNode");\r
228         #endif\r
229 \r
230         // root node's scene manager\r
231         SceneManager = this;\r
232 \r
233         if (Driver)\r
234                 Driver->grab();\r
235 \r
236         if (FileSystem)\r
237                 FileSystem->grab();\r
238 \r
239         if (CursorControl)\r
240                 CursorControl->grab();\r
241 \r
242         if (GUIEnvironment)\r
243                 GUIEnvironment->grab();\r
244 \r
245         // create mesh cache if not there already\r
246         if (!MeshCache)\r
247                 MeshCache = new CMeshCache();\r
248         else\r
249                 MeshCache->grab();\r
250 \r
251         // set scene parameters\r
252         Parameters = new io::CAttributes();\r
253         Parameters->setAttribute(DEBUG_NORMAL_LENGTH, 1.f);\r
254         Parameters->setAttribute(DEBUG_NORMAL_COLOR, video::SColor(255, 34, 221, 221));\r
255 \r
256         // create collision manager\r
257         CollisionManager = new CSceneCollisionManager(this, Driver);\r
258 \r
259         // create geometry creator\r
260         GeometryCreator = new CGeometryCreator();\r
261 \r
262         // add file format loaders. add the least commonly used ones first,\r
263         // as these are checked last\r
264 \r
265         // TODO: now that we have multiple scene managers, these should be\r
266         // shallow copies from the previous manager if there is one.\r
267 \r
268         #ifdef _IRR_COMPILE_WITH_STL_LOADER_\r
269         MeshLoaderList.push_back(new CSTLMeshFileLoader());\r
270         #endif\r
271         #ifdef _IRR_COMPILE_WITH_PLY_LOADER_\r
272         MeshLoaderList.push_back(new CPLYMeshFileLoader(this));\r
273         #endif\r
274         #ifdef _IRR_COMPILE_WITH_SMF_LOADER_\r
275         MeshLoaderList.push_back(new CSMFMeshFileLoader(FileSystem, Driver));\r
276         #endif\r
277         #ifdef _IRR_COMPILE_WITH_OCT_LOADER_\r
278         MeshLoaderList.push_back(new COCTLoader(this, FileSystem));\r
279         #endif\r
280         #ifdef _IRR_COMPILE_WITH_CSM_LOADER_\r
281         MeshLoaderList.push_back(new CCSMLoader(this, FileSystem));\r
282         #endif\r
283         #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_\r
284         MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, Parameters));\r
285         #endif\r
286         #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_\r
287         MeshLoaderList.push_back(new CMY3DMeshFileLoader(this, FileSystem));\r
288         #endif\r
289         #ifdef _IRR_COMPILE_WITH_DMF_LOADER_\r
290         MeshLoaderList.push_back(new CDMFLoader(this, FileSystem));\r
291         #endif\r
292         #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_\r
293         MeshLoaderList.push_back(new COgreMeshFileLoader(FileSystem, Driver));\r
294         #endif\r
295         #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_\r
296         MeshLoaderList.push_back(new CHalflifeMDLMeshFileLoader( this ));\r
297         #endif\r
298         #ifdef _IRR_COMPILE_WITH_MD3_LOADER_\r
299         MeshLoaderList.push_back(new CMD3MeshFileLoader( this));\r
300         #endif\r
301         #ifdef _IRR_COMPILE_WITH_LWO_LOADER_\r
302         MeshLoaderList.push_back(new CLWOMeshFileLoader(this, FileSystem));\r
303         #endif\r
304         #ifdef _IRR_COMPILE_WITH_MD2_LOADER_\r
305         MeshLoaderList.push_back(new CMD2MeshFileLoader());\r
306         #endif\r
307         #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_\r
308         MeshLoaderList.push_back(new CIrrMeshFileLoader(this, FileSystem));\r
309         #endif\r
310         #ifdef _IRR_COMPILE_WITH_BSP_LOADER_\r
311         MeshLoaderList.push_back(new CBSPMeshFileLoader(this, FileSystem));\r
312         #endif\r
313         #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_\r
314         MeshLoaderList.push_back(new CColladaFileLoader(this, FileSystem));\r
315         #endif\r
316         #ifdef _IRR_COMPILE_WITH_3DS_LOADER_\r
317         MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem));\r
318         #endif\r
319         #ifdef _IRR_COMPILE_WITH_X_LOADER_\r
320         MeshLoaderList.push_back(new CXMeshFileLoader(this, FileSystem));\r
321         #endif\r
322         #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_\r
323         MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver));\r
324         #endif\r
325         #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_\r
326         MeshLoaderList.push_back(new COBJMeshFileLoader(this, FileSystem));\r
327         #endif\r
328         #ifdef _IRR_COMPILE_WITH_B3D_LOADER_\r
329         MeshLoaderList.push_back(new CB3DMeshFileLoader(this));\r
330         #endif\r
331 \r
332         // scene loaders\r
333         #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_\r
334         SceneLoaderList.push_back(new CSceneLoaderIrr(this, FileSystem));\r
335         #endif\r
336 \r
337         // factories\r
338         ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this);\r
339         registerSceneNodeFactory(factory);\r
340         factory->drop();\r
341 \r
342         ISceneNodeAnimatorFactory* animatorFactory = new CDefaultSceneNodeAnimatorFactory(this, CursorControl);\r
343         registerSceneNodeAnimatorFactory(animatorFactory);\r
344         animatorFactory->drop();\r
345 \r
346         IRR_PROFILE(\r
347                 static bool initProfile = false;\r
348                 if (!initProfile )\r
349                 {\r
350                         initProfile = true;\r
351                         getProfiler().add(EPID_SM_DRAW_ALL, L"drawAll", L"Irrlicht scene");\r
352                         getProfiler().add(EPID_SM_ANIMATE, L"animate", L"Irrlicht scene");\r
353                         getProfiler().add(EPID_SM_RENDER_CAMERAS, L"cameras", L"Irrlicht scene");\r
354                         getProfiler().add(EPID_SM_RENDER_LIGHTS, L"lights", L"Irrlicht scene");\r
355                         getProfiler().add(EPID_SM_RENDER_SKYBOXES, L"skyboxes", L"Irrlicht scene");\r
356                         getProfiler().add(EPID_SM_RENDER_DEFAULT, L"defaultnodes", L"Irrlicht scene");\r
357                         getProfiler().add(EPID_SM_RENDER_SHADOWS, L"shadows", L"Irrlicht scene");\r
358                         getProfiler().add(EPID_SM_RENDER_TRANSPARENT, L"transp.nodes", L"Irrlicht scene");\r
359                         getProfiler().add(EPID_SM_RENDER_EFFECT, L"effectnodes", L"Irrlicht scene");\r
360                         getProfiler().add(EPID_SM_RENDER_GUI_NODES, L"guinodes", L"Irrlicht scene");\r
361                         getProfiler().add(EPID_SM_REGISTER, L"reg.render.node", L"Irrlicht scene");\r
362                 }\r
363         )\r
364 }\r
365 \r
366 \r
367 //! destructor\r
368 CSceneManager::~CSceneManager()\r
369 {\r
370         clearDeletionList();\r
371 \r
372         //! force to remove hardwareTextures from the driver\r
373         //! because Scenes may hold internally data bounded to sceneNodes\r
374         //! which may be destroyed twice\r
375         if (Driver)\r
376                 Driver->removeAllHardwareBuffers();\r
377 \r
378         if (FileSystem)\r
379                 FileSystem->drop();\r
380 \r
381         if (CursorControl)\r
382                 CursorControl->drop();\r
383 \r
384         if (CollisionManager)\r
385                 CollisionManager->drop();\r
386 \r
387         if (GeometryCreator)\r
388                 GeometryCreator->drop();\r
389 \r
390         if (GUIEnvironment)\r
391                 GUIEnvironment->drop();\r
392 \r
393         u32 i;\r
394         for (i=0; i<MeshLoaderList.size(); ++i)\r
395                 MeshLoaderList[i]->drop();\r
396 \r
397         for (i=0; i<SceneLoaderList.size(); ++i)\r
398                 SceneLoaderList[i]->drop();\r
399 \r
400         if (ActiveCamera)\r
401                 ActiveCamera->drop();\r
402         ActiveCamera = 0;\r
403 \r
404         if (MeshCache)\r
405                 MeshCache->drop();\r
406 \r
407         if (Parameters)\r
408                 Parameters->drop();\r
409 \r
410         for (i=0; i<SceneNodeFactoryList.size(); ++i)\r
411                 SceneNodeFactoryList[i]->drop();\r
412 \r
413         for (i=0; i<SceneNodeAnimatorFactoryList.size(); ++i)\r
414                 SceneNodeAnimatorFactoryList[i]->drop();\r
415 \r
416         if (LightManager)\r
417                 LightManager->drop();\r
418 \r
419         // remove all nodes and animators before dropping the driver\r
420         // as render targets may be destroyed twice\r
421 \r
422         removeAll();\r
423         removeAnimators();\r
424 \r
425         if (Driver)\r
426                 Driver->drop();\r
427 }\r
428 \r
429 \r
430 //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped.\r
431 IAnimatedMesh* CSceneManager::getMesh(const io::path& filename, const io::path& alternativeCacheName)\r
432 {\r
433         io::path cacheName = alternativeCacheName.empty() ? filename : alternativeCacheName;\r
434         IAnimatedMesh* msh = MeshCache->getMeshByName(cacheName);\r
435         if (msh)\r
436                 return msh;\r
437 \r
438         io::IReadFile* file = FileSystem->createAndOpenFile(filename);\r
439         if (!file)\r
440         {\r
441                 os::Printer::log("Could not load mesh, because file could not be opened: ", filename, ELL_ERROR);\r
442                 return 0;\r
443         }\r
444 \r
445         msh = getUncachedMesh(file, filename, cacheName);\r
446 \r
447         file->drop();\r
448 \r
449         return msh;\r
450 }\r
451 \r
452 \r
453 //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped.\r
454 IAnimatedMesh* CSceneManager::getMesh(io::IReadFile* file)\r
455 {\r
456         if (!file)\r
457                 return 0;\r
458 \r
459         io::path name = file->getFileName();\r
460         IAnimatedMesh* msh = MeshCache->getMeshByName(name);\r
461         if (msh)\r
462                 return msh;\r
463 \r
464         msh = getUncachedMesh(file, name, name);\r
465 \r
466         return msh;\r
467 }\r
468 \r
469 // load and create a mesh which we know already isn't in the cache and put it in there\r
470 IAnimatedMesh* CSceneManager::getUncachedMesh(io::IReadFile* file, const io::path& filename, const io::path& cachename)\r
471 {\r
472         IAnimatedMesh* msh = 0;\r
473 \r
474         // iterate the list in reverse order so user-added loaders can override the built-in ones\r
475         s32 count = MeshLoaderList.size();\r
476         for (s32 i=count-1; i>=0; --i)\r
477         {\r
478                 if (MeshLoaderList[i]->isALoadableFileExtension(filename))\r
479                 {\r
480                         // reset file to avoid side effects of previous calls to createMesh\r
481                         file->seek(0);\r
482                         msh = MeshLoaderList[i]->createMesh(file);\r
483                         if (msh)\r
484                         {\r
485                                 MeshCache->addMesh(cachename, msh);\r
486                                 msh->drop();\r
487                                 break;\r
488                         }\r
489                 }\r
490         }\r
491 \r
492         if (!msh)\r
493                 os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR);\r
494         else\r
495                 os::Printer::log("Loaded mesh", filename, ELL_DEBUG);\r
496 \r
497         return msh;\r
498 }\r
499 \r
500 //! returns the video driver\r
501 video::IVideoDriver* CSceneManager::getVideoDriver()\r
502 {\r
503         return Driver;\r
504 }\r
505 \r
506 \r
507 //! returns the GUI Environment\r
508 gui::IGUIEnvironment* CSceneManager::getGUIEnvironment()\r
509 {\r
510         return GUIEnvironment;\r
511 }\r
512 \r
513 //! Get the active FileSystem\r
514 /** \return Pointer to the FileSystem\r
515 This pointer should not be dropped. See IReferenceCounted::drop() for more information. */\r
516 io::IFileSystem* CSceneManager::getFileSystem()\r
517 {\r
518         return FileSystem;\r
519 }\r
520 \r
521 //! Adds a text scene node, which is able to display\r
522 //! 2d text at a position in three dimensional space\r
523 ITextSceneNode* CSceneManager::addTextSceneNode(gui::IGUIFont* font,\r
524                 const wchar_t* text, video::SColor color, ISceneNode* parent,\r
525                 const core::vector3df& position, s32 id)\r
526 {\r
527         if (!font)\r
528                 return 0;\r
529 \r
530         if (!parent)\r
531                 parent = this;\r
532 \r
533         ITextSceneNode* t = new CTextSceneNode(parent, this, id, font,\r
534                 getSceneCollisionManager(), position, text, color);\r
535         t->drop();\r
536 \r
537         return t;\r
538 }\r
539 \r
540 \r
541 //! Adds a text scene node, which uses billboards\r
542 IBillboardTextSceneNode* CSceneManager::addBillboardTextSceneNode(gui::IGUIFont* font,\r
543                 const wchar_t* text, ISceneNode* parent,\r
544                 const core::dimension2d<f32>& size,\r
545                 const core::vector3df& position, s32 id,\r
546                 video::SColor colorTop, video::SColor colorBottom)\r
547 {\r
548         if (!font && GUIEnvironment)\r
549                 font = GUIEnvironment->getBuiltInFont();\r
550 \r
551         if (!font)\r
552                 return 0;\r
553 \r
554         if (!parent)\r
555                 parent = this;\r
556 \r
557         IBillboardTextSceneNode* node = new CBillboardTextSceneNode(parent, this, id, font, text, position, size,\r
558                 colorTop, colorBottom);\r
559         node->drop();\r
560 \r
561         return node;\r
562 \r
563 }\r
564 \r
565 \r
566 //! Adds a scene node, which can render a quake3 shader\r
567 IMeshSceneNode* CSceneManager::addQuake3SceneNode(const IMeshBuffer* meshBuffer,\r
568                                         const quake3::IShader * shader,\r
569                                         ISceneNode* parent, s32 id )\r
570 {\r
571 #ifdef _IRR_COMPILE_WITH_BSP_LOADER_\r
572         if (!shader)\r
573                 return 0;\r
574 \r
575         if (!parent)\r
576                 parent = this;\r
577 \r
578         CQuake3ShaderSceneNode* node = new CQuake3ShaderSceneNode( parent,\r
579                 this, id, FileSystem,\r
580                 meshBuffer, shader );\r
581         node->drop();\r
582 \r
583         return node;\r
584 #else\r
585         return 0;\r
586 #endif\r
587 }\r
588 \r
589 \r
590 //! adds Volume Lighting Scene Node.\r
591 //! the returned pointer must not be dropped.\r
592 IVolumeLightSceneNode* CSceneManager::addVolumeLightSceneNode(\r
593                 ISceneNode* parent, s32 id,\r
594                 const u32 subdivU, const u32 subdivV,\r
595                 const video::SColor foot, const video::SColor tail,\r
596                 const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale)\r
597 {\r
598         if (!parent)\r
599                 parent = this;\r
600 \r
601         IVolumeLightSceneNode* node = new CVolumeLightSceneNode(parent, this, id, subdivU, subdivV, foot, tail, position, rotation, scale);\r
602         node->drop();\r
603 \r
604         return node;\r
605 }\r
606 \r
607 \r
608 //! adds a test scene node for test purposes to the scene. It is a simple cube of (1,1,1) size.\r
609 //! the returned pointer must not be dropped.\r
610 IMeshSceneNode* CSceneManager::addCubeSceneNode(f32 size, ISceneNode* parent,\r
611                 s32 id, const core::vector3df& position,\r
612                 const core::vector3df& rotation, const core::vector3df& scale)\r
613 {\r
614 #ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_\r
615         if (!parent)\r
616                 parent = this;\r
617 \r
618         IMeshSceneNode* node = new CCubeSceneNode(size, parent, this, id, position, rotation, scale);\r
619         node->drop();\r
620 \r
621         return node;\r
622 #else\r
623         return 0;\r
624 #endif\r
625 }\r
626 \r
627 \r
628 //! Adds a sphere scene node for test purposes to the scene.\r
629 IMeshSceneNode* CSceneManager::addSphereSceneNode(f32 radius, s32 polyCount,\r
630                 ISceneNode* parent, s32 id, const core::vector3df& position,\r
631                 const core::vector3df& rotation, const core::vector3df& scale)\r
632 {\r
633 #ifdef _IRR_COMPILE_WITH_SPHERE_SCENENODE_\r
634         if (!parent)\r
635                 parent = this;\r
636 \r
637         IMeshSceneNode* node = new CSphereSceneNode(radius, polyCount, polyCount, parent, this, id, position, rotation, scale);\r
638         node->drop();\r
639 \r
640         return node;\r
641 #else\r
642         return 0;\r
643 #endif // _IRR_COMPILE_WITH_SPHERE_SCENENODE_\r
644 }\r
645 \r
646 \r
647 //! adds a scene node for rendering a static mesh\r
648 //! the returned pointer must not be dropped.\r
649 IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id,\r
650         const core::vector3df& position, const core::vector3df& rotation,\r
651         const core::vector3df& scale, bool alsoAddIfMeshPointerZero)\r
652 {\r
653         if (!alsoAddIfMeshPointerZero && !mesh)\r
654                 return 0;\r
655 \r
656         if (!parent)\r
657                 parent = this;\r
658 \r
659         IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale);\r
660         node->drop();\r
661 \r
662         return node;\r
663 }\r
664 \r
665 \r
666 //! Adds a scene node for rendering a animated water surface mesh.\r
667 ISceneNode* CSceneManager::addWaterSurfaceSceneNode(IMesh* mesh, f32 waveHeight, f32 waveSpeed, f32 waveLength,\r
668         ISceneNode* parent, s32 id, const core::vector3df& position,\r
669         const core::vector3df& rotation, const core::vector3df& scale)\r
670 {\r
671 #ifdef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_\r
672         if (!parent)\r
673                 parent = this;\r
674 \r
675         ISceneNode* node = new CWaterSurfaceSceneNode(waveHeight, waveSpeed, waveLength,\r
676                 mesh, parent, this, id, position, rotation, scale);\r
677 \r
678         node->drop();\r
679 \r
680         return node;\r
681 #else\r
682         return 0;\r
683 #endif\r
684 }\r
685 \r
686 \r
687 //! adds a scene node for rendering an animated mesh model\r
688 IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id,\r
689         const core::vector3df& position, const core::vector3df& rotation,\r
690         const core::vector3df& scale, bool alsoAddIfMeshPointerZero)\r
691 {\r
692         if (!alsoAddIfMeshPointerZero && !mesh)\r
693                 return 0;\r
694 \r
695         if (!parent)\r
696                 parent = this;\r
697 \r
698         IAnimatedMeshSceneNode* node =\r
699                 new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale);\r
700         node->drop();\r
701 \r
702         return node;\r
703 }\r
704 \r
705 \r
706 //! Adds a scene node for rendering using a octree to the scene graph. This a good method for rendering\r
707 //! scenes with lots of geometry. The Octree is built on the fly from the mesh, much\r
708 //! faster then a bsp tree.\r
709 IOctreeSceneNode* CSceneManager::addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent,\r
710                         s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero)\r
711 {\r
712         if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount()))\r
713                 return 0;\r
714 \r
715         return addOctreeSceneNode(mesh ? mesh->getMesh(0) : 0,\r
716                                 parent, id, minimalPolysPerNode,\r
717                                 alsoAddIfMeshPointerZero);\r
718 }\r
719 \r
720 \r
721 //! Adds a scene node for rendering using a octree. This a good method for rendering\r
722 //! scenes with lots of geometry. The Octree is built on the fly from the mesh, much\r
723 //! faster then a bsp tree.\r
724 IOctreeSceneNode* CSceneManager::addOctreeSceneNode(IMesh* mesh, ISceneNode* parent,\r
725                 s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero)\r
726 {\r
727 #ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_\r
728         if (!alsoAddIfMeshPointerZero && !mesh)\r
729                 return 0;\r
730 \r
731         if (!parent)\r
732                 parent = this;\r
733 \r
734         COctreeSceneNode* node = new COctreeSceneNode(parent, this, id, minimalPolysPerNode);\r
735 \r
736         if (node)\r
737         {\r
738                 node->setMesh(mesh);\r
739                 node->drop();\r
740         }\r
741 \r
742         return node;\r
743 #else\r
744         return 0;\r
745 #endif\r
746 }\r
747 \r
748 \r
749 //! Adds a camera scene node to the tree and sets it as active camera.\r
750 //! \param position: Position of the space relative to its parent where the camera will be placed.\r
751 //! \param lookat: Position where the camera will look at. Also known as target.\r
752 //! \param parent: Parent scene node of the camera. Can be null. If the parent moves,\r
753 //! the camera will move too.\r
754 //! \return Returns pointer to interface to camera\r
755 ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent,\r
756         const core::vector3df& position, const core::vector3df& lookat, s32 id,\r
757         bool makeActive)\r
758 {\r
759         if (!parent)\r
760                 parent = this;\r
761 \r
762         ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat);\r
763 \r
764         if (makeActive)\r
765                 setActiveCamera(node);\r
766         node->drop();\r
767 \r
768         return node;\r
769 }\r
770 \r
771 \r
772 //! Adds a camera scene node which is able to be controlled with the mouse similar\r
773 //! to in the 3D Software Maya by Alias Wavefront.\r
774 //! The returned pointer must not be dropped.\r
775 ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent,\r
776         f32 rotateSpeed, f32 zoomSpeed, f32 translationSpeed, s32 id, f32 distance,\r
777         bool makeActive)\r
778 {\r
779         ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(),\r
780                         core::vector3df(0,0,100), id, makeActive);\r
781         if (node)\r
782         {\r
783                 ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraMaya(CursorControl,\r
784                         rotateSpeed, zoomSpeed, translationSpeed, distance);\r
785 \r
786                 node->addAnimator(anm);\r
787                 anm->drop();\r
788         }\r
789 \r
790         return node;\r
791 }\r
792 \r
793 \r
794 //! Adds a camera scene node which is able to be controlled with the mouse and keys\r
795 //! like in most first person shooters (FPS):\r
796 ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent,\r
797         f32 rotateSpeed, f32 moveSpeed, s32 id, SKeyMap* keyMapArray,\r
798         s32 keyMapSize, bool noVerticalMovement, f32 jumpSpeed,\r
799         bool invertMouseY, bool makeActive)\r
800 {\r
801         ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(),\r
802                         core::vector3df(0,0,100), id, makeActive);\r
803         if (node)\r
804         {\r
805                 ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraFPS(CursorControl,\r
806                                 rotateSpeed, moveSpeed, jumpSpeed,\r
807                                 keyMapArray, keyMapSize, noVerticalMovement, invertMouseY);\r
808 \r
809                 // Bind the node's rotation to its target. This is consistent with 1.4.2 and below.\r
810                 node->bindTargetAndRotation(true);\r
811                 node->addAnimator(anm);\r
812                 anm->drop();\r
813         }\r
814 \r
815         return node;\r
816 }\r
817 \r
818 \r
819 //! Adds a dynamic light scene node. The light will cast dynamic light on all\r
820 //! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING\r
821 //! turned on. (This is the default setting in most scene nodes).\r
822 ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent,\r
823         const core::vector3df& position, video::SColorf color, f32 range, s32 id)\r
824 {\r
825         if (!parent)\r
826                 parent = this;\r
827 \r
828         ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range);\r
829         node->drop();\r
830 \r
831         return node;\r
832 }\r
833 \r
834 \r
835 //! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element,\r
836 //! which always looks to the camera. It is usually used for things like explosions, fire,\r
837 //! lensflares and things like that.\r
838 IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent,\r
839         const core::dimension2d<f32>& size, const core::vector3df& position, s32 id,\r
840         video::SColor colorTop, video::SColor colorBottom\r
841         )\r
842 {\r
843 #ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_\r
844         if (!parent)\r
845                 parent = this;\r
846 \r
847         IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size,\r
848                 colorTop, colorBottom);\r
849         node->drop();\r
850 \r
851         return node;\r
852 #else\r
853         return 0;\r
854 #endif\r
855 }\r
856 \r
857 \r
858 //! Adds a skybox scene node. A skybox is a big cube with 6 textures on it and\r
859 //! is drawn around the camera position.\r
860 ISceneNode* CSceneManager::addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom,\r
861         video::ITexture* left, video::ITexture* right, video::ITexture* front,\r
862         video::ITexture* back, ISceneNode* parent, s32 id)\r
863 {\r
864         if (!parent)\r
865                 parent = this;\r
866 \r
867         ISceneNode* node = new CSkyBoxSceneNode(top, bottom, left, right,\r
868                         front, back, parent, this, id);\r
869 \r
870         node->drop();\r
871         return node;\r
872 }\r
873 \r
874 \r
875 //! Adds a skydome scene node. A skydome is a large (half-) sphere with a\r
876 //! panoramic texture on it and is drawn around the camera position.\r
877 ISceneNode* CSceneManager::addSkyDomeSceneNode(video::ITexture* texture,\r
878         u32 horiRes, u32 vertRes, f32 texturePercentage,f32 spherePercentage, f32 radius,\r
879         ISceneNode* parent, s32 id)\r
880 {\r
881 #ifdef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_\r
882         if (!parent)\r
883                 parent = this;\r
884 \r
885         ISceneNode* node = new CSkyDomeSceneNode(texture, horiRes, vertRes,\r
886                 texturePercentage, spherePercentage, radius, parent, this, id);\r
887 \r
888         node->drop();\r
889         return node;\r
890 #else\r
891         return 0;\r
892 #endif\r
893 }\r
894 \r
895 \r
896 //! Adds a particle system scene node.\r
897 IParticleSystemSceneNode* CSceneManager::addParticleSystemSceneNode(\r
898         bool withDefaultEmitter, ISceneNode* parent, s32 id,\r
899         const core::vector3df& position, const core::vector3df& rotation,\r
900         const core::vector3df& scale)\r
901 {\r
902 #ifdef _IRR_COMPILE_WITH_PARTICLES_\r
903         if (!parent)\r
904                 parent = this;\r
905 \r
906         IParticleSystemSceneNode* node = new CParticleSystemSceneNode(withDefaultEmitter,\r
907                 parent, this, id, position, rotation, scale);\r
908         node->drop();\r
909 \r
910         return node;\r
911 #else\r
912         return 0;\r
913 #endif // _IRR_COMPILE_WITH_PARTICLES_\r
914 }\r
915 \r
916 \r
917 //! Adds a terrain scene node to the scene graph.\r
918 ITerrainSceneNode* CSceneManager::addTerrainSceneNode(\r
919         const io::path& heightMapFileName,\r
920         ISceneNode* parent, s32 id,\r
921         const core::vector3df& position,\r
922         const core::vector3df& rotation,\r
923         const core::vector3df& scale,\r
924         video::SColor vertexColor,\r
925         s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, s32 smoothFactor,\r
926         bool addAlsoIfHeightmapEmpty)\r
927 {\r
928         io::IReadFile* file = FileSystem->createAndOpenFile(heightMapFileName);\r
929 \r
930         if (!file && !addAlsoIfHeightmapEmpty)\r
931         {\r
932                 os::Printer::log("Could not load terrain, because file could not be opened.",\r
933                 heightMapFileName, ELL_ERROR);\r
934                 return 0;\r
935         }\r
936 \r
937         ITerrainSceneNode* terrain = addTerrainSceneNode(file, parent, id,\r
938                 position, rotation, scale, vertexColor, maxLOD, patchSize,\r
939                 smoothFactor, addAlsoIfHeightmapEmpty);\r
940 \r
941         if (file)\r
942                 file->drop();\r
943 \r
944         return terrain;\r
945 }\r
946 \r
947 //! Adds a terrain scene node to the scene graph.\r
948 ITerrainSceneNode* CSceneManager::addTerrainSceneNode(\r
949         io::IReadFile* heightMapFile,\r
950         ISceneNode* parent, s32 id,\r
951         const core::vector3df& position,\r
952         const core::vector3df& rotation,\r
953         const core::vector3df& scale,\r
954         video::SColor vertexColor,\r
955         s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize,\r
956         s32 smoothFactor,\r
957         bool addAlsoIfHeightmapEmpty)\r
958 {\r
959 #ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
960         if (!parent)\r
961                 parent = this;\r
962 \r
963         if (!heightMapFile && !addAlsoIfHeightmapEmpty)\r
964         {\r
965                 os::Printer::log("Could not load terrain, because file could not be opened.", ELL_ERROR);\r
966                 return 0;\r
967         }\r
968 \r
969         CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id,\r
970                 maxLOD, patchSize, position, rotation, scale);\r
971 \r
972         if (!node->loadHeightMap(heightMapFile, vertexColor, smoothFactor))\r
973         {\r
974                 if (!addAlsoIfHeightmapEmpty)\r
975                 {\r
976                         node->remove();\r
977                         node->drop();\r
978                         return 0;\r
979                 }\r
980         }\r
981 \r
982         node->drop();\r
983         return node;\r
984 #else\r
985         return 0;\r
986 #endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
987 }\r
988 \r
989 \r
990 //! Adds an empty scene node.\r
991 ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id)\r
992 {\r
993         if (!parent)\r
994                 parent = this;\r
995 \r
996         ISceneNode* node = new CEmptySceneNode(parent, this, id);\r
997         node->drop();\r
998 \r
999         return node;\r
1000 }\r
1001 \r
1002 \r
1003 //! Adds a dummy transformation scene node to the scene graph.\r
1004 IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode(\r
1005         ISceneNode* parent, s32 id)\r
1006 {\r
1007         if (!parent)\r
1008                 parent = this;\r
1009 \r
1010         IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode(\r
1011                 parent, this, id);\r
1012         node->drop();\r
1013 \r
1014         return node;\r
1015 }\r
1016 \r
1017 //! Adds a Hill Plane mesh to the mesh pool. The mesh is generated on the fly\r
1018 //! and looks like a plane with some hills on it. You can specify how many hills\r
1019 //! there should be on the plane and how high they should be. Also you must\r
1020 //! specify a name for the mesh, because the mesh is added to the mesh pool,\r
1021 //! and can be retrieved again using ISceneManager::getMesh with the name as\r
1022 //! parameter.\r
1023 IAnimatedMesh* CSceneManager::addHillPlaneMesh(const io::path& name,\r
1024                 const core::dimension2d<f32>& tileSize,\r
1025                 const core::dimension2d<u32>& tileCount,\r
1026                 video::SMaterial* material, f32 hillHeight,\r
1027                 const core::dimension2d<f32>& countHills,\r
1028                 const core::dimension2d<f32>& textureRepeatCount)\r
1029 {\r
1030         if (MeshCache->isMeshLoaded(name))\r
1031                 return MeshCache->getMeshByName(name);\r
1032 \r
1033         IMesh* mesh = GeometryCreator->createHillPlaneMesh(tileSize,\r
1034                         tileCount, material, hillHeight, countHills,\r
1035                         textureRepeatCount);\r
1036         if (!mesh)\r
1037                 return 0;\r
1038 \r
1039         SAnimatedMesh* animatedMesh = new SAnimatedMesh();\r
1040         if (!animatedMesh)\r
1041         {\r
1042                 mesh->drop();\r
1043                 return 0;\r
1044         }\r
1045 \r
1046         animatedMesh->addMesh(mesh);\r
1047         mesh->drop();\r
1048         animatedMesh->recalculateBoundingBox();\r
1049 \r
1050         MeshCache->addMesh(name, animatedMesh);\r
1051         animatedMesh->drop();\r
1052 \r
1053         return animatedMesh;\r
1054 }\r
1055 \r
1056 \r
1057 //! Adds a terrain mesh to the mesh pool.\r
1058 IAnimatedMesh* CSceneManager::addTerrainMesh(const io::path& name,\r
1059         video::IImage* texture, video::IImage* heightmap,\r
1060         const core::dimension2d<f32>& stretchSize,\r
1061         f32 maxHeight,\r
1062         const core::dimension2d<u32>& defaultVertexBlockSize)\r
1063 {\r
1064         if (MeshCache->isMeshLoaded(name))\r
1065                 return MeshCache->getMeshByName(name);\r
1066 \r
1067         const bool debugBorders=false;\r
1068         IMesh* mesh = GeometryCreator->createTerrainMesh(texture, heightmap,\r
1069                         stretchSize, maxHeight, Driver,\r
1070                         defaultVertexBlockSize, debugBorders);\r
1071         if (!mesh)\r
1072                 return 0;\r
1073 \r
1074         SAnimatedMesh* animatedMesh = new SAnimatedMesh();\r
1075         if (!animatedMesh)\r
1076         {\r
1077                 mesh->drop();\r
1078                 return 0;\r
1079         }\r
1080 \r
1081         animatedMesh->addMesh(mesh);\r
1082         mesh->drop();\r
1083         animatedMesh->recalculateBoundingBox();\r
1084 \r
1085         MeshCache->addMesh(name, animatedMesh);\r
1086         animatedMesh->drop();\r
1087 \r
1088         return animatedMesh;\r
1089 }\r
1090 \r
1091 \r
1092 //! Adds an arrow mesh to the mesh pool.\r
1093 IAnimatedMesh* CSceneManager::addArrowMesh(const io::path& name,\r
1094                 video::SColor vtxColor0, video::SColor vtxColor1,\r
1095                 u32 tesselationCylinder, u32 tesselationCone, f32 height,\r
1096                 f32 cylinderHeight, f32 width0,f32 width1)\r
1097 {\r
1098         if (MeshCache->isMeshLoaded(name))\r
1099                 return MeshCache->getMeshByName(name);\r
1100 \r
1101         IMesh* mesh = GeometryCreator->createArrowMesh( tesselationCylinder,\r
1102                         tesselationCone, height, cylinderHeight, width0,width1,\r
1103                         vtxColor0, vtxColor1);\r
1104         if (!mesh)\r
1105                 return 0;\r
1106 \r
1107         SAnimatedMesh* animatedMesh = new SAnimatedMesh();\r
1108         if (!animatedMesh)\r
1109         {\r
1110                 mesh->drop();\r
1111                 return 0;\r
1112         }\r
1113 \r
1114         animatedMesh->addMesh(mesh);\r
1115         mesh->drop();\r
1116         animatedMesh->recalculateBoundingBox();\r
1117 \r
1118         MeshCache->addMesh(name, animatedMesh);\r
1119         animatedMesh->drop();\r
1120 \r
1121         return animatedMesh;\r
1122 }\r
1123 \r
1124 \r
1125 //! Adds a static sphere mesh to the mesh pool.\r
1126 IAnimatedMesh* CSceneManager::addSphereMesh(const io::path& name,\r
1127                 f32 radius, u32 polyCountX, u32 polyCountY)\r
1128 {\r
1129         if (MeshCache->isMeshLoaded(name))\r
1130                 return MeshCache->getMeshByName(name);\r
1131 \r
1132         IMesh* mesh = GeometryCreator->createSphereMesh(radius, polyCountX, polyCountY);\r
1133         if (!mesh)\r
1134                 return 0;\r
1135 \r
1136         SAnimatedMesh* animatedMesh = new SAnimatedMesh();\r
1137         if (!animatedMesh)\r
1138         {\r
1139                 mesh->drop();\r
1140                 return 0;\r
1141         }\r
1142 \r
1143         animatedMesh->addMesh(mesh);\r
1144         mesh->drop();\r
1145         animatedMesh->recalculateBoundingBox();\r
1146 \r
1147         MeshCache->addMesh(name, animatedMesh);\r
1148         animatedMesh->drop();\r
1149 \r
1150         return animatedMesh;\r
1151 }\r
1152 \r
1153 \r
1154 \r
1155 //! Adds a static volume light mesh to the mesh pool.\r
1156 IAnimatedMesh* CSceneManager::addVolumeLightMesh(const io::path& name,\r
1157                 const u32 SubdivideU, const u32 SubdivideV,\r
1158                 const video::SColor FootColor, const video::SColor TailColor)\r
1159 {\r
1160         if (MeshCache->isMeshLoaded(name))\r
1161                 return MeshCache->getMeshByName(name);\r
1162 \r
1163         IMesh* mesh = GeometryCreator->createVolumeLightMesh(SubdivideU, SubdivideV, FootColor, TailColor);\r
1164         if (!mesh)\r
1165                 return 0;\r
1166 \r
1167         SAnimatedMesh* animatedMesh = new SAnimatedMesh();\r
1168         if (!animatedMesh)\r
1169         {\r
1170                 mesh->drop();\r
1171                 return 0;\r
1172         }\r
1173 \r
1174         animatedMesh->addMesh(mesh);\r
1175         mesh->drop();\r
1176         animatedMesh->recalculateBoundingBox();\r
1177 \r
1178         MeshCache->addMesh(name, animatedMesh);\r
1179         animatedMesh->drop();\r
1180 \r
1181         return animatedMesh;\r
1182 }\r
1183 \r
1184 \r
1185 //! Returns the root scene node. This is the scene node which is parent\r
1186 //! of all scene nodes. The root scene node is a special scene node which\r
1187 //! only exists to manage all scene nodes. It is not rendered and cannot\r
1188 //! be removed from the scene.\r
1189 //! \return Returns a pointer to the root scene node.\r
1190 ISceneNode* CSceneManager::getRootSceneNode()\r
1191 {\r
1192         return this;\r
1193 }\r
1194 \r
1195 \r
1196 //! Returns the current active camera.\r
1197 //! \return The active camera is returned. Note that this can be NULL, if there\r
1198 //! was no camera created yet.\r
1199 ICameraSceneNode* CSceneManager::getActiveCamera() const\r
1200 {\r
1201         return ActiveCamera;\r
1202 }\r
1203 \r
1204 \r
1205 //! Sets the active camera. The previous active camera will be deactivated.\r
1206 //! \param camera: The new camera which should be active.\r
1207 void CSceneManager::setActiveCamera(ICameraSceneNode* camera)\r
1208 {\r
1209         if (camera)\r
1210                 camera->grab();\r
1211         if (ActiveCamera)\r
1212                 ActiveCamera->drop();\r
1213 \r
1214         ActiveCamera = camera;\r
1215 }\r
1216 \r
1217 \r
1218 //! renders the node.\r
1219 void CSceneManager::render()\r
1220 {\r
1221 }\r
1222 \r
1223 \r
1224 //! returns the axis aligned bounding box of this node\r
1225 const core::aabbox3d<f32>& CSceneManager::getBoundingBox() const\r
1226 {\r
1227         _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.\r
1228 \r
1229         static const core::aabbox3d<f32> dummy;\r
1230         return dummy;\r
1231 }\r
1232 \r
1233 \r
1234 //! returns if node is culled\r
1235 bool CSceneManager::isCulled(const ISceneNode* node) const\r
1236 {\r
1237         const ICameraSceneNode* cam = getActiveCamera();\r
1238         if (!cam)\r
1239         {\r
1240                 return false;\r
1241         }\r
1242         bool result = false;\r
1243 \r
1244         // has occlusion query information\r
1245         if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY)\r
1246         {\r
1247                 result = (Driver->getOcclusionQueryResult(const_cast<ISceneNode*>(node))==0);\r
1248         }\r
1249 \r
1250         // can be seen by a bounding box ?\r
1251         if (!result && (node->getAutomaticCulling() & scene::EAC_BOX))\r
1252         {\r
1253                 core::aabbox3d<f32> tbox = node->getBoundingBox();\r
1254                 node->getAbsoluteTransformation().transformBoxEx(tbox);\r
1255                 result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() ));\r
1256         }\r
1257 \r
1258         // can be seen by a bounding sphere\r
1259         if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE))\r
1260         {\r
1261                 const core::aabbox3df nbox = node->getTransformedBoundingBox();\r
1262                 const float rad = nbox.getRadius();\r
1263                 const core::vector3df center = nbox.getCenter();\r
1264 \r
1265                 const float camrad = cam->getViewFrustum()->getBoundingRadius();\r
1266                 const core::vector3df camcenter = cam->getViewFrustum()->getBoundingCenter();\r
1267 \r
1268                 const float dist = (center - camcenter).getLengthSQ();\r
1269                 const float maxdist = (rad + camrad) * (rad + camrad);\r
1270 \r
1271                 result = dist > maxdist;\r
1272         }\r
1273 \r
1274         // can be seen by cam pyramid planes ?\r
1275         if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX))\r
1276         {\r
1277                 SViewFrustum frust = *cam->getViewFrustum();\r
1278 \r
1279                 //transform the frustum to the node's current absolute transformation\r
1280                 core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE);\r
1281                 //invTrans.makeInverse();\r
1282                 frust.transform(invTrans);\r
1283 \r
1284                 core::vector3df edges[8];\r
1285                 node->getBoundingBox().getEdges(edges);\r
1286 \r
1287                 for (s32 i=0; i<scene::SViewFrustum::VF_PLANE_COUNT; ++i)\r
1288                 {\r
1289                         bool boxInFrustum=false;\r
1290                         for (u32 j=0; j<8; ++j)\r
1291                         {\r
1292                                 if (frust.planes[i].classifyPointRelation(edges[j]) != core::ISREL3D_FRONT)\r
1293                                 {\r
1294                                         boxInFrustum=true;\r
1295                                         break;\r
1296                                 }\r
1297                         }\r
1298 \r
1299                         if (!boxInFrustum)\r
1300                         {\r
1301                                 result = true;\r
1302                                 break;\r
1303                         }\r
1304                 }\r
1305         }\r
1306 \r
1307         return result;\r
1308 }\r
1309 \r
1310 \r
1311 //! registers a node for rendering it at a specific time.\r
1312 u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass)\r
1313 {\r
1314         IRR_PROFILE(CProfileScope p1(EPID_SM_REGISTER);)\r
1315         u32 taken = 0;\r
1316 \r
1317         switch(pass)\r
1318         {\r
1319                 // take camera if it is not already registered\r
1320         case ESNRP_CAMERA:\r
1321                 {\r
1322                         taken = 1;\r
1323                         for (u32 i = 0; i != CameraList.size(); ++i)\r
1324                         {\r
1325                                 if (CameraList[i] == node)\r
1326                                 {\r
1327                                         taken = 0;\r
1328                                         break;\r
1329                                 }\r
1330                         }\r
1331                         if (taken)\r
1332                         {\r
1333                                 CameraList.push_back(node);\r
1334                         }\r
1335                 }\r
1336                 break;\r
1337 \r
1338         case ESNRP_LIGHT:\r
1339                 // TODO: Point Light culling..\r
1340                 // Lighting model in irrlicht has to be redone..\r
1341                 //if (!isCulled(node))\r
1342                 {\r
1343                         LightList.push_back(node);\r
1344                         taken = 1;\r
1345                 }\r
1346                 break;\r
1347 \r
1348         case ESNRP_SKY_BOX:\r
1349                 SkyBoxList.push_back(node);\r
1350                 taken = 1;\r
1351                 break;\r
1352         case ESNRP_SOLID:\r
1353                 if (!isCulled(node))\r
1354                 {\r
1355                         SolidNodeList.push_back(node);\r
1356                         taken = 1;\r
1357                 }\r
1358                 break;\r
1359         case ESNRP_TRANSPARENT:\r
1360                 if (!isCulled(node))\r
1361                 {\r
1362                         TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos));\r
1363                         taken = 1;\r
1364                 }\r
1365                 break;\r
1366         case ESNRP_TRANSPARENT_EFFECT:\r
1367                 if (!isCulled(node))\r
1368                 {\r
1369                         TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos));\r
1370                         taken = 1;\r
1371                 }\r
1372                 break;\r
1373         case ESNRP_AUTOMATIC:\r
1374                 if (!isCulled(node))\r
1375                 {\r
1376                         const u32 count = node->getMaterialCount();\r
1377 \r
1378                         taken = 0;\r
1379                         for (u32 i=0; i<count; ++i)\r
1380                         {\r
1381                                 if (Driver->needsTransparentRenderPass(node->getMaterial(i)))\r
1382                                 {\r
1383                                         // register as transparent node\r
1384                                         TransparentNodeEntry e(node, camWorldPos);\r
1385                                         TransparentNodeList.push_back(e);\r
1386                                         taken = 1;\r
1387                                         break;\r
1388                                 }\r
1389                         }\r
1390 \r
1391                         // not transparent, register as solid\r
1392                         if (!taken)\r
1393                         {\r
1394                                 SolidNodeList.push_back(node);\r
1395                                 taken = 1;\r
1396                         }\r
1397                 }\r
1398                 break;\r
1399         case ESNRP_SHADOW:\r
1400                 if (!isCulled(node))\r
1401                 {\r
1402                         ShadowNodeList.push_back(node);\r
1403                         taken = 1;\r
1404                 }\r
1405                 break;\r
1406 \r
1407         case ESNRP_GUI:\r
1408                 if (!isCulled(node))\r
1409                 {\r
1410                         GuiNodeList.push_back(node);\r
1411                         taken = 1;\r
1412                 }\r
1413 \r
1414         case ESNRP_NONE: // ignore this one\r
1415                 break;\r
1416         }\r
1417 \r
1418 #ifdef _IRR_SCENEMANAGER_DEBUG\r
1419         s32 index = Parameters->findAttribute("calls");\r
1420         Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);\r
1421 \r
1422         if (!taken)\r
1423         {\r
1424                 index = Parameters->findAttribute("culled");\r
1425                 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);\r
1426         }\r
1427 #endif\r
1428 \r
1429         return taken;\r
1430 }\r
1431 \r
1432 void CSceneManager::clearAllRegisteredNodesForRendering()\r
1433 {\r
1434         CameraList.clear();\r
1435         LightList.clear();\r
1436         SkyBoxList.clear();\r
1437         SolidNodeList.clear();\r
1438         TransparentNodeList.clear();\r
1439         TransparentEffectNodeList.clear();\r
1440         ShadowNodeList.clear();\r
1441         GuiNodeList.clear();\r
1442 }\r
1443 \r
1444 //! This method is called just before the rendering process of the whole scene.\r
1445 //! draws all scene nodes\r
1446 void CSceneManager::drawAll()\r
1447 {\r
1448         IRR_PROFILE(CProfileScope psAll(EPID_SM_DRAW_ALL);)\r
1449 \r
1450         if (!Driver)\r
1451                 return;\r
1452 \r
1453 #ifdef _IRR_SCENEMANAGER_DEBUG\r
1454         // reset attributes\r
1455         Parameters->setAttribute("culled", 0);\r
1456         Parameters->setAttribute("calls", 0);\r
1457         Parameters->setAttribute("drawn_solid", 0);\r
1458         Parameters->setAttribute("drawn_transparent", 0);\r
1459         Parameters->setAttribute("drawn_transparent_effect", 0);\r
1460 #endif\r
1461 \r
1462         u32 i; // new ISO for scoping problem in some compilers\r
1463 \r
1464         // reset all transforms\r
1465         Driver->setMaterial(video::SMaterial());\r
1466         Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );\r
1467         Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );\r
1468         Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );\r
1469         for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i)\r
1470                 Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix );\r
1471         // TODO: This should not use an attribute here but a real parameter when necessary (too slow!)\r
1472         Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT));\r
1473 \r
1474         // do animations and other stuff.\r
1475         IRR_PROFILE(getProfiler().start(EPID_SM_ANIMATE));\r
1476         OnAnimate(os::Timer::getTime());\r
1477         IRR_PROFILE(getProfiler().stop(EPID_SM_ANIMATE));\r
1478 \r
1479         /*!\r
1480                 First Scene Node for prerendering should be the active camera\r
1481                 consistent Camera is needed for culling\r
1482         */\r
1483         IRR_PROFILE(getProfiler().start(EPID_SM_RENDER_CAMERAS));\r
1484         camWorldPos.set(0,0,0);\r
1485         if (ActiveCamera)\r
1486         {\r
1487                 ActiveCamera->render();\r
1488                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
1489         }\r
1490         IRR_PROFILE(getProfiler().stop(EPID_SM_RENDER_CAMERAS));\r
1491 \r
1492         // let all nodes register themselves\r
1493         OnRegisterSceneNode();\r
1494 \r
1495         if (LightManager)\r
1496                 LightManager->OnPreRender(LightList);\r
1497 \r
1498         //render camera scenes\r
1499         {\r
1500                 IRR_PROFILE(CProfileScope psCam(EPID_SM_RENDER_CAMERAS);)\r
1501                 CurrentRenderPass = ESNRP_CAMERA;\r
1502                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1503 \r
1504                 if (LightManager)\r
1505                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1506 \r
1507                 for (i=0; i<CameraList.size(); ++i)\r
1508                         CameraList[i]->render();\r
1509 \r
1510                 CameraList.set_used(0);\r
1511 \r
1512                 if (LightManager)\r
1513                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
1514         }\r
1515 \r
1516         //render lights scenes\r
1517         {\r
1518                 IRR_PROFILE(CProfileScope psLights(EPID_SM_RENDER_LIGHTS);)\r
1519                 CurrentRenderPass = ESNRP_LIGHT;\r
1520                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1521 \r
1522                 if (LightManager)\r
1523                 {\r
1524                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1525                 }\r
1526                 else\r
1527                 {\r
1528                         // Sort the lights by distance from the camera\r
1529                         core::vector3df camWorldPos(0, 0, 0);\r
1530                         if (ActiveCamera)\r
1531                                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
1532 \r
1533                         core::array<DistanceNodeEntry> SortedLights;\r
1534                         SortedLights.set_used(LightList.size());\r
1535                         for (s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
1536                                 SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos);\r
1537 \r
1538                         SortedLights.set_sorted(false);\r
1539                         SortedLights.sort();\r
1540 \r
1541                         for(s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
1542                                 LightList[light] = SortedLights[light].Node;\r
1543                 }\r
1544 \r
1545                 Driver->deleteAllDynamicLights();\r
1546 \r
1547                 Driver->setAmbientLight(AmbientLight);\r
1548 \r
1549                 u32 maxLights = LightList.size();\r
1550 \r
1551                 if (!LightManager)\r
1552                         maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights);\r
1553 \r
1554                 for (i=0; i< maxLights; ++i)\r
1555                         LightList[i]->render();\r
1556 \r
1557                 if (LightManager)\r
1558                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
1559         }\r
1560 \r
1561         // render skyboxes\r
1562         {\r
1563                 IRR_PROFILE(CProfileScope psSkyBox(EPID_SM_RENDER_SKYBOXES);)\r
1564                 CurrentRenderPass = ESNRP_SKY_BOX;\r
1565                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1566 \r
1567                 if (LightManager)\r
1568                 {\r
1569                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1570                         for (i=0; i<SkyBoxList.size(); ++i)\r
1571                         {\r
1572                                 ISceneNode* node = SkyBoxList[i];\r
1573                                 LightManager->OnNodePreRender(node);\r
1574                                 node->render();\r
1575                                 LightManager->OnNodePostRender(node);\r
1576                         }\r
1577                 }\r
1578                 else\r
1579                 {\r
1580                         for (i=0; i<SkyBoxList.size(); ++i)\r
1581                                 SkyBoxList[i]->render();\r
1582                 }\r
1583 \r
1584                 SkyBoxList.set_used(0);\r
1585 \r
1586                 if (LightManager)\r
1587                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
1588         }\r
1589 \r
1590 \r
1591         // render default objects\r
1592         {\r
1593                 IRR_PROFILE(CProfileScope psDefault(EPID_SM_RENDER_DEFAULT);)\r
1594                 CurrentRenderPass = ESNRP_SOLID;\r
1595                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1596 \r
1597                 SolidNodeList.sort(); // sort by textures\r
1598 \r
1599                 if (LightManager)\r
1600                 {\r
1601                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1602                         for (i=0; i<SolidNodeList.size(); ++i)\r
1603                         {\r
1604                                 ISceneNode* node = SolidNodeList[i].Node;\r
1605                                 LightManager->OnNodePreRender(node);\r
1606                                 node->render();\r
1607                                 LightManager->OnNodePostRender(node);\r
1608                         }\r
1609                 }\r
1610                 else\r
1611                 {\r
1612                         for (i=0; i<SolidNodeList.size(); ++i)\r
1613                                 SolidNodeList[i].Node->render();\r
1614                 }\r
1615 \r
1616 #ifdef _IRR_SCENEMANAGER_DEBUG\r
1617                 Parameters->setAttribute("drawn_solid", (s32) SolidNodeList.size() );\r
1618 #endif\r
1619                 SolidNodeList.set_used(0);\r
1620 \r
1621                 if (LightManager)\r
1622                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
1623         }\r
1624 \r
1625         // render shadows\r
1626         {\r
1627                 IRR_PROFILE(CProfileScope psShadow(EPID_SM_RENDER_SHADOWS);)\r
1628                 CurrentRenderPass = ESNRP_SHADOW;\r
1629                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1630 \r
1631                 if (LightManager)\r
1632                 {\r
1633                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1634                         for (i=0; i<ShadowNodeList.size(); ++i)\r
1635                         {\r
1636                                 ISceneNode* node = ShadowNodeList[i];\r
1637                                 LightManager->OnNodePreRender(node);\r
1638                                 node->render();\r
1639                                 LightManager->OnNodePostRender(node);\r
1640                         }\r
1641                 }\r
1642                 else\r
1643                 {\r
1644                         for (i=0; i<ShadowNodeList.size(); ++i)\r
1645                                 ShadowNodeList[i]->render();\r
1646                 }\r
1647 \r
1648                 if (!ShadowNodeList.empty())\r
1649                         Driver->drawStencilShadow(true,ShadowColor, ShadowColor,\r
1650                                 ShadowColor, ShadowColor);\r
1651 \r
1652                 ShadowNodeList.set_used(0);\r
1653 \r
1654                 if (LightManager)\r
1655                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
1656         }\r
1657 \r
1658         // render transparent objects.\r
1659         {\r
1660                 IRR_PROFILE(CProfileScope psTrans(EPID_SM_RENDER_TRANSPARENT);)\r
1661                 CurrentRenderPass = ESNRP_TRANSPARENT;\r
1662                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1663 \r
1664                 TransparentNodeList.sort(); // sort by distance from camera\r
1665                 if (LightManager)\r
1666                 {\r
1667                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1668 \r
1669                         for (i=0; i<TransparentNodeList.size(); ++i)\r
1670                         {\r
1671                                 ISceneNode* node = TransparentNodeList[i].Node;\r
1672                                 LightManager->OnNodePreRender(node);\r
1673                                 node->render();\r
1674                                 LightManager->OnNodePostRender(node);\r
1675                         }\r
1676                 }\r
1677                 else\r
1678                 {\r
1679                         for (i=0; i<TransparentNodeList.size(); ++i)\r
1680                                 TransparentNodeList[i].Node->render();\r
1681                 }\r
1682 \r
1683 #ifdef _IRR_SCENEMANAGER_DEBUG\r
1684                 Parameters->setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() );\r
1685 #endif\r
1686                 TransparentNodeList.set_used(0);\r
1687 \r
1688                 if (LightManager)\r
1689                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
1690         }\r
1691 \r
1692         // render transparent effect objects.\r
1693         {\r
1694                 IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_EFFECT);)\r
1695                 CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT;\r
1696                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1697 \r
1698                 TransparentEffectNodeList.sort(); // sort by distance from camera\r
1699 \r
1700                 if (LightManager)\r
1701                 {\r
1702                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1703 \r
1704                         for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
1705                         {\r
1706                                 ISceneNode* node = TransparentEffectNodeList[i].Node;\r
1707                                 LightManager->OnNodePreRender(node);\r
1708                                 node->render();\r
1709                                 LightManager->OnNodePostRender(node);\r
1710                         }\r
1711                 }\r
1712                 else\r
1713                 {\r
1714                         for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
1715                                 TransparentEffectNodeList[i].Node->render();\r
1716                 }\r
1717 #ifdef _IRR_SCENEMANAGER_DEBUG\r
1718                 Parameters->setAttribute("drawn_transparent_effect", (s32) TransparentEffectNodeList.size());\r
1719 #endif\r
1720                 TransparentEffectNodeList.set_used(0);\r
1721         }\r
1722 \r
1723         // render custom gui nodes\r
1724         {\r
1725                 IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_GUI_NODES);)\r
1726                 CurrentRenderPass = ESNRP_GUI;\r
1727                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
1728 \r
1729                 if (LightManager)\r
1730                 {\r
1731                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
1732 \r
1733                         for (i=0; i<GuiNodeList.size(); ++i)\r
1734                         {\r
1735                                 ISceneNode* node = GuiNodeList[i];\r
1736                                 LightManager->OnNodePreRender(node);\r
1737                                 node->render();\r
1738                                 LightManager->OnNodePostRender(node);\r
1739                         }\r
1740                 }\r
1741                 else\r
1742                 {\r
1743                         for (i=0; i<GuiNodeList.size(); ++i)\r
1744                                 GuiNodeList[i]->render();\r
1745                 }\r
1746 #ifdef _IRR_SCENEMANAGER_DEBUG\r
1747                 Parameters->setAttribute("drawn_gui_nodes", (s32) GuiNodeList.size());\r
1748 #endif\r
1749                 GuiNodeList.set_used(0);\r
1750         }\r
1751         \r
1752 \r
1753         if (LightManager)\r
1754                 LightManager->OnPostRender();\r
1755 \r
1756         LightList.set_used(0);\r
1757         clearDeletionList();\r
1758 \r
1759         CurrentRenderPass = ESNRP_NONE;\r
1760 }\r
1761 \r
1762 void CSceneManager::setLightManager(ILightManager* lightManager)\r
1763 {\r
1764         if (lightManager)\r
1765                 lightManager->grab();\r
1766         if (LightManager)\r
1767                 LightManager->drop();\r
1768 \r
1769         LightManager = lightManager;\r
1770 }\r
1771 \r
1772 \r
1773 //! Sets the color of stencil buffers shadows drawn by the scene manager.\r
1774 void CSceneManager::setShadowColor(video::SColor color)\r
1775 {\r
1776         ShadowColor = color;\r
1777 }\r
1778 \r
1779 \r
1780 //! Returns the current color of shadows.\r
1781 video::SColor CSceneManager::getShadowColor() const\r
1782 {\r
1783         return ShadowColor;\r
1784 }\r
1785 \r
1786 IShadowVolumeSceneNode* CSceneManager::createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity)\r
1787 {\r
1788 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
1789         return new CShadowVolumeSceneNode(shadowMesh, parent, this, id, zfailmethod, infinity);\r
1790 #else\r
1791         return 0;\r
1792 #endif\r
1793 }\r
1794 \r
1795 \r
1796 \r
1797 //! creates a rotation animator, which rotates the attached scene node around itself.\r
1798 ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& rotationPerSecond)\r
1799 {\r
1800         ISceneNodeAnimator* anim = new CSceneNodeAnimatorRotation(os::Timer::getTime(),\r
1801                 rotationPerSecond);\r
1802 \r
1803         return anim;\r
1804 }\r
1805 \r
1806 \r
1807 //! creates a fly circle animator, which lets the attached scene node fly around a center.\r
1808 ISceneNodeAnimator* CSceneManager::createFlyCircleAnimator(\r
1809                 const core::vector3df& center, f32 radius, f32 speed,\r
1810                 const core::vector3df& direction,\r
1811                 f32 startPosition,\r
1812                 f32 radiusEllipsoid)\r
1813 {\r
1814         const f32 orbitDurationMs = (core::DEGTORAD * 360.f) / speed;\r
1815         const u32 effectiveTime = os::Timer::getTime() + (u32)(orbitDurationMs * startPosition);\r
1816 \r
1817         ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle(\r
1818                         effectiveTime, center,\r
1819                         radius, speed, direction,radiusEllipsoid);\r
1820         return anim;\r
1821 }\r
1822 \r
1823 \r
1824 //! Creates a fly straight animator, which lets the attached scene node\r
1825 //! fly or move along a line between two points.\r
1826 ISceneNodeAnimator* CSceneManager::createFlyStraightAnimator(const core::vector3df& startPoint,\r
1827                                         const core::vector3df& endPoint, u32 timeForWay, bool loop,bool pingpong)\r
1828 {\r
1829         ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyStraight(startPoint,\r
1830                 endPoint, timeForWay, loop, os::Timer::getTime(), pingpong);\r
1831 \r
1832         return anim;\r
1833 }\r
1834 \r
1835 \r
1836 //! Creates a texture animator, which switches the textures of the target scene\r
1837 //! node based on a list of textures.\r
1838 ISceneNodeAnimator* CSceneManager::createTextureAnimator(const core::array<video::ITexture*>& textures,\r
1839         s32 timePerFrame, bool loop)\r
1840 {\r
1841         ISceneNodeAnimator* anim = new CSceneNodeAnimatorTexture(textures,\r
1842                 timePerFrame, loop, os::Timer::getTime());\r
1843 \r
1844         return anim;\r
1845 }\r
1846 \r
1847 \r
1848 //! Creates a scene node animator, which deletes the scene node after\r
1849 //! some time automatically.\r
1850 ISceneNodeAnimator* CSceneManager::createDeleteAnimator(u32 when)\r
1851 {\r
1852         return new CSceneNodeAnimatorDelete(this, os::Timer::getTime() + when);\r
1853 }\r
1854 \r
1855 \r
1856 //! Creates a special scene node animator for doing automatic collision detection\r
1857 //! and response.\r
1858 ISceneNodeAnimatorCollisionResponse* CSceneManager::createCollisionResponseAnimator(\r
1859         ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius,\r
1860         const core::vector3df& gravityPerSecond,\r
1861         const core::vector3df& ellipsoidTranslation, f32 slidingValue)\r
1862 {\r
1863         ISceneNodeAnimatorCollisionResponse* anim = new\r
1864                 CSceneNodeAnimatorCollisionResponse(this, world, sceneNode,\r
1865                         ellipsoidRadius, gravityPerSecond,\r
1866                         ellipsoidTranslation, slidingValue);\r
1867 \r
1868         return anim;\r
1869 }\r
1870 \r
1871 \r
1872 //! Creates a follow spline animator.\r
1873 ISceneNodeAnimator* CSceneManager::createFollowSplineAnimator(s32 startTime,\r
1874         const core::array< core::vector3df >& points,\r
1875         f32 speed, f32 tightness, bool loop, bool pingpong)\r
1876 {\r
1877         ISceneNodeAnimator* a = new CSceneNodeAnimatorFollowSpline(startTime, points,\r
1878                 speed, tightness, loop, pingpong);\r
1879         return a;\r
1880 }\r
1881 \r
1882 \r
1883 //! Adds an external mesh loader.\r
1884 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)\r
1885 {\r
1886         if (!externalLoader)\r
1887                 return;\r
1888 \r
1889         externalLoader->grab();\r
1890         MeshLoaderList.push_back(externalLoader);\r
1891 }\r
1892 \r
1893 \r
1894 //! Returns the number of mesh loaders supported by Irrlicht at this time\r
1895 u32 CSceneManager::getMeshLoaderCount() const\r
1896 {\r
1897         return MeshLoaderList.size();\r
1898 }\r
1899 \r
1900 \r
1901 //! Retrieve the given mesh loader\r
1902 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const\r
1903 {\r
1904         if (index < MeshLoaderList.size())\r
1905                 return MeshLoaderList[index];\r
1906         else\r
1907                 return 0;\r
1908 }\r
1909 \r
1910 \r
1911 //! Adds an external scene loader.\r
1912 void CSceneManager::addExternalSceneLoader(ISceneLoader* externalLoader)\r
1913 {\r
1914         if (!externalLoader)\r
1915                 return;\r
1916 \r
1917         externalLoader->grab();\r
1918         SceneLoaderList.push_back(externalLoader);\r
1919 }\r
1920 \r
1921 \r
1922 //! Returns the number of scene loaders\r
1923 u32 CSceneManager::getSceneLoaderCount() const\r
1924 {\r
1925         return SceneLoaderList.size();\r
1926 }\r
1927 \r
1928 \r
1929 //! Retrieve the given scene loader\r
1930 ISceneLoader* CSceneManager::getSceneLoader(u32 index) const\r
1931 {\r
1932         if (index < SceneLoaderList.size())\r
1933                 return SceneLoaderList[index];\r
1934         else\r
1935                 return 0;\r
1936 }\r
1937 \r
1938 \r
1939 //! Returns a pointer to the scene collision manager.\r
1940 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()\r
1941 {\r
1942         return CollisionManager;\r
1943 }\r
1944 \r
1945 \r
1946 //! Returns a pointer to the mesh manipulator.\r
1947 IMeshManipulator* CSceneManager::getMeshManipulator()\r
1948 {\r
1949         return Driver->getMeshManipulator();\r
1950 }\r
1951 \r
1952 \r
1953 //! Creates a simple ITriangleSelector, based on a mesh.\r
1954 ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers)\r
1955 {\r
1956         if (!mesh)\r
1957                 return 0;\r
1958 \r
1959         return new CTriangleSelector(mesh, node, separateMeshbuffers);\r
1960 }\r
1961 \r
1962 ITriangleSelector* CSceneManager::createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node)\r
1963 {\r
1964         if ( !meshBuffer)\r
1965                 return 0;\r
1966         return new  CTriangleSelector(meshBuffer, materialIndex, node);\r
1967 }\r
1968 \r
1969 \r
1970 //! Creates a ITriangleSelector, based on a the mesh owned by an animated scene node\r
1971 ITriangleSelector* CSceneManager::createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers)\r
1972 {\r
1973         if (!node || !node->getMesh())\r
1974                 return 0;\r
1975 \r
1976         return new CTriangleSelector(node, separateMeshbuffers);\r
1977 }\r
1978 \r
1979 \r
1980 //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box.\r
1981 ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node)\r
1982 {\r
1983         if (!node)\r
1984                 return 0;\r
1985 \r
1986         return new CTriangleBBSelector(node);\r
1987 }\r
1988 \r
1989 \r
1990 //! Creates a simple ITriangleSelector, based on a mesh.\r
1991 ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMesh* mesh,\r
1992                                                         ISceneNode* node, s32 minimalPolysPerNode)\r
1993 {\r
1994         if (!mesh)\r
1995                 return 0;\r
1996 \r
1997         return new COctreeTriangleSelector(mesh, node, minimalPolysPerNode);\r
1998 }\r
1999 \r
2000 ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex,\r
2001                         ISceneNode* node, s32 minimalPolysPerNode)\r
2002 {\r
2003         if ( !meshBuffer)\r
2004                 return 0;\r
2005 \r
2006         return new COctreeTriangleSelector(meshBuffer, materialIndex, node, minimalPolysPerNode);\r
2007 }\r
2008 \r
2009 //! Creates a meta triangle selector.\r
2010 IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector()\r
2011 {\r
2012         return new CMetaTriangleSelector();\r
2013 }\r
2014 \r
2015 \r
2016 //! Creates a triangle selector which can select triangles from a terrain scene node\r
2017 ITriangleSelector* CSceneManager::createTerrainTriangleSelector(\r
2018         ITerrainSceneNode* node, s32 LOD)\r
2019 {\r
2020 #ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_\r
2021         return new CTerrainTriangleSelector(node, LOD);\r
2022 #else\r
2023         return 0;\r
2024 #endif\r
2025 }\r
2026 \r
2027 \r
2028 \r
2029 //! Adds a scene node to the deletion queue.\r
2030 void CSceneManager::addToDeletionQueue(ISceneNode* node)\r
2031 {\r
2032         if (!node)\r
2033                 return;\r
2034 \r
2035         node->grab();\r
2036         DeletionList.push_back(node);\r
2037 }\r
2038 \r
2039 \r
2040 //! clears the deletion list\r
2041 void CSceneManager::clearDeletionList()\r
2042 {\r
2043         if (DeletionList.empty())\r
2044                 return;\r
2045 \r
2046         for (u32 i=0; i<DeletionList.size(); ++i)\r
2047         {\r
2048                 DeletionList[i]->remove();\r
2049                 DeletionList[i]->drop();\r
2050         }\r
2051 \r
2052         DeletionList.clear();\r
2053 }\r
2054 \r
2055 \r
2056 //! Returns the first scene node with the specified name.\r
2057 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)\r
2058 {\r
2059         if (start == 0)\r
2060                 start = getRootSceneNode();\r
2061 \r
2062         if (!strcmp(start->getName(),name))\r
2063                 return start;\r
2064 \r
2065         ISceneNode* node = 0;\r
2066 \r
2067         const ISceneNodeList& list = start->getChildren();\r
2068         ISceneNodeList::ConstIterator it = list.begin();\r
2069         for (; it!=list.end(); ++it)\r
2070         {\r
2071                 node = getSceneNodeFromName(name, *it);\r
2072                 if (node)\r
2073                         return node;\r
2074         }\r
2075 \r
2076         return 0;\r
2077 }\r
2078 \r
2079 \r
2080 //! Returns the first scene node with the specified id.\r
2081 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)\r
2082 {\r
2083         if (start == 0)\r
2084                 start = getRootSceneNode();\r
2085 \r
2086         if (start->getID() == id)\r
2087                 return start;\r
2088 \r
2089         ISceneNode* node = 0;\r
2090 \r
2091         const ISceneNodeList& list = start->getChildren();\r
2092         ISceneNodeList::ConstIterator it = list.begin();\r
2093         for (; it!=list.end(); ++it)\r
2094         {\r
2095                 node = getSceneNodeFromId(id, *it);\r
2096                 if (node)\r
2097                         return node;\r
2098         }\r
2099 \r
2100         return 0;\r
2101 }\r
2102 \r
2103 \r
2104 //! Returns the first scene node with the specified type.\r
2105 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)\r
2106 {\r
2107         if (start == 0)\r
2108                 start = getRootSceneNode();\r
2109 \r
2110         if (start->getType() == type || ESNT_ANY == type)\r
2111                 return start;\r
2112 \r
2113         ISceneNode* node = 0;\r
2114 \r
2115         const ISceneNodeList& list = start->getChildren();\r
2116         ISceneNodeList::ConstIterator it = list.begin();\r
2117         for (; it!=list.end(); ++it)\r
2118         {\r
2119                 node = getSceneNodeFromType(type, *it);\r
2120                 if (node)\r
2121                         return node;\r
2122         }\r
2123 \r
2124         return 0;\r
2125 }\r
2126 \r
2127 \r
2128 //! returns scene nodes by type.\r
2129 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)\r
2130 {\r
2131         if (start == 0)\r
2132                 start = getRootSceneNode();\r
2133 \r
2134         if (start->getType() == type || ESNT_ANY == type)\r
2135                 outNodes.push_back(start);\r
2136 \r
2137         const ISceneNodeList& list = start->getChildren();\r
2138         ISceneNodeList::ConstIterator it = list.begin();\r
2139 \r
2140         for (; it!=list.end(); ++it)\r
2141         {\r
2142                 getSceneNodesFromType(type, outNodes, *it);\r
2143         }\r
2144 }\r
2145 \r
2146 \r
2147 //! Posts an input event to the environment. Usually you do not have to\r
2148 //! use this method, it is used by the internal engine.\r
2149 bool CSceneManager::postEventFromUser(const SEvent& event)\r
2150 {\r
2151         bool ret = false;\r
2152         ICameraSceneNode* cam = getActiveCamera();\r
2153         if (cam)\r
2154                 ret = cam->OnEvent(event);\r
2155 \r
2156         return ret;\r
2157 }\r
2158 \r
2159 \r
2160 //! Removes all children of this scene node\r
2161 void CSceneManager::removeAll()\r
2162 {\r
2163         ISceneNode::removeAll();\r
2164         setActiveCamera(0);\r
2165         // Make sure the driver is reset, might need a more complex method at some point\r
2166         if (Driver)\r
2167                 Driver->setMaterial(video::SMaterial());\r
2168 }\r
2169 \r
2170 \r
2171 //! Clears the whole scene. All scene nodes are removed.\r
2172 void CSceneManager::clear()\r
2173 {\r
2174         removeAll();\r
2175 }\r
2176 \r
2177 \r
2178 //! Returns interface to the parameters set in this scene.\r
2179 io::IAttributes* CSceneManager::getParameters()\r
2180 {\r
2181         return Parameters;\r
2182 }\r
2183 \r
2184 \r
2185 //! Returns current render pass.\r
2186 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const\r
2187 {\r
2188         return CurrentRenderPass;\r
2189 }\r
2190 \r
2191 \r
2192 //! Returns an interface to the mesh cache which is shared between all existing scene managers.\r
2193 IMeshCache* CSceneManager::getMeshCache()\r
2194 {\r
2195         return MeshCache;\r
2196 }\r
2197 \r
2198 \r
2199 //! Creates a new scene manager.\r
2200 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)\r
2201 {\r
2202         CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment);\r
2203 \r
2204         if (cloneContent)\r
2205                 manager->cloneMembers(this, manager);\r
2206 \r
2207         return manager;\r
2208 }\r
2209 \r
2210 \r
2211 //! Returns the default scene node factory which can create all built in scene nodes\r
2212 ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory()\r
2213 {\r
2214         return getSceneNodeFactory(0);\r
2215 }\r
2216 \r
2217 \r
2218 //! Adds a scene node factory to the scene manager.\r
2219 void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd)\r
2220 {\r
2221         if (factoryToAdd)\r
2222         {\r
2223                 factoryToAdd->grab();\r
2224                 SceneNodeFactoryList.push_back(factoryToAdd);\r
2225         }\r
2226 }\r
2227 \r
2228 \r
2229 //! Returns amount of registered scene node factories.\r
2230 u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const\r
2231 {\r
2232         return SceneNodeFactoryList.size();\r
2233 }\r
2234 \r
2235 \r
2236 //! Returns a scene node factory by index\r
2237 ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index)\r
2238 {\r
2239         if (index < SceneNodeFactoryList.size())\r
2240                 return SceneNodeFactoryList[index];\r
2241 \r
2242         return 0;\r
2243 }\r
2244 \r
2245 \r
2246 //! Returns the default scene node animator factory which can create all built-in scene node animators\r
2247 ISceneNodeAnimatorFactory* CSceneManager::getDefaultSceneNodeAnimatorFactory()\r
2248 {\r
2249         return getSceneNodeAnimatorFactory(0);\r
2250 }\r
2251 \r
2252 //! Adds a scene node animator factory to the scene manager.\r
2253 void CSceneManager::registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd)\r
2254 {\r
2255         if (factoryToAdd)\r
2256         {\r
2257                 factoryToAdd->grab();\r
2258                 SceneNodeAnimatorFactoryList.push_back(factoryToAdd);\r
2259         }\r
2260 }\r
2261 \r
2262 \r
2263 //! Returns amount of registered scene node animator factories.\r
2264 u32 CSceneManager::getRegisteredSceneNodeAnimatorFactoryCount() const\r
2265 {\r
2266         return SceneNodeAnimatorFactoryList.size();\r
2267 }\r
2268 \r
2269 \r
2270 //! Returns a scene node animator factory by index\r
2271 ISceneNodeAnimatorFactory* CSceneManager::getSceneNodeAnimatorFactory(u32 index)\r
2272 {\r
2273         if (index < SceneNodeAnimatorFactoryList.size())\r
2274                 return SceneNodeAnimatorFactoryList[index];\r
2275 \r
2276         return 0;\r
2277 }\r
2278 \r
2279 \r
2280 //! Saves the current scene into a file.\r
2281 //! \param filename: Name of the file .\r
2282 bool CSceneManager::saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)\r
2283 {\r
2284         bool ret = false;\r
2285         io::IWriteFile* file = FileSystem->createAndWriteFile(filename);\r
2286         if (file)\r
2287         {\r
2288                 ret = saveScene(file, userDataSerializer, node);\r
2289                 file->drop();\r
2290         }\r
2291         else\r
2292                 os::Printer::log("Unable to open file", filename, ELL_ERROR);\r
2293 \r
2294         return ret;\r
2295 }\r
2296 \r
2297 \r
2298 //! Saves the current scene into a file.\r
2299 bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)\r
2300 {\r
2301         if (!file)\r
2302         {\r
2303                 return false;\r
2304         }\r
2305 \r
2306         bool result=false;\r
2307         io::IXMLWriter* writer = FileSystem->createXMLWriter(file);\r
2308         if (!writer)\r
2309         {\r
2310                 os::Printer::log("Unable to create XML writer", file->getFileName(), ELL_ERROR);\r
2311         }\r
2312         else\r
2313         {\r
2314                 result = saveScene(writer, FileSystem->getFileDir(FileSystem->getAbsolutePath(file->getFileName())), userDataSerializer, node);\r
2315                 writer->drop();\r
2316         }\r
2317         return result;\r
2318 }\r
2319 \r
2320 \r
2321 //! Saves the current scene into a file.\r
2322 bool CSceneManager::saveScene(io::IXMLWriter* writer, const io::path& currentPath, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)\r
2323 {\r
2324         if (!writer)\r
2325                 return false;\r
2326 \r
2327         if (!node)\r
2328                 node=this;\r
2329 \r
2330         char* oldLocale = setlocale(LC_NUMERIC, NULL);\r
2331         setlocale(LC_NUMERIC, "C");     // float number should to be saved with dots in this format independent of current locale settings.\r
2332 \r
2333         writer->writeXMLHeader();\r
2334         writeSceneNode(writer, node, userDataSerializer, currentPath.c_str(), true);\r
2335 \r
2336         setlocale(LC_NUMERIC, oldLocale);\r
2337 \r
2338         return true;\r
2339 }\r
2340 \r
2341 \r
2342 //! Loads a scene.\r
2343 bool CSceneManager::loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)\r
2344 {\r
2345         io::IReadFile* file = FileSystem->createAndOpenFile(filename);\r
2346         if (!file)\r
2347         {\r
2348                 os::Printer::log("Unable to open scene file", filename.c_str(), ELL_ERROR);\r
2349                 return false;\r
2350         }\r
2351 \r
2352         const bool ret = loadScene(file, userDataSerializer, rootNode);\r
2353         file->drop();\r
2354 \r
2355         return ret;\r
2356 }\r
2357 \r
2358 \r
2359 //! Loads a scene. Note that the current scene is not cleared before.\r
2360 bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)\r
2361 {\r
2362         if (!file)\r
2363         {\r
2364                 os::Printer::log("Unable to open scene file", ELL_ERROR);\r
2365                 return false;\r
2366         }\r
2367 \r
2368         bool ret = false;\r
2369 \r
2370         // try scene loaders in reverse order\r
2371         s32 i = SceneLoaderList.size()-1;\r
2372         for (; i >= 0 && !ret; --i)\r
2373                 if (SceneLoaderList[i]->isALoadableFileFormat(file))\r
2374                         ret = SceneLoaderList[i]->loadScene(file, userDataSerializer, rootNode);\r
2375 \r
2376         if (!ret)\r
2377                 os::Printer::log("Could not load scene file, perhaps the format is unsupported: ", file->getFileName().c_str(), ELL_ERROR);\r
2378 \r
2379         return ret;\r
2380 }\r
2381 \r
2382 \r
2383 //! writes a scene node\r
2384 void CSceneManager::writeSceneNode(io::IXMLWriter* writer, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer,\r
2385                 const fschar_t* currentPath, bool init)\r
2386 {\r
2387         if (!writer || !node || node->isDebugObject())\r
2388                 return;\r
2389 \r
2390         const wchar_t* name;\r
2391         ISceneNode* tmpNode=node;\r
2392 \r
2393         if (init)\r
2394         {\r
2395                 name = IRR_XML_FORMAT_SCENE.c_str();\r
2396                 writer->writeElement(name, false);\r
2397                 node=this;\r
2398         }\r
2399         else\r
2400         {\r
2401                 name = IRR_XML_FORMAT_NODE.c_str();\r
2402                 writer->writeElement(name, false, IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str(),\r
2403                         core::stringw(getSceneNodeTypeName(node->getType())).c_str());\r
2404         }\r
2405 \r
2406         writer->writeLineBreak();\r
2407 \r
2408         // write properties\r
2409 \r
2410         io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver);\r
2411         io::SAttributeReadWriteOptions options;\r
2412         if (currentPath)\r
2413         {\r
2414                 options.Filename=currentPath;\r
2415                 options.Flags|=io::EARWF_USE_RELATIVE_PATHS;\r
2416         }\r
2417         node->serializeAttributes(attr, &options);\r
2418 \r
2419         if (attr->getAttributeCount() != 0)\r
2420         {\r
2421                 attr->write(writer);\r
2422                 writer->writeLineBreak();\r
2423         }\r
2424 \r
2425         // write materials\r
2426 \r
2427         if (node->getMaterialCount() && Driver)\r
2428         {\r
2429                 const wchar_t* materialElement = L"materials";\r
2430 \r
2431                 writer->writeElement(materialElement);\r
2432                 writer->writeLineBreak();\r
2433 \r
2434                 for (u32 i=0; i < node->getMaterialCount(); ++i)\r
2435                 {\r
2436                         io::IAttributes* tmp_attr =\r
2437                                 Driver->createAttributesFromMaterial(node->getMaterial(i), &options);\r
2438                         tmp_attr->write(writer);\r
2439                         tmp_attr->drop();\r
2440                 }\r
2441 \r
2442                 writer->writeClosingTag(materialElement);\r
2443                 writer->writeLineBreak();\r
2444         }\r
2445 \r
2446         // write animators\r
2447 \r
2448         if (!node->getAnimators().empty())\r
2449         {\r
2450                 const wchar_t* animatorElement = L"animators";\r
2451                 writer->writeElement(animatorElement);\r
2452                 writer->writeLineBreak();\r
2453 \r
2454                 ISceneNodeAnimatorList::ConstIterator it = node->getAnimators().begin();\r
2455                 for (; it != node->getAnimators().end(); ++it)\r
2456                 {\r
2457                         attr->clear();\r
2458                         attr->addString("Type", getAnimatorTypeName((*it)->getType()));\r
2459 \r
2460                         (*it)->serializeAttributes(attr);\r
2461 \r
2462                         attr->write(writer);\r
2463                 }\r
2464 \r
2465                 writer->writeClosingTag(animatorElement);\r
2466                 writer->writeLineBreak();\r
2467         }\r
2468 \r
2469         // write possible user data\r
2470 \r
2471         if (userDataSerializer)\r
2472         {\r
2473                 io::IAttributes* userData = userDataSerializer->createUserData(node);\r
2474                 if (userData)\r
2475                 {\r
2476                         const wchar_t* userDataElement = L"userData";\r
2477 \r
2478                         writer->writeLineBreak();\r
2479                         writer->writeElement(userDataElement);\r
2480                         writer->writeLineBreak();\r
2481 \r
2482                         userData->write(writer);\r
2483 \r
2484                         writer->writeClosingTag(userDataElement);\r
2485                         writer->writeLineBreak();\r
2486                         writer->writeLineBreak();\r
2487 \r
2488                         userData->drop();\r
2489                 }\r
2490         }\r
2491         // reset to actual root node\r
2492         if (init)\r
2493                 node=tmpNode;\r
2494 \r
2495         // write children once root node is written\r
2496         // if parent is not scene manager, we need to write out node first\r
2497         if (init && (node != this))\r
2498         {\r
2499                 writeSceneNode(writer, node, userDataSerializer, currentPath);\r
2500         }\r
2501         else\r
2502         {\r
2503                 ISceneNodeList::ConstIterator it = node->getChildren().begin();\r
2504                 for (; it != node->getChildren().end(); ++it)\r
2505                         writeSceneNode(writer, (*it), userDataSerializer, currentPath);\r
2506         }\r
2507 \r
2508         attr->drop();\r
2509 \r
2510         writer->writeClosingTag(name);\r
2511         writer->writeLineBreak();\r
2512         writer->writeLineBreak();\r
2513 }\r
2514 \r
2515 \r
2516 //! Returns a typename from a scene node type or null if not found\r
2517 const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type)\r
2518 {\r
2519         const char* name = 0;\r
2520 \r
2521         for (s32 i=(s32)SceneNodeFactoryList.size()-1; !name && i>=0; --i)\r
2522                 name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type);\r
2523 \r
2524         return name;\r
2525 }\r
2526 \r
2527 //! Adds a scene node to the scene by name\r
2528 ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent)\r
2529 {\r
2530         ISceneNode* node = 0;\r
2531 \r
2532         for (s32 i=(s32)SceneNodeFactoryList.size()-1; i>=0 && !node; --i)\r
2533                         node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent);\r
2534 \r
2535         return node;\r
2536 }\r
2537 \r
2538 ISceneNodeAnimator* CSceneManager::createSceneNodeAnimator(const char* typeName, ISceneNode* target)\r
2539 {\r
2540         ISceneNodeAnimator *animator = 0;\r
2541 \r
2542         for (s32 i=(s32)SceneNodeAnimatorFactoryList.size()-1; i>=0 && !animator; --i)\r
2543                 animator = SceneNodeAnimatorFactoryList[i]->createSceneNodeAnimator(typeName, target);\r
2544 \r
2545         return animator;\r
2546 }\r
2547 \r
2548 \r
2549 //! Returns a typename from a scene node animator type or null if not found\r
2550 const c8* CSceneManager::getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type)\r
2551 {\r
2552         const char* name = 0;\r
2553 \r
2554         for (s32 i=SceneNodeAnimatorFactoryList.size()-1; !name && i >= 0; --i)\r
2555                 name = SceneNodeAnimatorFactoryList[i]->getCreateableSceneNodeAnimatorTypeName(type);\r
2556 \r
2557         return name;\r
2558 }\r
2559 \r
2560 \r
2561 //! Writes attributes of the scene node.\r
2562 void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const\r
2563 {\r
2564         out->addString  ("Name", Name.c_str());\r
2565         out->addInt     ("Id", ID );\r
2566         out->addColorf  ("AmbientLight", AmbientLight);\r
2567 \r
2568         // fog attributes from video driver\r
2569         video::SColor color;\r
2570         video::E_FOG_TYPE fogType;\r
2571         f32 start, end, density;\r
2572         bool pixelFog, rangeFog;\r
2573 \r
2574         Driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog);\r
2575 \r
2576         out->addEnum("FogType", fogType, video::FogTypeNames);\r
2577         out->addColorf("FogColor", color);\r
2578         out->addFloat("FogStart", start);\r
2579         out->addFloat("FogEnd", end);\r
2580         out->addFloat("FogDensity", density);\r
2581         out->addBool("FogPixel", pixelFog);\r
2582         out->addBool("FogRange", rangeFog);\r
2583 }\r
2584 \r
2585 //! Reads attributes of the scene node.\r
2586 void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)\r
2587 {\r
2588         Name = in->getAttributeAsString("Name");\r
2589         ID = in->getAttributeAsInt("Id");\r
2590         AmbientLight = in->getAttributeAsColorf("AmbientLight");\r
2591 \r
2592         // fog attributes\r
2593         video::SColor color;\r
2594         video::E_FOG_TYPE fogType;\r
2595         f32 start, end, density;\r
2596         bool pixelFog, rangeFog;\r
2597         if (in->existsAttribute("FogType"))\r
2598         {\r
2599                 fogType = (video::E_FOG_TYPE) in->getAttributeAsEnumeration("FogType", video::FogTypeNames);\r
2600                 color = in->getAttributeAsColorf("FogColor").toSColor();\r
2601                 start = in->getAttributeAsFloat("FogStart");\r
2602                 end = in->getAttributeAsFloat("FogEnd");\r
2603                 density = in->getAttributeAsFloat("FogDensity");\r
2604                 pixelFog = in->getAttributeAsBool("FogPixel");\r
2605                 rangeFog = in->getAttributeAsBool("FogRange");\r
2606                 Driver->setFog(color, fogType, start, end, density, pixelFog, rangeFog);\r
2607         }\r
2608 \r
2609         RelativeTranslation.set(0,0,0);\r
2610         RelativeRotation.set(0,0,0);\r
2611         RelativeScale.set(1,1,1);\r
2612         IsVisible = true;\r
2613         AutomaticCullingState = scene::EAC_BOX;\r
2614         DebugDataVisible = scene::EDS_OFF;\r
2615         IsDebugObject = false;\r
2616 \r
2617         updateAbsolutePosition();\r
2618 }\r
2619 \r
2620 \r
2621 //! Sets ambient color of the scene\r
2622 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)\r
2623 {\r
2624         AmbientLight = ambientColor;\r
2625 }\r
2626 \r
2627 \r
2628 //! Returns ambient color of the scene\r
2629 const video::SColorf& CSceneManager::getAmbientLight() const\r
2630 {\r
2631         return AmbientLight;\r
2632 }\r
2633 \r
2634 \r
2635 //! Get a skinned mesh, which is not available as header-only code\r
2636 ISkinnedMesh* CSceneManager::createSkinnedMesh()\r
2637 {\r
2638 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_\r
2639         return new CSkinnedMesh();\r
2640 #else\r
2641         return 0;\r
2642 #endif\r
2643 }\r
2644 \r
2645 //! Returns a mesh writer implementation if available\r
2646 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)\r
2647 {\r
2648         switch(type)\r
2649         {\r
2650         case EMWT_IRR_MESH:\r
2651 #ifdef _IRR_COMPILE_WITH_IRR_WRITER_\r
2652                 return new CIrrMeshWriter(Driver, FileSystem);\r
2653 #else\r
2654                 return 0;\r
2655 #endif\r
2656         case EMWT_COLLADA:\r
2657 #ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_\r
2658                 return new CColladaMeshWriter(this, Driver, FileSystem);\r
2659 #else\r
2660                 return 0;\r
2661 #endif\r
2662         case EMWT_STL:\r
2663 #ifdef _IRR_COMPILE_WITH_STL_WRITER_\r
2664                 return new CSTLMeshWriter(this);\r
2665 #else\r
2666                 return 0;\r
2667 #endif\r
2668         case EMWT_OBJ:\r
2669 #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_\r
2670                 return new COBJMeshWriter(this, FileSystem);\r
2671 #else\r
2672                 return 0;\r
2673 #endif\r
2674 \r
2675         case EMWT_PLY:\r
2676 #ifdef _IRR_COMPILE_WITH_PLY_WRITER_\r
2677                 return new CPLYMeshWriter();\r
2678 #else\r
2679                 return 0;\r
2680 #endif\r
2681 \r
2682         case EMWT_B3D:\r
2683 #ifdef _IRR_COMPILE_WITH_B3D_WRITER_\r
2684                 return new CB3DMeshWriter();\r
2685 #else\r
2686                 return 0;\r
2687 #endif\r
2688         }\r
2689 \r
2690         return 0;\r
2691 }\r
2692 \r
2693 \r
2694 // creates a scenemanager\r
2695 ISceneManager* createSceneManager(video::IVideoDriver* driver,\r
2696                 io::IFileSystem* fs, gui::ICursorControl* cursorcontrol,\r
2697                 gui::IGUIEnvironment *guiEnvironment)\r
2698 {\r
2699         return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment );\r
2700 }\r
2701 \r
2702 \r
2703 } // end namespace scene\r
2704 } // end namespace irr\r
2705 \r