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 "ISceneUserDataSerializer.h"
\r
12 #include "IGUIEnvironment.h"
\r
13 #include "IMaterialRenderer.h"
\r
14 #include "IReadFile.h"
\r
15 #include "IWriteFile.h"
\r
16 #include "ISceneLoader.h"
\r
17 #include "EProfileIDs.h"
\r
18 #include "IProfiler.h"
\r
22 // We need this include for the case of skinned mesh support without
\r
24 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
\r
25 #include "CSkinnedMesh.h"
\r
28 #ifdef _IRR_COMPILE_WITH_X_LOADER_
\r
29 #include "CXMeshFileLoader.h"
\r
32 #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_
\r
33 #include "COBJMeshFileLoader.h"
\r
36 #ifdef _IRR_COMPILE_WITH_B3D_LOADER_
\r
37 #include "CB3DMeshFileLoader.h"
\r
40 #ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_
\r
41 #include "CBillboardSceneNode.h"
\r
42 #endif // _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_
\r
43 #include "CAnimatedMeshSceneNode.h"
\r
44 #include "CCameraSceneNode.h"
\r
45 #include "CMeshSceneNode.h"
\r
46 #include "CDummyTransformationSceneNode.h"
\r
47 #include "CEmptySceneNode.h"
\r
49 #include "CDefaultSceneNodeFactory.h"
\r
51 #include "CSceneCollisionManager.h"
\r
59 CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs,
\r
60 gui::ICursorControl* cursorControl, IMeshCache* cache,
\r
61 gui::IGUIEnvironment* gui)
\r
62 : ISceneNode(0, 0), Driver(driver), FileSystem(fs), GUIEnvironment(gui),
\r
63 CursorControl(cursorControl),
\r
64 ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), Parameters(0),
\r
65 MeshCache(cache), CurrentRenderPass(ESNRP_NONE)
\r
68 ISceneManager::setDebugName("CSceneManager ISceneManager");
\r
69 ISceneNode::setDebugName("CSceneManager ISceneNode");
\r
72 // root node's scene manager
\r
73 SceneManager = this;
\r
82 CursorControl->grab();
\r
85 GUIEnvironment->grab();
\r
87 // create mesh cache if not there already
\r
89 MeshCache = new CMeshCache();
\r
93 // set scene parameters
\r
94 Parameters = new io::CAttributes();
\r
95 Parameters->setAttribute(DEBUG_NORMAL_LENGTH, 1.f);
\r
96 Parameters->setAttribute(DEBUG_NORMAL_COLOR, video::SColor(255, 34, 221, 221));
\r
98 // create collision manager
\r
99 CollisionManager = new CSceneCollisionManager(this, Driver);
\r
101 // add file format loaders. add the least commonly used ones first,
\r
102 // as these are checked last
\r
104 // TODO: now that we have multiple scene managers, these should be
\r
105 // shallow copies from the previous manager if there is one.
\r
107 #ifdef _IRR_COMPILE_WITH_X_LOADER_
\r
108 MeshLoaderList.push_back(new CXMeshFileLoader(this, FileSystem));
\r
110 #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_
\r
111 MeshLoaderList.push_back(new COBJMeshFileLoader(this, FileSystem));
\r
113 #ifdef _IRR_COMPILE_WITH_B3D_LOADER_
\r
114 MeshLoaderList.push_back(new CB3DMeshFileLoader(this));
\r
118 ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this);
\r
119 registerSceneNodeFactory(factory);
\r
123 static bool initProfile = false;
\r
126 initProfile = true;
\r
127 getProfiler().add(EPID_SM_DRAW_ALL, L"drawAll", L"Irrlicht scene");
\r
128 getProfiler().add(EPID_SM_ANIMATE, L"animate", L"Irrlicht scene");
\r
129 getProfiler().add(EPID_SM_RENDER_CAMERAS, L"cameras", L"Irrlicht scene");
\r
130 getProfiler().add(EPID_SM_RENDER_LIGHTS, L"lights", L"Irrlicht scene");
\r
131 getProfiler().add(EPID_SM_RENDER_SKYBOXES, L"skyboxes", L"Irrlicht scene");
\r
132 getProfiler().add(EPID_SM_RENDER_DEFAULT, L"defaultnodes", L"Irrlicht scene");
\r
133 getProfiler().add(EPID_SM_RENDER_SHADOWS, L"shadows", L"Irrlicht scene");
\r
134 getProfiler().add(EPID_SM_RENDER_TRANSPARENT, L"transp.nodes", L"Irrlicht scene");
\r
135 getProfiler().add(EPID_SM_RENDER_EFFECT, L"effectnodes", L"Irrlicht scene");
\r
136 getProfiler().add(EPID_SM_RENDER_GUI_NODES, L"guinodes", L"Irrlicht scene");
\r
137 getProfiler().add(EPID_SM_REGISTER, L"reg.render.node", L"Irrlicht scene");
\r
144 CSceneManager::~CSceneManager()
\r
146 clearDeletionList();
\r
148 //! force to remove hardwareTextures from the driver
\r
149 //! because Scenes may hold internally data bounded to sceneNodes
\r
150 //! which may be destroyed twice
\r
152 Driver->removeAllHardwareBuffers();
\r
155 FileSystem->drop();
\r
158 CursorControl->drop();
\r
160 if (CollisionManager)
\r
161 CollisionManager->drop();
\r
163 if (GUIEnvironment)
\r
164 GUIEnvironment->drop();
\r
167 for (i=0; i<MeshLoaderList.size(); ++i)
\r
168 MeshLoaderList[i]->drop();
\r
170 for (i=0; i<SceneLoaderList.size(); ++i)
\r
171 SceneLoaderList[i]->drop();
\r
174 ActiveCamera->drop();
\r
181 Parameters->drop();
\r
183 for (i=0; i<SceneNodeFactoryList.size(); ++i)
\r
184 SceneNodeFactoryList[i]->drop();
\r
186 // remove all nodes before dropping the driver
\r
187 // as render targets may be destroyed twice
\r
196 //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped.
\r
197 IAnimatedMesh* CSceneManager::getMesh(const io::path& filename, const io::path& alternativeCacheName)
\r
199 io::path cacheName = alternativeCacheName.empty() ? filename : alternativeCacheName;
\r
200 IAnimatedMesh* msh = MeshCache->getMeshByName(cacheName);
\r
204 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
207 os::Printer::log("Could not load mesh, because file could not be opened: ", filename, ELL_ERROR);
\r
211 msh = getUncachedMesh(file, filename, cacheName);
\r
219 //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped.
\r
220 IAnimatedMesh* CSceneManager::getMesh(io::IReadFile* file)
\r
225 io::path name = file->getFileName();
\r
226 IAnimatedMesh* msh = MeshCache->getMeshByName(name);
\r
230 msh = getUncachedMesh(file, name, name);
\r
235 // load and create a mesh which we know already isn't in the cache and put it in there
\r
236 IAnimatedMesh* CSceneManager::getUncachedMesh(io::IReadFile* file, const io::path& filename, const io::path& cachename)
\r
238 IAnimatedMesh* msh = 0;
\r
240 // iterate the list in reverse order so user-added loaders can override the built-in ones
\r
241 s32 count = MeshLoaderList.size();
\r
242 for (s32 i=count-1; i>=0; --i)
\r
244 if (MeshLoaderList[i]->isALoadableFileExtension(filename))
\r
246 // reset file to avoid side effects of previous calls to createMesh
\r
248 msh = MeshLoaderList[i]->createMesh(file);
\r
251 MeshCache->addMesh(cachename, msh);
\r
259 os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR);
\r
261 os::Printer::log("Loaded mesh", filename, ELL_DEBUG);
\r
266 //! returns the video driver
\r
267 video::IVideoDriver* CSceneManager::getVideoDriver()
\r
273 //! returns the GUI Environment
\r
274 gui::IGUIEnvironment* CSceneManager::getGUIEnvironment()
\r
276 return GUIEnvironment;
\r
279 //! Get the active FileSystem
\r
280 /** \return Pointer to the FileSystem
\r
281 This pointer should not be dropped. See IReferenceCounted::drop() for more information. */
\r
282 io::IFileSystem* CSceneManager::getFileSystem()
\r
288 //! adds a scene node for rendering a static mesh
\r
289 //! the returned pointer must not be dropped.
\r
290 IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id,
\r
291 const core::vector3df& position, const core::vector3df& rotation,
\r
292 const core::vector3df& scale, bool alsoAddIfMeshPointerZero)
\r
294 if (!alsoAddIfMeshPointerZero && !mesh)
\r
300 IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale);
\r
307 //! adds a scene node for rendering an animated mesh model
\r
308 IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id,
\r
309 const core::vector3df& position, const core::vector3df& rotation,
\r
310 const core::vector3df& scale, bool alsoAddIfMeshPointerZero)
\r
312 if (!alsoAddIfMeshPointerZero && !mesh)
\r
318 IAnimatedMeshSceneNode* node =
\r
319 new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale);
\r
326 //! Adds a camera scene node to the tree and sets it as active camera.
\r
327 //! \param position: Position of the space relative to its parent where the camera will be placed.
\r
328 //! \param lookat: Position where the camera will look at. Also known as target.
\r
329 //! \param parent: Parent scene node of the camera. Can be null. If the parent moves,
\r
330 //! the camera will move too.
\r
331 //! \return Returns pointer to interface to camera
\r
332 ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent,
\r
333 const core::vector3df& position, const core::vector3df& lookat, s32 id,
\r
339 ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat);
\r
342 setActiveCamera(node);
\r
349 //! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element,
\r
350 //! which always looks to the camera. It is usually used for things like explosions, fire,
\r
351 //! lensflares and things like that.
\r
352 IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent,
\r
353 const core::dimension2d<f32>& size, const core::vector3df& position, s32 id,
\r
354 video::SColor colorTop, video::SColor colorBottom
\r
357 #ifdef _IRR_COMPILE_WITH_BILLBOARD_SCENENODE_
\r
361 IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size,
\r
362 colorTop, colorBottom);
\r
372 //! Adds an empty scene node.
\r
373 ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id)
\r
378 ISceneNode* node = new CEmptySceneNode(parent, this, id);
\r
385 //! Adds a dummy transformation scene node to the scene graph.
\r
386 IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode(
\r
387 ISceneNode* parent, s32 id)
\r
392 IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode(
\r
400 //! Returns the root scene node. This is the scene node which is parent
\r
401 //! of all scene nodes. The root scene node is a special scene node which
\r
402 //! only exists to manage all scene nodes. It is not rendered and cannot
\r
403 //! be removed from the scene.
\r
404 //! \return Returns a pointer to the root scene node.
\r
405 ISceneNode* CSceneManager::getRootSceneNode()
\r
411 //! Returns the current active camera.
\r
412 //! \return The active camera is returned. Note that this can be NULL, if there
\r
413 //! was no camera created yet.
\r
414 ICameraSceneNode* CSceneManager::getActiveCamera() const
\r
416 return ActiveCamera;
\r
420 //! Sets the active camera. The previous active camera will be deactivated.
\r
421 //! \param camera: The new camera which should be active.
\r
422 void CSceneManager::setActiveCamera(ICameraSceneNode* camera)
\r
427 ActiveCamera->drop();
\r
429 ActiveCamera = camera;
\r
433 //! renders the node.
\r
434 void CSceneManager::render()
\r
439 //! returns the axis aligned bounding box of this node
\r
440 const core::aabbox3d<f32>& CSceneManager::getBoundingBox() const
\r
442 _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.
\r
444 static const core::aabbox3d<f32> dummy;
\r
449 //! returns if node is culled
\r
450 bool CSceneManager::isCulled(const ISceneNode* node) const
\r
452 const ICameraSceneNode* cam = getActiveCamera();
\r
457 bool result = false;
\r
459 // has occlusion query information
\r
460 if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY)
\r
462 result = (Driver->getOcclusionQueryResult(const_cast<ISceneNode*>(node))==0);
\r
465 // can be seen by a bounding box ?
\r
466 if (!result && (node->getAutomaticCulling() & scene::EAC_BOX))
\r
468 core::aabbox3d<f32> tbox = node->getBoundingBox();
\r
469 node->getAbsoluteTransformation().transformBoxEx(tbox);
\r
470 result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() ));
\r
473 // can be seen by a bounding sphere
\r
474 if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE))
\r
476 const core::aabbox3df nbox = node->getTransformedBoundingBox();
\r
477 const float rad = nbox.getRadius();
\r
478 const core::vector3df center = nbox.getCenter();
\r
480 const float camrad = cam->getViewFrustum()->getBoundingRadius();
\r
481 const core::vector3df camcenter = cam->getViewFrustum()->getBoundingCenter();
\r
483 const float dist = (center - camcenter).getLengthSQ();
\r
484 const float maxdist = (rad + camrad) * (rad + camrad);
\r
486 result = dist > maxdist;
\r
489 // can be seen by cam pyramid planes ?
\r
490 if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX))
\r
492 SViewFrustum frust = *cam->getViewFrustum();
\r
494 //transform the frustum to the node's current absolute transformation
\r
495 core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE);
\r
496 //invTrans.makeInverse();
\r
497 frust.transform(invTrans);
\r
499 core::vector3df edges[8];
\r
500 node->getBoundingBox().getEdges(edges);
\r
502 for (s32 i=0; i<scene::SViewFrustum::VF_PLANE_COUNT; ++i)
\r
504 bool boxInFrustum=false;
\r
505 for (u32 j=0; j<8; ++j)
\r
507 if (frust.planes[i].classifyPointRelation(edges[j]) != core::ISREL3D_FRONT)
\r
526 //! registers a node for rendering it at a specific time.
\r
527 u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass)
\r
529 IRR_PROFILE(CProfileScope p1(EPID_SM_REGISTER);)
\r
534 // take camera if it is not already registered
\r
538 for (u32 i = 0; i != CameraList.size(); ++i)
\r
540 if (CameraList[i] == node)
\r
548 CameraList.push_back(node);
\r
552 case ESNRP_SKY_BOX:
\r
553 SkyBoxList.push_back(node);
\r
557 if (!isCulled(node))
\r
559 SolidNodeList.push_back(node);
\r
563 case ESNRP_TRANSPARENT:
\r
564 if (!isCulled(node))
\r
566 TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos));
\r
570 case ESNRP_TRANSPARENT_EFFECT:
\r
571 if (!isCulled(node))
\r
573 TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos));
\r
577 case ESNRP_AUTOMATIC:
\r
578 if (!isCulled(node))
\r
580 const u32 count = node->getMaterialCount();
\r
583 for (u32 i=0; i<count; ++i)
\r
585 if (Driver->needsTransparentRenderPass(node->getMaterial(i)))
\r
587 // register as transparent node
\r
588 TransparentNodeEntry e(node, camWorldPos);
\r
589 TransparentNodeList.push_back(e);
\r
595 // not transparent, register as solid
\r
598 SolidNodeList.push_back(node);
\r
604 if (!isCulled(node))
\r
606 GuiNodeList.push_back(node);
\r
610 case ESNRP_NONE: // ignore this one
\r
614 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
615 s32 index = Parameters->findAttribute("calls");
\r
616 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);
\r
620 index = Parameters->findAttribute("culled");
\r
621 Parameters->setAttribute(index, Parameters->getAttributeAsInt(index)+1);
\r
628 void CSceneManager::clearAllRegisteredNodesForRendering()
\r
630 CameraList.clear();
\r
631 SkyBoxList.clear();
\r
632 SolidNodeList.clear();
\r
633 TransparentNodeList.clear();
\r
634 TransparentEffectNodeList.clear();
\r
635 GuiNodeList.clear();
\r
638 //! This method is called just before the rendering process of the whole scene.
\r
639 //! draws all scene nodes
\r
640 void CSceneManager::drawAll()
\r
642 IRR_PROFILE(CProfileScope psAll(EPID_SM_DRAW_ALL);)
\r
647 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
648 // reset attributes
\r
649 Parameters->setAttribute("culled", 0);
\r
650 Parameters->setAttribute("calls", 0);
\r
651 Parameters->setAttribute("drawn_solid", 0);
\r
652 Parameters->setAttribute("drawn_transparent", 0);
\r
653 Parameters->setAttribute("drawn_transparent_effect", 0);
\r
656 u32 i; // new ISO for scoping problem in some compilers
\r
658 // reset all transforms
\r
659 Driver->setMaterial(video::SMaterial());
\r
660 Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );
\r
661 Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );
\r
662 Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );
\r
663 for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i)
\r
664 Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix );
\r
665 // TODO: This should not use an attribute here but a real parameter when necessary (too slow!)
\r
666 Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT));
\r
668 // do animations and other stuff.
\r
669 IRR_PROFILE(getProfiler().start(EPID_SM_ANIMATE));
\r
670 OnAnimate(os::Timer::getTime());
\r
671 IRR_PROFILE(getProfiler().stop(EPID_SM_ANIMATE));
\r
674 First Scene Node for prerendering should be the active camera
\r
675 consistent Camera is needed for culling
\r
677 IRR_PROFILE(getProfiler().start(EPID_SM_RENDER_CAMERAS));
\r
678 camWorldPos.set(0,0,0);
\r
681 ActiveCamera->render();
\r
682 camWorldPos = ActiveCamera->getAbsolutePosition();
\r
684 IRR_PROFILE(getProfiler().stop(EPID_SM_RENDER_CAMERAS));
\r
686 // let all nodes register themselves
\r
687 OnRegisterSceneNode();
\r
689 //render camera scenes
\r
691 IRR_PROFILE(CProfileScope psCam(EPID_SM_RENDER_CAMERAS);)
\r
692 CurrentRenderPass = ESNRP_CAMERA;
\r
693 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
\r
695 for (i=0; i<CameraList.size(); ++i)
\r
696 CameraList[i]->render();
\r
698 CameraList.set_used(0);
\r
703 IRR_PROFILE(CProfileScope psSkyBox(EPID_SM_RENDER_SKYBOXES);)
\r
704 CurrentRenderPass = ESNRP_SKY_BOX;
\r
705 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
\r
707 for (i=0; i<SkyBoxList.size(); ++i)
\r
708 SkyBoxList[i]->render();
\r
710 SkyBoxList.set_used(0);
\r
713 // render default objects
\r
715 IRR_PROFILE(CProfileScope psDefault(EPID_SM_RENDER_DEFAULT);)
\r
716 CurrentRenderPass = ESNRP_SOLID;
\r
717 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
\r
719 SolidNodeList.sort(); // sort by textures
\r
721 for (i=0; i<SolidNodeList.size(); ++i)
\r
722 SolidNodeList[i].Node->render();
\r
724 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
725 Parameters->setAttribute("drawn_solid", (s32) SolidNodeList.size() );
\r
727 SolidNodeList.set_used(0);
\r
730 // render transparent objects.
\r
732 IRR_PROFILE(CProfileScope psTrans(EPID_SM_RENDER_TRANSPARENT);)
\r
733 CurrentRenderPass = ESNRP_TRANSPARENT;
\r
734 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
\r
736 TransparentNodeList.sort(); // sort by distance from camera
\r
737 for (i=0; i<TransparentNodeList.size(); ++i)
\r
738 TransparentNodeList[i].Node->render();
\r
740 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
741 Parameters->setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() );
\r
743 TransparentNodeList.set_used(0);
\r
746 // render transparent effect objects.
\r
748 IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_EFFECT);)
\r
749 CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT;
\r
750 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
\r
752 TransparentEffectNodeList.sort(); // sort by distance from camera
\r
754 for (i=0; i<TransparentEffectNodeList.size(); ++i)
\r
755 TransparentEffectNodeList[i].Node->render();
\r
756 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
757 Parameters->setAttribute("drawn_transparent_effect", (s32) TransparentEffectNodeList.size());
\r
759 TransparentEffectNodeList.set_used(0);
\r
762 // render custom gui nodes
\r
764 IRR_PROFILE(CProfileScope psEffect(EPID_SM_RENDER_GUI_NODES);)
\r
765 CurrentRenderPass = ESNRP_GUI;
\r
766 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
\r
768 for (i=0; i<GuiNodeList.size(); ++i)
\r
769 GuiNodeList[i]->render();
\r
770 #ifdef _IRR_SCENEMANAGER_DEBUG
\r
771 Parameters->setAttribute("drawn_gui_nodes", (s32) GuiNodeList.size());
\r
773 GuiNodeList.set_used(0);
\r
775 clearDeletionList();
\r
777 CurrentRenderPass = ESNRP_NONE;
\r
781 //! Adds an external mesh loader.
\r
782 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)
\r
784 if (!externalLoader)
\r
787 externalLoader->grab();
\r
788 MeshLoaderList.push_back(externalLoader);
\r
792 //! Returns the number of mesh loaders supported by Irrlicht at this time
\r
793 u32 CSceneManager::getMeshLoaderCount() const
\r
795 return MeshLoaderList.size();
\r
799 //! Retrieve the given mesh loader
\r
800 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const
\r
802 if (index < MeshLoaderList.size())
\r
803 return MeshLoaderList[index];
\r
809 //! Adds an external scene loader.
\r
810 void CSceneManager::addExternalSceneLoader(ISceneLoader* externalLoader)
\r
812 if (!externalLoader)
\r
815 externalLoader->grab();
\r
816 SceneLoaderList.push_back(externalLoader);
\r
820 //! Returns the number of scene loaders
\r
821 u32 CSceneManager::getSceneLoaderCount() const
\r
823 return SceneLoaderList.size();
\r
827 //! Retrieve the given scene loader
\r
828 ISceneLoader* CSceneManager::getSceneLoader(u32 index) const
\r
830 if (index < SceneLoaderList.size())
\r
831 return SceneLoaderList[index];
\r
836 //! Returns a pointer to the scene collision manager.
\r
837 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()
\r
839 return CollisionManager;
\r
843 //! Returns a pointer to the mesh manipulator.
\r
844 IMeshManipulator* CSceneManager::getMeshManipulator()
\r
846 return Driver->getMeshManipulator();
\r
850 //! Adds a scene node to the deletion queue.
\r
851 void CSceneManager::addToDeletionQueue(ISceneNode* node)
\r
857 DeletionList.push_back(node);
\r
861 //! clears the deletion list
\r
862 void CSceneManager::clearDeletionList()
\r
864 if (DeletionList.empty())
\r
867 for (u32 i=0; i<DeletionList.size(); ++i)
\r
869 DeletionList[i]->remove();
\r
870 DeletionList[i]->drop();
\r
873 DeletionList.clear();
\r
877 //! Returns the first scene node with the specified name.
\r
878 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)
\r
881 start = getRootSceneNode();
\r
883 if (!strcmp(start->getName(),name))
\r
886 ISceneNode* node = 0;
\r
888 const ISceneNodeList& list = start->getChildren();
\r
889 ISceneNodeList::ConstIterator it = list.begin();
\r
890 for (; it!=list.end(); ++it)
\r
892 node = getSceneNodeFromName(name, *it);
\r
901 //! Returns the first scene node with the specified id.
\r
902 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)
\r
905 start = getRootSceneNode();
\r
907 if (start->getID() == id)
\r
910 ISceneNode* node = 0;
\r
912 const ISceneNodeList& list = start->getChildren();
\r
913 ISceneNodeList::ConstIterator it = list.begin();
\r
914 for (; it!=list.end(); ++it)
\r
916 node = getSceneNodeFromId(id, *it);
\r
925 //! Returns the first scene node with the specified type.
\r
926 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)
\r
929 start = getRootSceneNode();
\r
931 if (start->getType() == type || ESNT_ANY == type)
\r
934 ISceneNode* node = 0;
\r
936 const ISceneNodeList& list = start->getChildren();
\r
937 ISceneNodeList::ConstIterator it = list.begin();
\r
938 for (; it!=list.end(); ++it)
\r
940 node = getSceneNodeFromType(type, *it);
\r
949 //! returns scene nodes by type.
\r
950 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)
\r
953 start = getRootSceneNode();
\r
955 if (start->getType() == type || ESNT_ANY == type)
\r
956 outNodes.push_back(start);
\r
958 const ISceneNodeList& list = start->getChildren();
\r
959 ISceneNodeList::ConstIterator it = list.begin();
\r
961 for (; it!=list.end(); ++it)
\r
963 getSceneNodesFromType(type, outNodes, *it);
\r
968 //! Posts an input event to the environment. Usually you do not have to
\r
969 //! use this method, it is used by the internal engine.
\r
970 bool CSceneManager::postEventFromUser(const SEvent& event)
\r
973 ICameraSceneNode* cam = getActiveCamera();
\r
975 ret = cam->OnEvent(event);
\r
981 //! Removes all children of this scene node
\r
982 void CSceneManager::removeAll()
\r
984 ISceneNode::removeAll();
\r
985 setActiveCamera(0);
\r
986 // Make sure the driver is reset, might need a more complex method at some point
\r
988 Driver->setMaterial(video::SMaterial());
\r
992 //! Clears the whole scene. All scene nodes are removed.
\r
993 void CSceneManager::clear()
\r
999 //! Returns interface to the parameters set in this scene.
\r
1000 io::IAttributes* CSceneManager::getParameters()
\r
1002 return Parameters;
\r
1006 //! Returns current render pass.
\r
1007 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const
\r
1009 return CurrentRenderPass;
\r
1013 //! Returns an interface to the mesh cache which is shared between all existing scene managers.
\r
1014 IMeshCache* CSceneManager::getMeshCache()
\r
1020 //! Creates a new scene manager.
\r
1021 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)
\r
1023 CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment);
\r
1026 manager->cloneMembers(this, manager);
\r
1032 //! Returns the default scene node factory which can create all built in scene nodes
\r
1033 ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory()
\r
1035 return getSceneNodeFactory(0);
\r
1039 //! Adds a scene node factory to the scene manager.
\r
1040 void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd)
\r
1044 factoryToAdd->grab();
\r
1045 SceneNodeFactoryList.push_back(factoryToAdd);
\r
1050 //! Returns amount of registered scene node factories.
\r
1051 u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const
\r
1053 return SceneNodeFactoryList.size();
\r
1057 //! Returns a scene node factory by index
\r
1058 ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index)
\r
1060 if (index < SceneNodeFactoryList.size())
\r
1061 return SceneNodeFactoryList[index];
\r
1066 //! Saves the current scene into a file.
\r
1067 //! \param filename: Name of the file .
\r
1068 bool CSceneManager::saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)
\r
1071 io::IWriteFile* file = FileSystem->createAndWriteFile(filename);
\r
1074 ret = saveScene(file, userDataSerializer, node);
\r
1078 os::Printer::log("Unable to open file", filename, ELL_ERROR);
\r
1084 //! Saves the current scene into a file.
\r
1085 bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node)
\r
1091 //! Loads a scene.
\r
1092 bool CSceneManager::loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)
\r
1094 io::IReadFile* file = FileSystem->createAndOpenFile(filename);
\r
1097 os::Printer::log("Unable to open scene file", filename.c_str(), ELL_ERROR);
\r
1101 const bool ret = loadScene(file, userDataSerializer, rootNode);
\r
1108 //! Loads a scene. Note that the current scene is not cleared before.
\r
1109 bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode)
\r
1113 os::Printer::log("Unable to open scene file", ELL_ERROR);
\r
1119 // try scene loaders in reverse order
\r
1120 s32 i = SceneLoaderList.size()-1;
\r
1121 for (; i >= 0 && !ret; --i)
\r
1122 if (SceneLoaderList[i]->isALoadableFileFormat(file))
\r
1123 ret = SceneLoaderList[i]->loadScene(file, userDataSerializer, rootNode);
\r
1126 os::Printer::log("Could not load scene file, perhaps the format is unsupported: ", file->getFileName().c_str(), ELL_ERROR);
\r
1132 //! Returns a typename from a scene node type or null if not found
\r
1133 const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type)
\r
1135 const char* name = 0;
\r
1137 for (s32 i=(s32)SceneNodeFactoryList.size()-1; !name && i>=0; --i)
\r
1138 name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type);
\r
1143 //! Adds a scene node to the scene by name
\r
1144 ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent)
\r
1146 ISceneNode* node = 0;
\r
1148 for (s32 i=(s32)SceneNodeFactoryList.size()-1; i>=0 && !node; --i)
\r
1149 node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent);
\r
1154 //! Writes attributes of the scene node.
\r
1155 void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
\r
1157 out->addString ("Name", Name.c_str());
\r
1158 out->addInt ("Id", ID );
\r
1159 out->addColorf ("AmbientLight", AmbientLight);
\r
1161 // fog attributes from video driver
\r
1162 video::SColor color;
\r
1163 video::E_FOG_TYPE fogType;
\r
1164 f32 start, end, density;
\r
1165 bool pixelFog, rangeFog;
\r
1167 Driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog);
\r
1169 out->addEnum("FogType", fogType, video::FogTypeNames);
\r
1170 out->addColorf("FogColor", color);
\r
1171 out->addFloat("FogStart", start);
\r
1172 out->addFloat("FogEnd", end);
\r
1173 out->addFloat("FogDensity", density);
\r
1174 out->addBool("FogPixel", pixelFog);
\r
1175 out->addBool("FogRange", rangeFog);
\r
1178 //! Reads attributes of the scene node.
\r
1179 void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
\r
1181 Name = in->getAttributeAsString("Name");
\r
1182 ID = in->getAttributeAsInt("Id");
\r
1183 AmbientLight = in->getAttributeAsColorf("AmbientLight");
\r
1186 video::SColor color;
\r
1187 video::E_FOG_TYPE fogType;
\r
1188 f32 start, end, density;
\r
1189 bool pixelFog, rangeFog;
\r
1190 if (in->existsAttribute("FogType"))
\r
1192 fogType = (video::E_FOG_TYPE) in->getAttributeAsEnumeration("FogType", video::FogTypeNames);
\r
1193 color = in->getAttributeAsColorf("FogColor").toSColor();
\r
1194 start = in->getAttributeAsFloat("FogStart");
\r
1195 end = in->getAttributeAsFloat("FogEnd");
\r
1196 density = in->getAttributeAsFloat("FogDensity");
\r
1197 pixelFog = in->getAttributeAsBool("FogPixel");
\r
1198 rangeFog = in->getAttributeAsBool("FogRange");
\r
1199 Driver->setFog(color, fogType, start, end, density, pixelFog, rangeFog);
\r
1202 RelativeTranslation.set(0,0,0);
\r
1203 RelativeRotation.set(0,0,0);
\r
1204 RelativeScale.set(1,1,1);
\r
1206 AutomaticCullingState = scene::EAC_BOX;
\r
1207 DebugDataVisible = scene::EDS_OFF;
\r
1208 IsDebugObject = false;
\r
1210 updateAbsolutePosition();
\r
1214 //! Sets ambient color of the scene
\r
1215 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)
\r
1217 AmbientLight = ambientColor;
\r
1221 //! Returns ambient color of the scene
\r
1222 const video::SColorf& CSceneManager::getAmbientLight() const
\r
1224 return AmbientLight;
\r
1228 //! Get a skinned mesh, which is not available as header-only code
\r
1229 ISkinnedMesh* CSceneManager::createSkinnedMesh()
\r
1231 #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
\r
1232 return new CSkinnedMesh();
\r
1238 //! Returns a mesh writer implementation if available
\r
1239 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)
\r
1243 case EMWT_IRR_MESH:
\r
1244 case EMWT_COLLADA:
\r
1247 #ifdef _IRR_COMPILE_WITH_STL_WRITER_
\r
1248 return new CSTLMeshWriter(this);
\r
1253 #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_
\r
1254 return new COBJMeshWriter(this, FileSystem);
\r
1260 #ifdef _IRR_COMPILE_WITH_PLY_WRITER_
\r
1261 return new CPLYMeshWriter();
\r
1267 #ifdef _IRR_COMPILE_WITH_B3D_WRITER_
\r
1268 return new CB3DMeshWriter();
\r
1278 // creates a scenemanager
\r
1279 ISceneManager* createSceneManager(video::IVideoDriver* driver,
\r
1280 io::IFileSystem* fs, gui::ICursorControl* cursorcontrol,
\r
1281 gui::IGUIEnvironment *guiEnvironment)
\r
1283 return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment );
\r
1287 } // end namespace scene
\r
1288 } // end namespace irr
\r