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