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
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
23 // We need this include for the case of skinned mesh support without
\r
25 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
\r
26 #include "CSkinnedMesh.h"
\r
29 #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_
\r
30 #include "CIrrMeshFileLoader.h"
\r
33 #ifdef _IRR_COMPILE_WITH_BSP_LOADER_
\r
34 #include "CBSPMeshFileLoader.h"
\r
37 #ifdef _IRR_COMPILE_WITH_MD2_LOADER_
\r
38 #include "CMD2MeshFileLoader.h"
\r
41 #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
\r
42 #include "CAnimatedMeshHalfLife.h"
\r
45 #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_
\r
46 #include "CMS3DMeshFileLoader.h"
\r
49 #ifdef _IRR_COMPILE_WITH_3DS_LOADER_
\r
50 #include "C3DSMeshFileLoader.h"
\r
53 #ifdef _IRR_COMPILE_WITH_X_LOADER_
\r
54 #include "CXMeshFileLoader.h"
\r
57 #ifdef _IRR_COMPILE_WITH_OCT_LOADER_
\r
58 #include "COCTLoader.h"
\r
61 #ifdef _IRR_COMPILE_WITH_CSM_LOADER_
\r
62 #include "CCSMLoader.h"
\r
65 #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_
\r
66 #include "CLMTSMeshFileLoader.h"
\r
69 #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_
\r
70 #include "CMY3DMeshFileLoader.h"
\r
73 #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_
\r
74 #include "CColladaFileLoader.h"
\r
77 #ifdef _IRR_COMPILE_WITH_DMF_LOADER_
\r
78 #include "CDMFLoader.h"
\r
81 #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_
\r
82 #include "COgreMeshFileLoader.h"
\r
85 #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_
\r
86 #include "COBJMeshFileLoader.h"
\r
89 #ifdef _IRR_COMPILE_WITH_MD3_LOADER_
\r
90 #include "CMD3MeshFileLoader.h"
\r
93 #ifdef _IRR_COMPILE_WITH_B3D_LOADER_
\r
94 #include "CB3DMeshFileLoader.h"
\r
97 #ifdef _IRR_COMPILE_WITH_LWO_LOADER_
\r
98 #include "CLWOMeshFileLoader.h"
\r
101 #ifdef _IRR_COMPILE_WITH_STL_LOADER_
\r
102 #include "CSTLMeshFileLoader.h"
\r
105 #ifdef _IRR_COMPILE_WITH_PLY_LOADER_
\r
106 #include "CPLYMeshFileLoader.h"
\r
109 #ifdef _IRR_COMPILE_WITH_SMF_LOADER_
\r
110 #include "CSMFMeshFileLoader.h"
\r
113 #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_
\r
114 #include "CSceneLoaderIrr.h"
\r
117 #ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_
\r
118 #include "CColladaMeshWriter.h"
\r
121 #ifdef _IRR_COMPILE_WITH_IRR_WRITER_
\r
122 #include "CIrrMeshWriter.h"
\r
125 #ifdef _IRR_COMPILE_WITH_STL_WRITER_
\r
126 #include "CSTLMeshWriter.h"
\r
129 #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_
\r
130 #include "COBJMeshWriter.h"
\r
133 #ifdef _IRR_COMPILE_WITH_PLY_WRITER_
\r
134 #include "CPLYMeshWriter.h"
\r
137 #ifdef _IRR_COMPILE_WITH_B3D_WRITER_
\r
138 #include "CB3DMeshWriter.h"
\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
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
162 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
\r
163 #include "CShadowVolumeSceneNode.h"
\r
165 #include "IShadowVolumeSceneNode.h"
\r
166 #endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
\r
168 #ifdef _IRR_COMPILE_WITH_PARTICLES_
\r
169 #include "CParticleSystemSceneNode.h"
\r
170 #endif // _IRR_COMPILE_WITH_PARTICLES_
\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
184 #include "CDefaultSceneNodeFactory.h"
\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
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
206 #include "CGeometryCreator.h"
\r
208 #include <locale.h>
\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
226 ISceneManager::setDebugName("CSceneManager ISceneManager");
\r
227 ISceneNode::setDebugName("CSceneManager ISceneNode");
\r
230 // root node's scene manager
\r
231 SceneManager = this;
\r
237 FileSystem->grab();
\r
240 CursorControl->grab();
\r
242 if (GUIEnvironment)
\r
243 GUIEnvironment->grab();
\r
245 // create mesh cache if not there already
\r
247 MeshCache = new CMeshCache();
\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
256 // create collision manager
\r
257 CollisionManager = new CSceneCollisionManager(this, Driver);
\r
259 // create geometry creator
\r
260 GeometryCreator = new CGeometryCreator();
\r
262 // add file format loaders. add the least commonly used ones first,
\r
263 // as these are checked last
\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
268 #ifdef _IRR_COMPILE_WITH_STL_LOADER_
\r
269 MeshLoaderList.push_back(new CSTLMeshFileLoader());
\r
271 #ifdef _IRR_COMPILE_WITH_PLY_LOADER_
\r
272 MeshLoaderList.push_back(new CPLYMeshFileLoader(this));
\r
274 #ifdef _IRR_COMPILE_WITH_SMF_LOADER_
\r
275 MeshLoaderList.push_back(new CSMFMeshFileLoader(FileSystem, Driver));
\r
277 #ifdef _IRR_COMPILE_WITH_OCT_LOADER_
\r
278 MeshLoaderList.push_back(new COCTLoader(this, FileSystem));
\r
280 #ifdef _IRR_COMPILE_WITH_CSM_LOADER_
\r
281 MeshLoaderList.push_back(new CCSMLoader(this, FileSystem));
\r
283 #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_
\r
284 MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, Parameters));
\r
286 #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_
\r
287 MeshLoaderList.push_back(new CMY3DMeshFileLoader(this, FileSystem));
\r
289 #ifdef _IRR_COMPILE_WITH_DMF_LOADER_
\r
290 MeshLoaderList.push_back(new CDMFLoader(this, FileSystem));
\r
292 #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_
\r
293 MeshLoaderList.push_back(new COgreMeshFileLoader(FileSystem, Driver));
\r
295 #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_
\r
296 MeshLoaderList.push_back(new CHalflifeMDLMeshFileLoader( this ));
\r
298 #ifdef _IRR_COMPILE_WITH_MD3_LOADER_
\r
299 MeshLoaderList.push_back(new CMD3MeshFileLoader( this));
\r
301 #ifdef _IRR_COMPILE_WITH_LWO_LOADER_
\r
302 MeshLoaderList.push_back(new CLWOMeshFileLoader(this, FileSystem));
\r
304 #ifdef _IRR_COMPILE_WITH_MD2_LOADER_
\r
305 MeshLoaderList.push_back(new CMD2MeshFileLoader());
\r
307 #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_
\r
308 MeshLoaderList.push_back(new CIrrMeshFileLoader(this, FileSystem));
\r
310 #ifdef _IRR_COMPILE_WITH_BSP_LOADER_
\r
311 MeshLoaderList.push_back(new CBSPMeshFileLoader(this, FileSystem));
\r
313 #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_
\r
314 MeshLoaderList.push_back(new CColladaFileLoader(this, FileSystem));
\r
316 #ifdef _IRR_COMPILE_WITH_3DS_LOADER_
\r
317 MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem));
\r
319 #ifdef _IRR_COMPILE_WITH_X_LOADER_
\r
320 MeshLoaderList.push_back(new CXMeshFileLoader(this, FileSystem));
\r
322 #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_
\r
323 MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver));
\r
325 #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_
\r
326 MeshLoaderList.push_back(new COBJMeshFileLoader(this, FileSystem));
\r
328 #ifdef _IRR_COMPILE_WITH_B3D_LOADER_
\r
329 MeshLoaderList.push_back(new CB3DMeshFileLoader(this));
\r
333 #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_
\r
334 SceneLoaderList.push_back(new CSceneLoaderIrr(this, FileSystem));
\r
338 ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this);
\r
339 registerSceneNodeFactory(factory);
\r
342 ISceneNodeAnimatorFactory* animatorFactory = new CDefaultSceneNodeAnimatorFactory(this, CursorControl);
\r
343 registerSceneNodeAnimatorFactory(animatorFactory);
\r
344 animatorFactory->drop();
\r
347 static bool initProfile = false;
\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
368 CSceneManager::~CSceneManager()
\r
370 clearDeletionList();
\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
376 Driver->removeAllHardwareBuffers();
\r
379 FileSystem->drop();
\r
382 CursorControl->drop();
\r
384 if (CollisionManager)
\r
385 CollisionManager->drop();
\r
387 if (GeometryCreator)
\r
388 GeometryCreator->drop();
\r
390 if (GUIEnvironment)
\r
391 GUIEnvironment->drop();
\r
394 for (i=0; i<MeshLoaderList.size(); ++i)
\r
395 MeshLoaderList[i]->drop();
\r
397 for (i=0; i<SceneLoaderList.size(); ++i)
\r
398 SceneLoaderList[i]->drop();
\r
401 ActiveCamera->drop();
\r
408 Parameters->drop();
\r
410 for (i=0; i<SceneNodeFactoryList.size(); ++i)
\r
411 SceneNodeFactoryList[i]->drop();
\r
413 for (i=0; i<SceneNodeAnimatorFactoryList.size(); ++i)
\r
414 SceneNodeAnimatorFactoryList[i]->drop();
\r
417 LightManager->drop();
\r
419 // remove all nodes and animators before dropping the driver
\r
420 // as render targets may be destroyed twice
\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
433 io::path cacheName = alternativeCacheName.empty() ? filename : alternativeCacheName;
\r
434 IAnimatedMesh* msh = MeshCache->getMeshByName(cacheName);
\r
438 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
441 os::Printer::log("Could not load mesh, because file could not be opened: ", filename, ELL_ERROR);
\r
445 msh = getUncachedMesh(file, filename, cacheName);
\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
459 io::path name = file->getFileName();
\r
460 IAnimatedMesh* msh = MeshCache->getMeshByName(name);
\r
464 msh = getUncachedMesh(file, name, name);
\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
472 IAnimatedMesh* msh = 0;
\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
478 if (MeshLoaderList[i]->isALoadableFileExtension(filename))
\r
480 // reset file to avoid side effects of previous calls to createMesh
\r
482 msh = MeshLoaderList[i]->createMesh(file);
\r
485 MeshCache->addMesh(cachename, msh);
\r
493 os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR);
\r
495 os::Printer::log("Loaded mesh", filename, ELL_DEBUG);
\r
500 //! returns the video driver
\r
501 video::IVideoDriver* CSceneManager::getVideoDriver()
\r
507 //! returns the GUI Environment
\r
508 gui::IGUIEnvironment* CSceneManager::getGUIEnvironment()
\r
510 return GUIEnvironment;
\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
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
533 ITextSceneNode* t = new CTextSceneNode(parent, this, id, font,
\r
534 getSceneCollisionManager(), position, text, color);
\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
548 if (!font && GUIEnvironment)
\r
549 font = GUIEnvironment->getBuiltInFont();
\r
557 IBillboardTextSceneNode* node = new CBillboardTextSceneNode(parent, this, id, font, text, position, size,
\r
558 colorTop, colorBottom);
\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
571 #ifdef _IRR_COMPILE_WITH_BSP_LOADER_
\r
578 CQuake3ShaderSceneNode* node = new CQuake3ShaderSceneNode( parent,
\r
579 this, id, FileSystem,
\r
580 meshBuffer, shader );
\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
601 IVolumeLightSceneNode* node = new CVolumeLightSceneNode(parent, this, id, subdivU, subdivV, foot, tail, position, rotation, scale);
\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
614 #ifdef _IRR_COMPILE_WITH_CUBE_SCENENODE_
\r
618 IMeshSceneNode* node = new CCubeSceneNode(size, parent, this, id, position, rotation, scale);
\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
633 #ifdef _IRR_COMPILE_WITH_SPHERE_SCENENODE_
\r
637 IMeshSceneNode* node = new CSphereSceneNode(radius, polyCount, polyCount, parent, this, id, position, rotation, scale);
\r
643 #endif // _IRR_COMPILE_WITH_SPHERE_SCENENODE_
\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
653 if (!alsoAddIfMeshPointerZero && !mesh)
\r
659 IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale);
\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
671 #ifdef _IRR_COMPILE_WITH_WATER_SURFACE_SCENENODE_
\r
675 ISceneNode* node = new CWaterSurfaceSceneNode(waveHeight, waveSpeed, waveLength,
\r
676 mesh, parent, this, id, position, rotation, scale);
\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
692 if (!alsoAddIfMeshPointerZero && !mesh)
\r
698 IAnimatedMeshSceneNode* node =
\r
699 new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale);
\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
712 if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount()))
\r
715 return addOctreeSceneNode(mesh ? mesh->getMesh(0) : 0,
\r
716 parent, id, minimalPolysPerNode,
\r
717 alsoAddIfMeshPointerZero);
\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
727 #ifdef _IRR_COMPILE_WITH_OCTREE_SCENENODE_
\r
728 if (!alsoAddIfMeshPointerZero && !mesh)
\r
734 COctreeSceneNode* node = new COctreeSceneNode(parent, this, id, minimalPolysPerNode);
\r
738 node->setMesh(mesh);
\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
762 ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat);
\r
765 setActiveCamera(node);
\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
779 ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(),
\r
780 core::vector3df(0,0,100), id, makeActive);
\r
783 ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraMaya(CursorControl,
\r
784 rotateSpeed, zoomSpeed, translationSpeed, distance);
\r
786 node->addAnimator(anm);
\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
801 ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(),
\r
802 core::vector3df(0,0,100), id, makeActive);
\r
805 ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraFPS(CursorControl,
\r
806 rotateSpeed, moveSpeed, jumpSpeed,
\r
807 keyMapArray, keyMapSize, noVerticalMovement, invertMouseY);
\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
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
828 ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range);
\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
843 #ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_
\r
847 IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size,
\r
848 colorTop, colorBottom);
\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
867 ISceneNode* node = new CSkyBoxSceneNode(top, bottom, left, right,
\r
868 front, back, parent, this, id);
\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
881 #ifdef _IRR_COMPILE_WITH_SKYDOME_SCENENODE_
\r
885 ISceneNode* node = new CSkyDomeSceneNode(texture, horiRes, vertRes,
\r
886 texturePercentage, spherePercentage, radius, parent, this, id);
\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
902 #ifdef _IRR_COMPILE_WITH_PARTICLES_
\r
906 IParticleSystemSceneNode* node = new CParticleSystemSceneNode(withDefaultEmitter,
\r
907 parent, this, id, position, rotation, scale);
\r
913 #endif // _IRR_COMPILE_WITH_PARTICLES_
\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
928 io::IReadFile* file = FileSystem->createAndOpenFile(heightMapFileName);
\r
930 if (!file && !addAlsoIfHeightmapEmpty)
\r
932 os::Printer::log("Could not load terrain, because file could not be opened.",
\r
933 heightMapFileName, ELL_ERROR);
\r
937 ITerrainSceneNode* terrain = addTerrainSceneNode(file, parent, id,
\r
938 position, rotation, scale, vertexColor, maxLOD, patchSize,
\r
939 smoothFactor, addAlsoIfHeightmapEmpty);
\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
957 bool addAlsoIfHeightmapEmpty)
\r
959 #ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_
\r
963 if (!heightMapFile && !addAlsoIfHeightmapEmpty)
\r
965 os::Printer::log("Could not load terrain, because file could not be opened.", ELL_ERROR);
\r
969 CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id,
\r
970 maxLOD, patchSize, position, rotation, scale);
\r
972 if (!node->loadHeightMap(heightMapFile, vertexColor, smoothFactor))
\r
974 if (!addAlsoIfHeightmapEmpty)
\r
986 #endif // _IRR_COMPILE_WITH_TERRAIN_SCENENODE_
\r
990 //! Adds an empty scene node.
\r
991 ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id)
\r
996 ISceneNode* node = new CEmptySceneNode(parent, this, id);
\r
1003 //! Adds a dummy transformation scene node to the scene graph.
\r
1004 IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode(
\r
1005 ISceneNode* parent, s32 id)
\r
1010 IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode(
\r
1011 parent, this, id);
\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
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
1030 if (MeshCache->isMeshLoaded(name))
\r
1031 return MeshCache->getMeshByName(name);
\r
1033 IMesh* mesh = GeometryCreator->createHillPlaneMesh(tileSize,
\r
1034 tileCount, material, hillHeight, countHills,
\r
1035 textureRepeatCount);
\r
1039 SAnimatedMesh* animatedMesh = new SAnimatedMesh();
\r
1040 if (!animatedMesh)
\r
1046 animatedMesh->addMesh(mesh);
\r
1048 animatedMesh->recalculateBoundingBox();
\r
1050 MeshCache->addMesh(name, animatedMesh);
\r
1051 animatedMesh->drop();
\r
1053 return animatedMesh;
\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
1062 const core::dimension2d<u32>& defaultVertexBlockSize)
\r
1064 if (MeshCache->isMeshLoaded(name))
\r
1065 return MeshCache->getMeshByName(name);
\r
1067 const bool debugBorders=false;
\r
1068 IMesh* mesh = GeometryCreator->createTerrainMesh(texture, heightmap,
\r
1069 stretchSize, maxHeight, Driver,
\r
1070 defaultVertexBlockSize, debugBorders);
\r
1074 SAnimatedMesh* animatedMesh = new SAnimatedMesh();
\r
1075 if (!animatedMesh)
\r
1081 animatedMesh->addMesh(mesh);
\r
1083 animatedMesh->recalculateBoundingBox();
\r
1085 MeshCache->addMesh(name, animatedMesh);
\r
1086 animatedMesh->drop();
\r
1088 return animatedMesh;
\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
1098 if (MeshCache->isMeshLoaded(name))
\r
1099 return MeshCache->getMeshByName(name);
\r
1101 IMesh* mesh = GeometryCreator->createArrowMesh( tesselationCylinder,
\r
1102 tesselationCone, height, cylinderHeight, width0,width1,
\r
1103 vtxColor0, vtxColor1);
\r
1107 SAnimatedMesh* animatedMesh = new SAnimatedMesh();
\r
1108 if (!animatedMesh)
\r
1114 animatedMesh->addMesh(mesh);
\r
1116 animatedMesh->recalculateBoundingBox();
\r
1118 MeshCache->addMesh(name, animatedMesh);
\r
1119 animatedMesh->drop();
\r
1121 return animatedMesh;
\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
1129 if (MeshCache->isMeshLoaded(name))
\r
1130 return MeshCache->getMeshByName(name);
\r
1132 IMesh* mesh = GeometryCreator->createSphereMesh(radius, polyCountX, polyCountY);
\r
1136 SAnimatedMesh* animatedMesh = new SAnimatedMesh();
\r
1137 if (!animatedMesh)
\r
1143 animatedMesh->addMesh(mesh);
\r
1145 animatedMesh->recalculateBoundingBox();
\r
1147 MeshCache->addMesh(name, animatedMesh);
\r
1148 animatedMesh->drop();
\r
1150 return animatedMesh;
\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
1160 if (MeshCache->isMeshLoaded(name))
\r
1161 return MeshCache->getMeshByName(name);
\r
1163 IMesh* mesh = GeometryCreator->createVolumeLightMesh(SubdivideU, SubdivideV, FootColor, TailColor);
\r
1167 SAnimatedMesh* animatedMesh = new SAnimatedMesh();
\r
1168 if (!animatedMesh)
\r
1174 animatedMesh->addMesh(mesh);
\r
1176 animatedMesh->recalculateBoundingBox();
\r
1178 MeshCache->addMesh(name, animatedMesh);
\r
1179 animatedMesh->drop();
\r
1181 return animatedMesh;
\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
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
1201 return ActiveCamera;
\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
1212 ActiveCamera->drop();
\r
1214 ActiveCamera = camera;
\r
1218 //! renders the node.
\r
1219 void CSceneManager::render()
\r
1224 //! returns the axis aligned bounding box of this node
\r
1225 const core::aabbox3d<f32>& CSceneManager::getBoundingBox() const
\r
1227 _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.
\r
1229 static const core::aabbox3d<f32> dummy;
\r
1234 //! returns if node is culled
\r
1235 bool CSceneManager::isCulled(const ISceneNode* node) const
\r
1237 const ICameraSceneNode* cam = getActiveCamera();
\r
1242 bool result = false;
\r
1244 // has occlusion query information
\r
1245 if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY)
\r
1247 result = (Driver->getOcclusionQueryResult(const_cast<ISceneNode*>(node))==0);
\r
1250 // can be seen by a bounding box ?
\r
1251 if (!result && (node->getAutomaticCulling() & scene::EAC_BOX))
\r
1253 core::aabbox3d<f32> tbox = node->getBoundingBox();
\r
1254 node->getAbsoluteTransformation().transformBoxEx(tbox);
\r
1255 result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() ));
\r
1258 // can be seen by a bounding sphere
\r
1259 if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE))
\r
1261 const core::aabbox3df nbox = node->getTransformedBoundingBox();
\r
1262 const float rad = nbox.getRadius();
\r
1263 const core::vector3df center = nbox.getCenter();
\r
1265 const float camrad = cam->getViewFrustum()->getBoundingRadius();
\r
1266 const core::vector3df camcenter = cam->getViewFrustum()->getBoundingCenter();
\r
1268 const float dist = (center - camcenter).getLengthSQ();
\r
1269 const float maxdist = (rad + camrad) * (rad + camrad);
\r
1271 result = dist > maxdist;
\r
1274 // can be seen by cam pyramid planes ?
\r
1275 if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX))
\r
1277 SViewFrustum frust = *cam->getViewFrustum();
\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
1284 core::vector3df edges[8];
\r
1285 node->getBoundingBox().getEdges(edges);
\r
1287 for (s32 i=0; i<scene::SViewFrustum::VF_PLANE_COUNT; ++i)
\r
1289 bool boxInFrustum=false;
\r
1290 for (u32 j=0; j<8; ++j)
\r
1292 if (frust.planes[i].classifyPointRelation(edges[j]) != core::ISREL3D_FRONT)
\r
1294 boxInFrustum=true;
\r
1299 if (!boxInFrustum)
\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
1314 IRR_PROFILE(CProfileScope p1(EPID_SM_REGISTER);)
\r
1319 // take camera if it is not already registered
\r
1320 case ESNRP_CAMERA:
\r
1323 for (u32 i = 0; i != CameraList.size(); ++i)
\r
1325 if (CameraList[i] == node)
\r
1333 CameraList.push_back(node);
\r
1339 // TODO: Point Light culling..
\r
1340 // Lighting model in irrlicht has to be redone..
\r
1341 //if (!isCulled(node))
\r
1343 LightList.push_back(node);
\r
1348 case ESNRP_SKY_BOX:
\r
1349 SkyBoxList.push_back(node);
\r
1353 if (!isCulled(node))
\r
1355 SolidNodeList.push_back(node);
\r
1359 case ESNRP_TRANSPARENT:
\r
1360 if (!isCulled(node))
\r
1362 TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos));
\r
1366 case ESNRP_TRANSPARENT_EFFECT:
\r
1367 if (!isCulled(node))
\r
1369 TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos));
\r
1373 case ESNRP_AUTOMATIC:
\r
1374 if (!isCulled(node))
\r
1376 const u32 count = node->getMaterialCount();
\r
1379 for (u32 i=0; i<count; ++i)
\r
1381 if (Driver->needsTransparentRenderPass(node->getMaterial(i)))
\r
1383 // register as transparent node
\r
1384 TransparentNodeEntry e(node, camWorldPos);
\r
1385 TransparentNodeList.push_back(e);
\r
1391 // not transparent, register as solid
\r
1394 SolidNodeList.push_back(node);
\r
1399 case ESNRP_SHADOW:
\r
1400 if (!isCulled(node))
\r
1402 ShadowNodeList.push_back(node);
\r
1408 if (!isCulled(node))
\r
1410 GuiNodeList.push_back(node);
\r
1414 case ESNRP_NONE: // ignore this one
\r
1418 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
1419 s32 index = Parameters->findAttribute("calls");
\r
1420 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);
\r
1424 index = Parameters->findAttribute("culled");
\r
1425 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);
\r
1432 void CSceneManager::clearAllRegisteredNodesForRendering()
\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
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
1448 IRR_PROFILE(CProfileScope psAll(EPID_SM_DRAW_ALL);)
\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
1462 u32 i; // new ISO for scoping problem in some compilers
\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
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
1480 First Scene Node for prerendering should be the active camera
\r
1481 consistent Camera is needed for culling
\r
1483 IRR_PROFILE(getProfiler().start(EPID_SM_RENDER_CAMERAS));
\r
1484 camWorldPos.set(0,0,0);
\r
1487 ActiveCamera->render();
\r
1488 camWorldPos = ActiveCamera->getAbsolutePosition();
\r
1490 IRR_PROFILE(getProfiler().stop(EPID_SM_RENDER_CAMERAS));
\r
1492 // let all nodes register themselves
\r
1493 OnRegisterSceneNode();
\r
1496 LightManager->OnPreRender(LightList);
\r
1498 //render camera scenes
\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
1505 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1507 for (i=0; i<CameraList.size(); ++i)
\r
1508 CameraList[i]->render();
\r
1510 CameraList.set_used(0);
\r
1513 LightManager->OnRenderPassPostRender(CurrentRenderPass);
\r
1516 //render lights scenes
\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
1524 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1528 // Sort the lights by distance from the camera
\r
1529 core::vector3df camWorldPos(0, 0, 0);
\r
1531 camWorldPos = ActiveCamera->getAbsolutePosition();
\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
1538 SortedLights.set_sorted(false);
\r
1539 SortedLights.sort();
\r
1541 for(s32 light = (s32)LightList.size() - 1; light >= 0; --light)
\r
1542 LightList[light] = SortedLights[light].Node;
\r
1545 Driver->deleteAllDynamicLights();
\r
1547 Driver->setAmbientLight(AmbientLight);
\r
1549 u32 maxLights = LightList.size();
\r
1551 if (!LightManager)
\r
1552 maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights);
\r
1554 for (i=0; i< maxLights; ++i)
\r
1555 LightList[i]->render();
\r
1558 LightManager->OnRenderPassPostRender(CurrentRenderPass);
\r
1561 // render skyboxes
\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
1569 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1570 for (i=0; i<SkyBoxList.size(); ++i)
\r
1572 ISceneNode* node = SkyBoxList[i];
\r
1573 LightManager->OnNodePreRender(node);
\r
1575 LightManager->OnNodePostRender(node);
\r
1580 for (i=0; i<SkyBoxList.size(); ++i)
\r
1581 SkyBoxList[i]->render();
\r
1584 SkyBoxList.set_used(0);
\r
1587 LightManager->OnRenderPassPostRender(CurrentRenderPass);
\r
1591 // render default objects
\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
1597 SolidNodeList.sort(); // sort by textures
\r
1601 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1602 for (i=0; i<SolidNodeList.size(); ++i)
\r
1604 ISceneNode* node = SolidNodeList[i].Node;
\r
1605 LightManager->OnNodePreRender(node);
\r
1607 LightManager->OnNodePostRender(node);
\r
1612 for (i=0; i<SolidNodeList.size(); ++i)
\r
1613 SolidNodeList[i].Node->render();
\r
1616 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
1617 Parameters->setAttribute("drawn_solid", (s32) SolidNodeList.size() );
\r
1619 SolidNodeList.set_used(0);
\r
1622 LightManager->OnRenderPassPostRender(CurrentRenderPass);
\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
1633 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1634 for (i=0; i<ShadowNodeList.size(); ++i)
\r
1636 ISceneNode* node = ShadowNodeList[i];
\r
1637 LightManager->OnNodePreRender(node);
\r
1639 LightManager->OnNodePostRender(node);
\r
1644 for (i=0; i<ShadowNodeList.size(); ++i)
\r
1645 ShadowNodeList[i]->render();
\r
1648 if (!ShadowNodeList.empty())
\r
1649 Driver->drawStencilShadow(true,ShadowColor, ShadowColor,
\r
1650 ShadowColor, ShadowColor);
\r
1652 ShadowNodeList.set_used(0);
\r
1655 LightManager->OnRenderPassPostRender(CurrentRenderPass);
\r
1658 // render transparent objects.
\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
1664 TransparentNodeList.sort(); // sort by distance from camera
\r
1667 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1669 for (i=0; i<TransparentNodeList.size(); ++i)
\r
1671 ISceneNode* node = TransparentNodeList[i].Node;
\r
1672 LightManager->OnNodePreRender(node);
\r
1674 LightManager->OnNodePostRender(node);
\r
1679 for (i=0; i<TransparentNodeList.size(); ++i)
\r
1680 TransparentNodeList[i].Node->render();
\r
1683 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
1684 Parameters->setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() );
\r
1686 TransparentNodeList.set_used(0);
\r
1689 LightManager->OnRenderPassPostRender(CurrentRenderPass);
\r
1692 // render transparent effect objects.
\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
1698 TransparentEffectNodeList.sort(); // sort by distance from camera
\r
1702 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1704 for (i=0; i<TransparentEffectNodeList.size(); ++i)
\r
1706 ISceneNode* node = TransparentEffectNodeList[i].Node;
\r
1707 LightManager->OnNodePreRender(node);
\r
1709 LightManager->OnNodePostRender(node);
\r
1714 for (i=0; i<TransparentEffectNodeList.size(); ++i)
\r
1715 TransparentEffectNodeList[i].Node->render();
\r
1717 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
1718 Parameters->setAttribute("drawn_transparent_effect", (s32) TransparentEffectNodeList.size());
\r
1720 TransparentEffectNodeList.set_used(0);
\r
1723 // render custom gui nodes
\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
1731 LightManager->OnRenderPassPreRender(CurrentRenderPass);
\r
1733 for (i=0; i<GuiNodeList.size(); ++i)
\r
1735 ISceneNode* node = GuiNodeList[i];
\r
1736 LightManager->OnNodePreRender(node);
\r
1738 LightManager->OnNodePostRender(node);
\r
1743 for (i=0; i<GuiNodeList.size(); ++i)
\r
1744 GuiNodeList[i]->render();
\r
1746 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
1747 Parameters->setAttribute("drawn_gui_nodes", (s32) GuiNodeList.size());
\r
1749 GuiNodeList.set_used(0);
\r
1754 LightManager->OnPostRender();
\r
1756 LightList.set_used(0);
\r
1757 clearDeletionList();
\r
1759 CurrentRenderPass = ESNRP_NONE;
\r
1762 void CSceneManager::setLightManager(ILightManager* lightManager)
\r
1765 lightManager->grab();
\r
1767 LightManager->drop();
\r
1769 LightManager = lightManager;
\r
1773 //! Sets the color of stencil buffers shadows drawn by the scene manager.
\r
1774 void CSceneManager::setShadowColor(video::SColor color)
\r
1776 ShadowColor = color;
\r
1780 //! Returns the current color of shadows.
\r
1781 video::SColor CSceneManager::getShadowColor() const
\r
1783 return ShadowColor;
\r
1786 IShadowVolumeSceneNode* CSceneManager::createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity)
\r
1788 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
\r
1789 return new CShadowVolumeSceneNode(shadowMesh, parent, this, id, zfailmethod, infinity);
\r
1797 //! creates a rotation animator, which rotates the attached scene node around itself.
\r
1798 ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& rotationPerSecond)
\r
1800 ISceneNodeAnimator* anim = new CSceneNodeAnimatorRotation(os::Timer::getTime(),
\r
1801 rotationPerSecond);
\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
1814 const f32 orbitDurationMs = (core::DEGTORAD * 360.f) / speed;
\r
1815 const u32 effectiveTime = os::Timer::getTime() + (u32)(orbitDurationMs * startPosition);
\r
1817 ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle(
\r
1818 effectiveTime, center,
\r
1819 radius, speed, direction,radiusEllipsoid);
\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
1829 ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyStraight(startPoint,
\r
1830 endPoint, timeForWay, loop, os::Timer::getTime(), pingpong);
\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
1841 ISceneNodeAnimator* anim = new CSceneNodeAnimatorTexture(textures,
\r
1842 timePerFrame, loop, os::Timer::getTime());
\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
1852 return new CSceneNodeAnimatorDelete(this, os::Timer::getTime() + when);
\r
1856 //! Creates a special scene node animator for doing automatic collision detection
\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
1863 ISceneNodeAnimatorCollisionResponse* anim = new
\r
1864 CSceneNodeAnimatorCollisionResponse(this, world, sceneNode,
\r
1865 ellipsoidRadius, gravityPerSecond,
\r
1866 ellipsoidTranslation, slidingValue);
\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
1877 ISceneNodeAnimator* a = new CSceneNodeAnimatorFollowSpline(startTime, points,
\r
1878 speed, tightness, loop, pingpong);
\r
1883 //! Adds an external mesh loader.
\r
1884 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)
\r
1886 if (!externalLoader)
\r
1889 externalLoader->grab();
\r
1890 MeshLoaderList.push_back(externalLoader);
\r
1894 //! Returns the number of mesh loaders supported by Irrlicht at this time
\r
1895 u32 CSceneManager::getMeshLoaderCount() const
\r
1897 return MeshLoaderList.size();
\r
1901 //! Retrieve the given mesh loader
\r
1902 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const
\r
1904 if (index < MeshLoaderList.size())
\r
1905 return MeshLoaderList[index];
\r
1911 //! Adds an external scene loader.
\r
1912 void CSceneManager::addExternalSceneLoader(ISceneLoader* externalLoader)
\r
1914 if (!externalLoader)
\r
1917 externalLoader->grab();
\r
1918 SceneLoaderList.push_back(externalLoader);
\r
1922 //! Returns the number of scene loaders
\r
1923 u32 CSceneManager::getSceneLoaderCount() const
\r
1925 return SceneLoaderList.size();
\r
1929 //! Retrieve the given scene loader
\r
1930 ISceneLoader* CSceneManager::getSceneLoader(u32 index) const
\r
1932 if (index < SceneLoaderList.size())
\r
1933 return SceneLoaderList[index];
\r
1939 //! Returns a pointer to the scene collision manager.
\r
1940 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()
\r
1942 return CollisionManager;
\r
1946 //! Returns a pointer to the mesh manipulator.
\r
1947 IMeshManipulator* CSceneManager::getMeshManipulator()
\r
1949 return Driver->getMeshManipulator();
\r
1953 //! Creates a simple ITriangleSelector, based on a mesh.
\r
1954 ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers)
\r
1959 return new CTriangleSelector(mesh, node, separateMeshbuffers);
\r
1962 ITriangleSelector* CSceneManager::createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node)
\r
1966 return new CTriangleSelector(meshBuffer, materialIndex, node);
\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
1973 if (!node || !node->getMesh())
\r
1976 return new CTriangleSelector(node, separateMeshbuffers);
\r
1980 //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box.
\r
1981 ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node)
\r
1986 return new CTriangleBBSelector(node);
\r
1990 //! Creates a simple ITriangleSelector, based on a mesh.
\r
1991 ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMesh* mesh,
\r
1992 ISceneNode* node, s32 minimalPolysPerNode)
\r
1997 return new COctreeTriangleSelector(mesh, node, minimalPolysPerNode);
\r
2000 ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex,
\r
2001 ISceneNode* node, s32 minimalPolysPerNode)
\r
2006 return new COctreeTriangleSelector(meshBuffer, materialIndex, node, minimalPolysPerNode);
\r
2009 //! Creates a meta triangle selector.
\r
2010 IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector()
\r
2012 return new CMetaTriangleSelector();
\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
2020 #ifdef _IRR_COMPILE_WITH_TERRAIN_SCENENODE_
\r
2021 return new CTerrainTriangleSelector(node, LOD);
\r
2029 //! Adds a scene node to the deletion queue.
\r
2030 void CSceneManager::addToDeletionQueue(ISceneNode* node)
\r
2036 DeletionList.push_back(node);
\r
2040 //! clears the deletion list
\r
2041 void CSceneManager::clearDeletionList()
\r
2043 if (DeletionList.empty())
\r
2046 for (u32 i=0; i<DeletionList.size(); ++i)
\r
2048 DeletionList[i]->remove();
\r
2049 DeletionList[i]->drop();
\r
2052 DeletionList.clear();
\r
2056 //! Returns the first scene node with the specified name.
\r
2057 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)
\r
2060 start = getRootSceneNode();
\r
2062 if (!strcmp(start->getName(),name))
\r
2065 ISceneNode* node = 0;
\r
2067 const ISceneNodeList& list = start->getChildren();
\r
2068 ISceneNodeList::ConstIterator it = list.begin();
\r
2069 for (; it!=list.end(); ++it)
\r
2071 node = getSceneNodeFromName(name, *it);
\r
2080 //! Returns the first scene node with the specified id.
\r
2081 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)
\r
2084 start = getRootSceneNode();
\r
2086 if (start->getID() == id)
\r
2089 ISceneNode* node = 0;
\r
2091 const ISceneNodeList& list = start->getChildren();
\r
2092 ISceneNodeList::ConstIterator it = list.begin();
\r
2093 for (; it!=list.end(); ++it)
\r
2095 node = getSceneNodeFromId(id, *it);
\r
2104 //! Returns the first scene node with the specified type.
\r
2105 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)
\r
2108 start = getRootSceneNode();
\r
2110 if (start->getType() == type || ESNT_ANY == type)
\r
2113 ISceneNode* node = 0;
\r
2115 const ISceneNodeList& list = start->getChildren();
\r
2116 ISceneNodeList::ConstIterator it = list.begin();
\r
2117 for (; it!=list.end(); ++it)
\r
2119 node = getSceneNodeFromType(type, *it);
\r
2128 //! returns scene nodes by type.
\r
2129 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)
\r
2132 start = getRootSceneNode();
\r
2134 if (start->getType() == type || ESNT_ANY == type)
\r
2135 outNodes.push_back(start);
\r
2137 const ISceneNodeList& list = start->getChildren();
\r
2138 ISceneNodeList::ConstIterator it = list.begin();
\r
2140 for (; it!=list.end(); ++it)
\r
2142 getSceneNodesFromType(type, outNodes, *it);
\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
2152 ICameraSceneNode* cam = getActiveCamera();
\r
2154 ret = cam->OnEvent(event);
\r
2160 //! Removes all children of this scene node
\r
2161 void CSceneManager::removeAll()
\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
2167 Driver->setMaterial(video::SMaterial());
\r
2171 //! Clears the whole scene. All scene nodes are removed.
\r
2172 void CSceneManager::clear()
\r
2178 //! Returns interface to the parameters set in this scene.
\r
2179 io::IAttributes* CSceneManager::getParameters()
\r
2181 return Parameters;
\r
2185 //! Returns current render pass.
\r
2186 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const
\r
2188 return CurrentRenderPass;
\r
2192 //! Returns an interface to the mesh cache which is shared between all existing scene managers.
\r
2193 IMeshCache* CSceneManager::getMeshCache()
\r
2199 //! Creates a new scene manager.
\r
2200 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)
\r
2202 CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment);
\r
2205 manager->cloneMembers(this, manager);
\r
2211 //! Returns the default scene node factory which can create all built in scene nodes
\r
2212 ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory()
\r
2214 return getSceneNodeFactory(0);
\r
2218 //! Adds a scene node factory to the scene manager.
\r
2219 void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd)
\r
2223 factoryToAdd->grab();
\r
2224 SceneNodeFactoryList.push_back(factoryToAdd);
\r
2229 //! Returns amount of registered scene node factories.
\r
2230 u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const
\r
2232 return SceneNodeFactoryList.size();
\r
2236 //! Returns a scene node factory by index
\r
2237 ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index)
\r
2239 if (index < SceneNodeFactoryList.size())
\r
2240 return SceneNodeFactoryList[index];
\r
2246 //! Returns the default scene node animator factory which can create all built-in scene node animators
\r
2247 ISceneNodeAnimatorFactory* CSceneManager::getDefaultSceneNodeAnimatorFactory()
\r
2249 return getSceneNodeAnimatorFactory(0);
\r
2252 //! Adds a scene node animator factory to the scene manager.
\r
2253 void CSceneManager::registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd)
\r
2257 factoryToAdd->grab();
\r
2258 SceneNodeAnimatorFactoryList.push_back(factoryToAdd);
\r
2263 //! Returns amount of registered scene node animator factories.
\r
2264 u32 CSceneManager::getRegisteredSceneNodeAnimatorFactoryCount() const
\r
2266 return SceneNodeAnimatorFactoryList.size();
\r
2270 //! Returns a scene node animator factory by index
\r
2271 ISceneNodeAnimatorFactory* CSceneManager::getSceneNodeAnimatorFactory(u32 index)
\r
2273 if (index < SceneNodeAnimatorFactoryList.size())
\r
2274 return SceneNodeAnimatorFactoryList[index];
\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
2285 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
\r
2288 ret = saveScene(file, userDataSerializer, node);
\r
2292 os::Printer::log("Unable to open file", filename, ELL_ERROR);
\r
2298 //! Saves the current scene into a file.
\r
2299 bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)
\r
2306 bool result=false;
\r
2307 io::IXMLWriter* writer = FileSystem->createXMLWriter(file);
\r
2310 os::Printer::log("Unable to create XML writer", file->getFileName(), ELL_ERROR);
\r
2314 result = saveScene(writer, FileSystem->getFileDir(FileSystem->getAbsolutePath(file->getFileName())), userDataSerializer, node);
\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
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
2333 writer->writeXMLHeader();
\r
2334 writeSceneNode(writer, node, userDataSerializer, currentPath.c_str(), true);
\r
2336 setlocale(LC_NUMERIC, oldLocale);
\r
2342 //! Loads a scene.
\r
2343 bool CSceneManager::loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)
\r
2345 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
2348 os::Printer::log("Unable to open scene file", filename.c_str(), ELL_ERROR);
\r
2352 const bool ret = loadScene(file, userDataSerializer, rootNode);
\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
2364 os::Printer::log("Unable to open scene file", ELL_ERROR);
\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
2377 os::Printer::log("Could not load scene file, perhaps the format is unsupported: ", file->getFileName().c_str(), ELL_ERROR);
\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
2387 if (!writer || !node || node->isDebugObject())
\r
2390 const wchar_t* name;
\r
2391 ISceneNode* tmpNode=node;
\r
2395 name = IRR_XML_FORMAT_SCENE.c_str();
\r
2396 writer->writeElement(name, false);
\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
2406 writer->writeLineBreak();
\r
2408 // write properties
\r
2410 io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver);
\r
2411 io::SAttributeReadWriteOptions options;
\r
2414 options.Filename=currentPath;
\r
2415 options.Flags|=io::EARWF_USE_RELATIVE_PATHS;
\r
2417 node->serializeAttributes(attr, &options);
\r
2419 if (attr->getAttributeCount() != 0)
\r
2421 attr->write(writer);
\r
2422 writer->writeLineBreak();
\r
2425 // write materials
\r
2427 if (node->getMaterialCount() && Driver)
\r
2429 const wchar_t* materialElement = L"materials";
\r
2431 writer->writeElement(materialElement);
\r
2432 writer->writeLineBreak();
\r
2434 for (u32 i=0; i < node->getMaterialCount(); ++i)
\r
2436 io::IAttributes* tmp_attr =
\r
2437 Driver->createAttributesFromMaterial(node->getMaterial(i), &options);
\r
2438 tmp_attr->write(writer);
\r
2442 writer->writeClosingTag(materialElement);
\r
2443 writer->writeLineBreak();
\r
2446 // write animators
\r
2448 if (!node->getAnimators().empty())
\r
2450 const wchar_t* animatorElement = L"animators";
\r
2451 writer->writeElement(animatorElement);
\r
2452 writer->writeLineBreak();
\r
2454 ISceneNodeAnimatorList::ConstIterator it = node->getAnimators().begin();
\r
2455 for (; it != node->getAnimators().end(); ++it)
\r
2458 attr->addString("Type", getAnimatorTypeName((*it)->getType()));
\r
2460 (*it)->serializeAttributes(attr);
\r
2462 attr->write(writer);
\r
2465 writer->writeClosingTag(animatorElement);
\r
2466 writer->writeLineBreak();
\r
2469 // write possible user data
\r
2471 if (userDataSerializer)
\r
2473 io::IAttributes* userData = userDataSerializer->createUserData(node);
\r
2476 const wchar_t* userDataElement = L"userData";
\r
2478 writer->writeLineBreak();
\r
2479 writer->writeElement(userDataElement);
\r
2480 writer->writeLineBreak();
\r
2482 userData->write(writer);
\r
2484 writer->writeClosingTag(userDataElement);
\r
2485 writer->writeLineBreak();
\r
2486 writer->writeLineBreak();
\r
2491 // reset to actual root node
\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
2499 writeSceneNode(writer, node, userDataSerializer, currentPath);
\r
2503 ISceneNodeList::ConstIterator it = node->getChildren().begin();
\r
2504 for (; it != node->getChildren().end(); ++it)
\r
2505 writeSceneNode(writer, (*it), userDataSerializer, currentPath);
\r
2510 writer->writeClosingTag(name);
\r
2511 writer->writeLineBreak();
\r
2512 writer->writeLineBreak();
\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
2519 const char* name = 0;
\r
2521 for (s32 i=(s32)SceneNodeFactoryList.size()-1; !name && i>=0; --i)
\r
2522 name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type);
\r
2527 //! Adds a scene node to the scene by name
\r
2528 ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent)
\r
2530 ISceneNode* node = 0;
\r
2532 for (s32 i=(s32)SceneNodeFactoryList.size()-1; i>=0 && !node; --i)
\r
2533 node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent);
\r
2538 ISceneNodeAnimator* CSceneManager::createSceneNodeAnimator(const char* typeName, ISceneNode* target)
\r
2540 ISceneNodeAnimator *animator = 0;
\r
2542 for (s32 i=(s32)SceneNodeAnimatorFactoryList.size()-1; i>=0 && !animator; --i)
\r
2543 animator = SceneNodeAnimatorFactoryList[i]->createSceneNodeAnimator(typeName, target);
\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
2552 const char* name = 0;
\r
2554 for (s32 i=SceneNodeAnimatorFactoryList.size()-1; !name && i >= 0; --i)
\r
2555 name = SceneNodeAnimatorFactoryList[i]->getCreateableSceneNodeAnimatorTypeName(type);
\r
2561 //! Writes attributes of the scene node.
\r
2562 void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
\r
2564 out->addString ("Name", Name.c_str());
\r
2565 out->addInt ("Id", ID );
\r
2566 out->addColorf ("AmbientLight", AmbientLight);
\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
2574 Driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog);
\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
2585 //! Reads attributes of the scene node.
\r
2586 void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
\r
2588 Name = in->getAttributeAsString("Name");
\r
2589 ID = in->getAttributeAsInt("Id");
\r
2590 AmbientLight = in->getAttributeAsColorf("AmbientLight");
\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
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
2609 RelativeTranslation.set(0,0,0);
\r
2610 RelativeRotation.set(0,0,0);
\r
2611 RelativeScale.set(1,1,1);
\r
2613 AutomaticCullingState = scene::EAC_BOX;
\r
2614 DebugDataVisible = scene::EDS_OFF;
\r
2615 IsDebugObject = false;
\r
2617 updateAbsolutePosition();
\r
2621 //! Sets ambient color of the scene
\r
2622 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)
\r
2624 AmbientLight = ambientColor;
\r
2628 //! Returns ambient color of the scene
\r
2629 const video::SColorf& CSceneManager::getAmbientLight() const
\r
2631 return AmbientLight;
\r
2635 //! Get a skinned mesh, which is not available as header-only code
\r
2636 ISkinnedMesh* CSceneManager::createSkinnedMesh()
\r
2638 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
\r
2639 return new CSkinnedMesh();
\r
2645 //! Returns a mesh writer implementation if available
\r
2646 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)
\r
2650 case EMWT_IRR_MESH:
\r
2651 #ifdef _IRR_COMPILE_WITH_IRR_WRITER_
\r
2652 return new CIrrMeshWriter(Driver, FileSystem);
\r
2656 case EMWT_COLLADA:
\r
2657 #ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_
\r
2658 return new CColladaMeshWriter(this, Driver, FileSystem);
\r
2663 #ifdef _IRR_COMPILE_WITH_STL_WRITER_
\r
2664 return new CSTLMeshWriter(this);
\r
2669 #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_
\r
2670 return new COBJMeshWriter(this, FileSystem);
\r
2676 #ifdef _IRR_COMPILE_WITH_PLY_WRITER_
\r
2677 return new CPLYMeshWriter();
\r
2683 #ifdef _IRR_COMPILE_WITH_B3D_WRITER_
\r
2684 return new CB3DMeshWriter();
\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
2699 return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment );
\r
2703 } // end namespace scene
\r
2704 } // end namespace irr
\r