]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CSceneManager.cpp
Add back LightManager
[irrlicht.git] / source / Irrlicht / CSceneManager.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CSceneManager.h"\r
6 #include "IVideoDriver.h"\r
7 #include "IFileSystem.h"\r
8 #include "SAnimatedMesh.h"\r
9 #include "CMeshCache.h"\r
10 #include "IGUIEnvironment.h"\r
11 #include "IMaterialRenderer.h"\r
12 #include "IReadFile.h"\r
13 #include "IWriteFile.h"\r
14 \r
15 #include "os.h"\r
16 \r
17 #include "CSkinnedMesh.h"\r
18 #include "CXMeshFileLoader.h"\r
19 #include "COBJMeshFileLoader.h"\r
20 #include "CB3DMeshFileLoader.h"\r
21 #include "CBillboardSceneNode.h"\r
22 #include "CAnimatedMeshSceneNode.h"\r
23 #include "CCameraSceneNode.h"\r
24 #include "CLightSceneNode.h"\r
25 #include "CMeshSceneNode.h"\r
26 \r
27 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
28 #include "CShadowVolumeSceneNode.h"\r
29 #else\r
30 #include "IShadowVolumeSceneNode.h"\r
31 #endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
32 \r
33 #include "CDummyTransformationSceneNode.h"\r
34 #include "CEmptySceneNode.h"\r
35 \r
36 #include "CSceneCollisionManager.h"\r
37 \r
38 namespace irr\r
39 {\r
40 namespace scene\r
41 {\r
42 \r
43 //! constructor\r
44 CSceneManager::CSceneManager(video::IVideoDriver* driver,\r
45                 gui::ICursorControl* cursorControl, IMeshCache* cache)\r
46 : ISceneNode(0, 0), Driver(driver),\r
47         CursorControl(cursorControl),\r
48         ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), Parameters(0),\r
49         MeshCache(cache), CurrentRenderPass(ESNRP_NONE), LightManager(0)\r
50 {\r
51         #ifdef _DEBUG\r
52         ISceneManager::setDebugName("CSceneManager ISceneManager");\r
53         ISceneNode::setDebugName("CSceneManager ISceneNode");\r
54         #endif\r
55 \r
56         // root node's scene manager\r
57         SceneManager = this;\r
58 \r
59         if (Driver)\r
60                 Driver->grab();\r
61 \r
62         if (CursorControl)\r
63                 CursorControl->grab();\r
64 \r
65         // create mesh cache if not there already\r
66         if (!MeshCache)\r
67                 MeshCache = new CMeshCache();\r
68         else\r
69                 MeshCache->grab();\r
70 \r
71         // set scene parameters\r
72         Parameters = new io::CAttributes();\r
73 \r
74         // create collision manager\r
75         CollisionManager = new CSceneCollisionManager(this, Driver);\r
76 \r
77         // add file format loaders. add the least commonly used ones first,\r
78         // as these are checked last\r
79 \r
80         // TODO: now that we have multiple scene managers, these should be\r
81         // shallow copies from the previous manager if there is one.\r
82 \r
83         MeshLoaderList.push_back(new CXMeshFileLoader(this));\r
84         MeshLoaderList.push_back(new COBJMeshFileLoader(this));\r
85         MeshLoaderList.push_back(new CB3DMeshFileLoader(this));\r
86 }\r
87 \r
88 \r
89 //! destructor\r
90 CSceneManager::~CSceneManager()\r
91 {\r
92         clearDeletionList();\r
93 \r
94         //! force to remove hardwareTextures from the driver\r
95         //! because Scenes may hold internally data bounded to sceneNodes\r
96         //! which may be destroyed twice\r
97         if (Driver)\r
98                 Driver->removeAllHardwareBuffers();\r
99 \r
100         if (CursorControl)\r
101                 CursorControl->drop();\r
102 \r
103         if (CollisionManager)\r
104                 CollisionManager->drop();\r
105 \r
106         u32 i;\r
107         for (i=0; i<MeshLoaderList.size(); ++i)\r
108                 MeshLoaderList[i]->drop();\r
109 \r
110         if (ActiveCamera)\r
111                 ActiveCamera->drop();\r
112         ActiveCamera = 0;\r
113 \r
114         if (MeshCache)\r
115                 MeshCache->drop();\r
116 \r
117         if (Parameters)\r
118                 Parameters->drop();\r
119 \r
120         if (LightManager)\r
121                 LightManager->drop();\r
122 \r
123         // remove all nodes before dropping the driver\r
124         // as render targets may be destroyed twice\r
125 \r
126         removeAll();\r
127 \r
128         if (Driver)\r
129                 Driver->drop();\r
130 }\r
131 \r
132 \r
133 //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped.\r
134 IAnimatedMesh* CSceneManager::getMesh(io::IReadFile* file)\r
135 {\r
136         if (!file)\r
137                 return 0;\r
138 \r
139         io::path name = file->getFileName();\r
140         IAnimatedMesh* msh = MeshCache->getMeshByName(name);\r
141         if (msh)\r
142                 return msh;\r
143 \r
144         msh = getUncachedMesh(file, name, name);\r
145 \r
146         return msh;\r
147 }\r
148 \r
149 // load and create a mesh which we know already isn't in the cache and put it in there\r
150 IAnimatedMesh* CSceneManager::getUncachedMesh(io::IReadFile* file, const io::path& filename, const io::path& cachename)\r
151 {\r
152         IAnimatedMesh* msh = 0;\r
153 \r
154         // iterate the list in reverse order so user-added loaders can override the built-in ones\r
155         s32 count = MeshLoaderList.size();\r
156         for (s32 i=count-1; i>=0; --i)\r
157         {\r
158                 if (MeshLoaderList[i]->isALoadableFileExtension(filename))\r
159                 {\r
160                         // reset file to avoid side effects of previous calls to createMesh\r
161                         file->seek(0);\r
162                         msh = MeshLoaderList[i]->createMesh(file);\r
163                         if (msh)\r
164                         {\r
165                                 MeshCache->addMesh(cachename, msh);\r
166                                 msh->drop();\r
167                                 break;\r
168                         }\r
169                 }\r
170         }\r
171 \r
172         if (!msh)\r
173                 os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR);\r
174         else\r
175                 os::Printer::log("Loaded mesh", filename, ELL_DEBUG);\r
176 \r
177         return msh;\r
178 }\r
179 \r
180 //! returns the video driver\r
181 video::IVideoDriver* CSceneManager::getVideoDriver()\r
182 {\r
183         return Driver;\r
184 }\r
185 \r
186 \r
187 //! adds a scene node for rendering a static mesh\r
188 //! the returned pointer must not be dropped.\r
189 IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id,\r
190         const core::vector3df& position, const core::vector3df& rotation,\r
191         const core::vector3df& scale, bool alsoAddIfMeshPointerZero)\r
192 {\r
193         if (!alsoAddIfMeshPointerZero && !mesh)\r
194                 return 0;\r
195 \r
196         if (!parent)\r
197                 parent = this;\r
198 \r
199         IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale);\r
200         node->drop();\r
201 \r
202         return node;\r
203 }\r
204 \r
205 \r
206 //! adds a scene node for rendering an animated mesh model\r
207 IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id,\r
208         const core::vector3df& position, const core::vector3df& rotation,\r
209         const core::vector3df& scale, bool alsoAddIfMeshPointerZero)\r
210 {\r
211         if (!alsoAddIfMeshPointerZero && !mesh)\r
212                 return 0;\r
213 \r
214         if (!parent)\r
215                 parent = this;\r
216 \r
217         IAnimatedMeshSceneNode* node =\r
218                 new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale);\r
219         node->drop();\r
220 \r
221         return node;\r
222 }\r
223 \r
224 \r
225 //! Adds a camera scene node to the tree and sets it as active camera.\r
226 //! \param position: Position of the space relative to its parent where the camera will be placed.\r
227 //! \param lookat: Position where the camera will look at. Also known as target.\r
228 //! \param parent: Parent scene node of the camera. Can be null. If the parent moves,\r
229 //! the camera will move too.\r
230 //! \return Returns pointer to interface to camera\r
231 ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent,\r
232         const core::vector3df& position, const core::vector3df& lookat, s32 id,\r
233         bool makeActive)\r
234 {\r
235         if (!parent)\r
236                 parent = this;\r
237 \r
238         ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat);\r
239 \r
240         if (makeActive)\r
241                 setActiveCamera(node);\r
242         node->drop();\r
243 \r
244         return node;\r
245 }\r
246 \r
247 \r
248 //! Adds a dynamic light scene node. The light will cast dynamic light on all\r
249 //! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING\r
250 //! turned on. (This is the default setting in most scene nodes).\r
251 ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent,\r
252         const core::vector3df& position, video::SColorf color, f32 range, s32 id)\r
253 {\r
254         if (!parent)\r
255                 parent = this;\r
256 \r
257         ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range);\r
258         node->drop();\r
259 \r
260         return node;\r
261 }\r
262 \r
263 \r
264 //! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element,\r
265 //! which always looks to the camera. It is usually used for things like explosions, fire,\r
266 //! lensflares and things like that.\r
267 IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent,\r
268         const core::dimension2d<f32>& size, const core::vector3df& position, s32 id,\r
269         video::SColor colorTop, video::SColor colorBottom\r
270         )\r
271 {\r
272         if (!parent)\r
273                 parent = this;\r
274 \r
275         IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size,\r
276                 colorTop, colorBottom);\r
277         node->drop();\r
278 \r
279         return node;\r
280 }\r
281 \r
282 \r
283 //! Adds an empty scene node.\r
284 ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id)\r
285 {\r
286         if (!parent)\r
287                 parent = this;\r
288 \r
289         ISceneNode* node = new CEmptySceneNode(parent, this, id);\r
290         node->drop();\r
291 \r
292         return node;\r
293 }\r
294 \r
295 \r
296 //! Adds a dummy transformation scene node to the scene graph.\r
297 IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode(\r
298         ISceneNode* parent, s32 id)\r
299 {\r
300         if (!parent)\r
301                 parent = this;\r
302 \r
303         IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode(\r
304                 parent, this, id);\r
305         node->drop();\r
306 \r
307         return node;\r
308 }\r
309 \r
310 \r
311 //! Returns the root scene node. This is the scene node which is parent\r
312 //! of all scene nodes. The root scene node is a special scene node which\r
313 //! only exists to manage all scene nodes. It is not rendered and cannot\r
314 //! be removed from the scene.\r
315 //! \return Returns a pointer to the root scene node.\r
316 ISceneNode* CSceneManager::getRootSceneNode()\r
317 {\r
318         return this;\r
319 }\r
320 \r
321 \r
322 //! Returns the current active camera.\r
323 //! \return The active camera is returned. Note that this can be NULL, if there\r
324 //! was no camera created yet.\r
325 ICameraSceneNode* CSceneManager::getActiveCamera() const\r
326 {\r
327         return ActiveCamera;\r
328 }\r
329 \r
330 \r
331 //! Sets the active camera. The previous active camera will be deactivated.\r
332 //! \param camera: The new camera which should be active.\r
333 void CSceneManager::setActiveCamera(ICameraSceneNode* camera)\r
334 {\r
335         if (camera)\r
336                 camera->grab();\r
337         if (ActiveCamera)\r
338                 ActiveCamera->drop();\r
339 \r
340         ActiveCamera = camera;\r
341 }\r
342 \r
343 \r
344 //! renders the node.\r
345 void CSceneManager::render()\r
346 {\r
347 }\r
348 \r
349 \r
350 //! returns the axis aligned bounding box of this node\r
351 const core::aabbox3d<f32>& CSceneManager::getBoundingBox() const\r
352 {\r
353         _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager should never be used.\r
354 \r
355         static const core::aabbox3d<f32> dummy;\r
356         return dummy;\r
357 }\r
358 \r
359 \r
360 //! returns if node is culled\r
361 bool CSceneManager::isCulled(const ISceneNode* node) const\r
362 {\r
363         const ICameraSceneNode* cam = getActiveCamera();\r
364         if (!cam)\r
365         {\r
366                 return false;\r
367         }\r
368         bool result = false;\r
369 \r
370         // has occlusion query information\r
371         if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY)\r
372         {\r
373                 result = (Driver->getOcclusionQueryResult(const_cast<ISceneNode*>(node))==0);\r
374         }\r
375 \r
376         // can be seen by a bounding box ?\r
377         if (!result && (node->getAutomaticCulling() & scene::EAC_BOX))\r
378         {\r
379                 core::aabbox3d<f32> tbox = node->getBoundingBox();\r
380                 node->getAbsoluteTransformation().transformBoxEx(tbox);\r
381                 result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() ));\r
382         }\r
383 \r
384         // can be seen by a bounding sphere\r
385         if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE))\r
386         {\r
387                 const core::aabbox3df nbox = node->getTransformedBoundingBox();\r
388                 const float rad = nbox.getRadius();\r
389                 const core::vector3df center = nbox.getCenter();\r
390 \r
391                 const float camrad = cam->getViewFrustum()->getBoundingRadius();\r
392                 const core::vector3df camcenter = cam->getViewFrustum()->getBoundingCenter();\r
393 \r
394                 const float dist = (center - camcenter).getLengthSQ();\r
395                 const float maxdist = (rad + camrad) * (rad + camrad);\r
396 \r
397                 result = dist > maxdist;\r
398         }\r
399 \r
400         // can be seen by cam pyramid planes ?\r
401         if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX))\r
402         {\r
403                 SViewFrustum frust = *cam->getViewFrustum();\r
404 \r
405                 //transform the frustum to the node's current absolute transformation\r
406                 core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE);\r
407                 //invTrans.makeInverse();\r
408                 frust.transform(invTrans);\r
409 \r
410                 core::vector3df edges[8];\r
411                 node->getBoundingBox().getEdges(edges);\r
412 \r
413                 for (s32 i=0; i<scene::SViewFrustum::VF_PLANE_COUNT; ++i)\r
414                 {\r
415                         bool boxInFrustum=false;\r
416                         for (u32 j=0; j<8; ++j)\r
417                         {\r
418                                 if (frust.planes[i].classifyPointRelation(edges[j]) != core::ISREL3D_FRONT)\r
419                                 {\r
420                                         boxInFrustum=true;\r
421                                         break;\r
422                                 }\r
423                         }\r
424 \r
425                         if (!boxInFrustum)\r
426                         {\r
427                                 result = true;\r
428                                 break;\r
429                         }\r
430                 }\r
431         }\r
432 \r
433         return result;\r
434 }\r
435 \r
436 \r
437 //! registers a node for rendering it at a specific time.\r
438 u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass)\r
439 {\r
440         u32 taken = 0;\r
441 \r
442         switch(pass)\r
443         {\r
444                 // take camera if it is not already registered\r
445         case ESNRP_CAMERA:\r
446                 {\r
447                         taken = 1;\r
448                         for (u32 i = 0; i != CameraList.size(); ++i)\r
449                         {\r
450                                 if (CameraList[i] == node)\r
451                                 {\r
452                                         taken = 0;\r
453                                         break;\r
454                                 }\r
455                         }\r
456                         if (taken)\r
457                         {\r
458                                 CameraList.push_back(node);\r
459                         }\r
460                 }\r
461                 break;\r
462         case ESNRP_LIGHT:\r
463                 // TODO: Point Light culling..\r
464                 // Lighting model in irrlicht has to be redone..\r
465                 //if (!isCulled(node))\r
466                 {\r
467                         LightList.push_back(node);\r
468                         taken = 1;\r
469                 }\r
470                 break;\r
471         case ESNRP_SKY_BOX:\r
472                 SkyBoxList.push_back(node);\r
473                 taken = 1;\r
474                 break;\r
475         case ESNRP_SOLID:\r
476                 if (!isCulled(node))\r
477                 {\r
478                         SolidNodeList.push_back(node);\r
479                         taken = 1;\r
480                 }\r
481                 break;\r
482         case ESNRP_TRANSPARENT:\r
483                 if (!isCulled(node))\r
484                 {\r
485                         TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos));\r
486                         taken = 1;\r
487                 }\r
488                 break;\r
489         case ESNRP_TRANSPARENT_EFFECT:\r
490                 if (!isCulled(node))\r
491                 {\r
492                         TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos));\r
493                         taken = 1;\r
494                 }\r
495                 break;\r
496         case ESNRP_AUTOMATIC:\r
497                 if (!isCulled(node))\r
498                 {\r
499                         const u32 count = node->getMaterialCount();\r
500 \r
501                         taken = 0;\r
502                         for (u32 i=0; i<count; ++i)\r
503                         {\r
504                                 if (Driver->needsTransparentRenderPass(node->getMaterial(i)))\r
505                                 {\r
506                                         // register as transparent node\r
507                                         TransparentNodeEntry e(node, camWorldPos);\r
508                                         TransparentNodeList.push_back(e);\r
509                                         taken = 1;\r
510                                         break;\r
511                                 }\r
512                         }\r
513 \r
514                         // not transparent, register as solid\r
515                         if (!taken)\r
516                         {\r
517                                 SolidNodeList.push_back(node);\r
518                                 taken = 1;\r
519                         }\r
520                 }\r
521                 break;\r
522         case ESNRP_SHADOW:\r
523                 if (!isCulled(node))\r
524                 {\r
525                         ShadowNodeList.push_back(node);\r
526                         taken = 1;\r
527                 }\r
528                 break;\r
529         case ESNRP_GUI:\r
530                 if (!isCulled(node))\r
531                 {\r
532                         GuiNodeList.push_back(node);\r
533                         taken = 1;\r
534                 }\r
535 \r
536         case ESNRP_NONE: // ignore this one\r
537                 break;\r
538         }\r
539 \r
540         return taken;\r
541 }\r
542 \r
543 void CSceneManager::clearAllRegisteredNodesForRendering()\r
544 {\r
545         CameraList.clear();\r
546         LightList.clear();\r
547         SkyBoxList.clear();\r
548         SolidNodeList.clear();\r
549         TransparentNodeList.clear();\r
550         TransparentEffectNodeList.clear();\r
551         ShadowNodeList.clear();\r
552         GuiNodeList.clear();\r
553 }\r
554 \r
555 //! This method is called just before the rendering process of the whole scene.\r
556 //! draws all scene nodes\r
557 void CSceneManager::drawAll()\r
558 {\r
559         if (!Driver)\r
560                 return;\r
561 \r
562         u32 i; // new ISO for scoping problem in some compilers\r
563 \r
564         // reset all transforms\r
565         Driver->setMaterial(video::SMaterial());\r
566         Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix );\r
567         Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix );\r
568         Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix );\r
569         for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i)\r
570                 Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix );\r
571         // TODO: This should not use an attribute here but a real parameter when necessary (too slow!)\r
572         Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT));\r
573 \r
574         // do animations and other stuff.\r
575         OnAnimate(os::Timer::getTime());\r
576 \r
577         /*!\r
578                 First Scene Node for prerendering should be the active camera\r
579                 consistent Camera is needed for culling\r
580         */\r
581         camWorldPos.set(0,0,0);\r
582         if (ActiveCamera)\r
583         {\r
584                 ActiveCamera->render();\r
585                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
586         }\r
587 \r
588         // let all nodes register themselves\r
589         OnRegisterSceneNode();\r
590 \r
591         if (LightManager)\r
592                 LightManager->OnPreRender(LightList);\r
593 \r
594         //render camera scenes\r
595         {\r
596                 CurrentRenderPass = ESNRP_CAMERA;\r
597                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
598 \r
599                 if (LightManager)\r
600                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
601 \r
602                 for (i=0; i<CameraList.size(); ++i)\r
603                         CameraList[i]->render();\r
604 \r
605                 CameraList.set_used(0);\r
606 \r
607                 if (LightManager)\r
608                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
609         }\r
610 \r
611         //render lights scenes\r
612         {\r
613                 CurrentRenderPass = ESNRP_LIGHT;\r
614                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
615 \r
616                 if (LightManager)\r
617                 {\r
618                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
619                 }\r
620                 else\r
621                 {\r
622                         // Sort the lights by distance from the camera\r
623                         core::vector3df camWorldPos(0, 0, 0);\r
624                         if (ActiveCamera)\r
625                                 camWorldPos = ActiveCamera->getAbsolutePosition();\r
626 \r
627                         core::array<DistanceNodeEntry> SortedLights;\r
628                         SortedLights.set_used(LightList.size());\r
629                         for (s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
630                                 SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos);\r
631 \r
632                         SortedLights.set_sorted(false);\r
633                         SortedLights.sort();\r
634 \r
635                         for(s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
636                                 LightList[light] = SortedLights[light].Node;\r
637                 }\r
638 \r
639                 Driver->deleteAllDynamicLights();\r
640 \r
641                 Driver->setAmbientLight(AmbientLight);\r
642 \r
643                 u32 maxLights = LightList.size();\r
644 \r
645                 if (!LightManager)\r
646                         maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights);\r
647 \r
648                 for (i=0; i< maxLights; ++i)\r
649                         LightList[i]->render();\r
650 \r
651                 if (LightManager)\r
652                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
653         }\r
654 \r
655         // render skyboxes\r
656         {\r
657                 CurrentRenderPass = ESNRP_SKY_BOX;\r
658                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
659 \r
660                 if (LightManager)\r
661                 {\r
662                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
663                         for (i=0; i<SkyBoxList.size(); ++i)\r
664                         {\r
665                                 ISceneNode* node = SkyBoxList[i];\r
666                                 LightManager->OnNodePreRender(node);\r
667                                 node->render();\r
668                                 LightManager->OnNodePostRender(node);\r
669                         }\r
670                 }\r
671                 else\r
672                 {\r
673                         for (i=0; i<SkyBoxList.size(); ++i)\r
674                                 SkyBoxList[i]->render();\r
675                 }\r
676 \r
677                 SkyBoxList.set_used(0);\r
678 \r
679                 if (LightManager)\r
680                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
681         }\r
682 \r
683         // render default objects\r
684         {\r
685                 CurrentRenderPass = ESNRP_SOLID;\r
686                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
687 \r
688                 SolidNodeList.sort(); // sort by textures\r
689 \r
690                 if (LightManager)\r
691                 {\r
692                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
693                         for (i=0; i<SolidNodeList.size(); ++i)\r
694                         {\r
695                                 ISceneNode* node = SolidNodeList[i].Node;\r
696                                 LightManager->OnNodePreRender(node);\r
697                                 node->render();\r
698                                 LightManager->OnNodePostRender(node);\r
699                         }\r
700                 }\r
701                 else\r
702                 {\r
703                         for (i=0; i<SolidNodeList.size(); ++i)\r
704                                 SolidNodeList[i].Node->render();\r
705                 }\r
706 \r
707                 SolidNodeList.set_used(0);\r
708 \r
709                 if (LightManager)\r
710                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
711         }\r
712 \r
713         // render shadows\r
714         {\r
715                 CurrentRenderPass = ESNRP_SHADOW;\r
716                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
717 \r
718                 if (LightManager)\r
719                 {\r
720                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
721                         for (i=0; i<ShadowNodeList.size(); ++i)\r
722                         {\r
723                                 ISceneNode* node = ShadowNodeList[i];\r
724                                 LightManager->OnNodePreRender(node);\r
725                                 node->render();\r
726                                 LightManager->OnNodePostRender(node);\r
727                         }\r
728                 }\r
729                 else\r
730                 {\r
731                         for (i=0; i<ShadowNodeList.size(); ++i)\r
732                                 ShadowNodeList[i]->render();\r
733                 }\r
734 \r
735                 if (!ShadowNodeList.empty())\r
736                         Driver->drawStencilShadow(true,ShadowColor, ShadowColor,\r
737                                 ShadowColor, ShadowColor);\r
738 \r
739                 ShadowNodeList.set_used(0);\r
740 \r
741                 if (LightManager)\r
742                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
743         }\r
744 \r
745         // render transparent objects.\r
746         {\r
747                 CurrentRenderPass = ESNRP_TRANSPARENT;\r
748                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
749 \r
750                 TransparentNodeList.sort(); // sort by distance from camera\r
751                 if (LightManager)\r
752                 {\r
753                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
754 \r
755                         for (i=0; i<TransparentNodeList.size(); ++i)\r
756                         {\r
757                                 ISceneNode* node = TransparentNodeList[i].Node;\r
758                                 LightManager->OnNodePreRender(node);\r
759                                 node->render();\r
760                                 LightManager->OnNodePostRender(node);\r
761                         }\r
762                 }\r
763                 else\r
764                 {\r
765                         for (i=0; i<TransparentNodeList.size(); ++i)\r
766                                 TransparentNodeList[i].Node->render();\r
767                 }\r
768 \r
769                 TransparentNodeList.set_used(0);\r
770 \r
771                 if (LightManager)\r
772                         LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
773         }\r
774 \r
775         // render transparent effect objects.\r
776         {\r
777                 CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT;\r
778                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
779 \r
780                 TransparentEffectNodeList.sort(); // sort by distance from camera\r
781 \r
782                 if (LightManager)\r
783                 {\r
784                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
785 \r
786                         for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
787                         {\r
788                                 ISceneNode* node = TransparentEffectNodeList[i].Node;\r
789                                 LightManager->OnNodePreRender(node);\r
790                                 node->render();\r
791                                 LightManager->OnNodePostRender(node);\r
792                         }\r
793                 }\r
794                 else\r
795                 {\r
796                         for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
797                                 TransparentEffectNodeList[i].Node->render();\r
798                 }\r
799 \r
800                 TransparentEffectNodeList.set_used(0);\r
801         }\r
802 \r
803         // render custom gui nodes\r
804         {\r
805                 CurrentRenderPass = ESNRP_GUI;\r
806                 Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
807 \r
808                 if (LightManager)\r
809                 {\r
810                         LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
811 \r
812                         for (i=0; i<GuiNodeList.size(); ++i)\r
813                         {\r
814                                 ISceneNode* node = GuiNodeList[i];\r
815                                 LightManager->OnNodePreRender(node);\r
816                                 node->render();\r
817                                 LightManager->OnNodePostRender(node);\r
818                         }\r
819                 }\r
820                 else\r
821                 {\r
822                         for (i=0; i<GuiNodeList.size(); ++i)\r
823                                 GuiNodeList[i]->render();\r
824                 }\r
825 \r
826                 GuiNodeList.set_used(0);\r
827         }\r
828 \r
829 \r
830         if (LightManager)\r
831                 LightManager->OnPostRender();\r
832 \r
833         LightList.set_used(0);\r
834         clearDeletionList();\r
835 \r
836         CurrentRenderPass = ESNRP_NONE;\r
837 }\r
838 \r
839 void CSceneManager::setLightManager(ILightManager* lightManager)\r
840 {\r
841         if (lightManager)\r
842                 lightManager->grab();\r
843         if (LightManager)\r
844                 LightManager->drop();\r
845 \r
846         LightManager = lightManager;\r
847 }\r
848 \r
849 \r
850 //! Sets the color of stencil buffers shadows drawn by the scene manager.\r
851 void CSceneManager::setShadowColor(video::SColor color)\r
852 {\r
853         ShadowColor = color;\r
854 }\r
855 \r
856 \r
857 //! Returns the current color of shadows.\r
858 video::SColor CSceneManager::getShadowColor() const\r
859 {\r
860         return ShadowColor;\r
861 }\r
862 \r
863 IShadowVolumeSceneNode* CSceneManager::createShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, s32 id, bool zfailmethod, f32 infinity)\r
864 {\r
865 #ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_\r
866         return new CShadowVolumeSceneNode(shadowMesh, parent, this, id, zfailmethod, infinity);\r
867 #else\r
868         return 0;\r
869 #endif\r
870 }\r
871 \r
872 \r
873 \r
874 //! Adds an external mesh loader.\r
875 void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader)\r
876 {\r
877         if (!externalLoader)\r
878                 return;\r
879 \r
880         externalLoader->grab();\r
881         MeshLoaderList.push_back(externalLoader);\r
882 }\r
883 \r
884 \r
885 //! Returns the number of mesh loaders supported by Irrlicht at this time\r
886 u32 CSceneManager::getMeshLoaderCount() const\r
887 {\r
888         return MeshLoaderList.size();\r
889 }\r
890 \r
891 \r
892 //! Retrieve the given mesh loader\r
893 IMeshLoader* CSceneManager::getMeshLoader(u32 index) const\r
894 {\r
895         if (index < MeshLoaderList.size())\r
896                 return MeshLoaderList[index];\r
897         else\r
898                 return 0;\r
899 }\r
900 \r
901 \r
902 //! Returns a pointer to the scene collision manager.\r
903 ISceneCollisionManager* CSceneManager::getSceneCollisionManager()\r
904 {\r
905         return CollisionManager;\r
906 }\r
907 \r
908 \r
909 //! Returns a pointer to the mesh manipulator.\r
910 IMeshManipulator* CSceneManager::getMeshManipulator()\r
911 {\r
912         return Driver->getMeshManipulator();\r
913 }\r
914 \r
915 \r
916 //! Adds a scene node to the deletion queue.\r
917 void CSceneManager::addToDeletionQueue(ISceneNode* node)\r
918 {\r
919         if (!node)\r
920                 return;\r
921 \r
922         node->grab();\r
923         DeletionList.push_back(node);\r
924 }\r
925 \r
926 \r
927 //! clears the deletion list\r
928 void CSceneManager::clearDeletionList()\r
929 {\r
930         if (DeletionList.empty())\r
931                 return;\r
932 \r
933         for (u32 i=0; i<DeletionList.size(); ++i)\r
934         {\r
935                 DeletionList[i]->remove();\r
936                 DeletionList[i]->drop();\r
937         }\r
938 \r
939         DeletionList.clear();\r
940 }\r
941 \r
942 \r
943 //! Returns the first scene node with the specified name.\r
944 ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start)\r
945 {\r
946         if (start == 0)\r
947                 start = getRootSceneNode();\r
948 \r
949         if (!strcmp(start->getName(),name))\r
950                 return start;\r
951 \r
952         ISceneNode* node = 0;\r
953 \r
954         const ISceneNodeList& list = start->getChildren();\r
955         ISceneNodeList::const_iterator it = list.begin();\r
956         for (; it!=list.end(); ++it)\r
957         {\r
958                 node = getSceneNodeFromName(name, *it);\r
959                 if (node)\r
960                         return node;\r
961         }\r
962 \r
963         return 0;\r
964 }\r
965 \r
966 \r
967 //! Returns the first scene node with the specified id.\r
968 ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start)\r
969 {\r
970         if (start == 0)\r
971                 start = getRootSceneNode();\r
972 \r
973         if (start->getID() == id)\r
974                 return start;\r
975 \r
976         ISceneNode* node = 0;\r
977 \r
978         const ISceneNodeList& list = start->getChildren();\r
979         ISceneNodeList::const_iterator it = list.begin();\r
980         for (; it!=list.end(); ++it)\r
981         {\r
982                 node = getSceneNodeFromId(id, *it);\r
983                 if (node)\r
984                         return node;\r
985         }\r
986 \r
987         return 0;\r
988 }\r
989 \r
990 \r
991 //! Returns the first scene node with the specified type.\r
992 ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start)\r
993 {\r
994         if (start == 0)\r
995                 start = getRootSceneNode();\r
996 \r
997         if (start->getType() == type || ESNT_ANY == type)\r
998                 return start;\r
999 \r
1000         ISceneNode* node = 0;\r
1001 \r
1002         const ISceneNodeList& list = start->getChildren();\r
1003         ISceneNodeList::const_iterator it = list.begin();\r
1004         for (; it!=list.end(); ++it)\r
1005         {\r
1006                 node = getSceneNodeFromType(type, *it);\r
1007                 if (node)\r
1008                         return node;\r
1009         }\r
1010 \r
1011         return 0;\r
1012 }\r
1013 \r
1014 \r
1015 //! returns scene nodes by type.\r
1016 void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start)\r
1017 {\r
1018         if (start == 0)\r
1019                 start = getRootSceneNode();\r
1020 \r
1021         if (start->getType() == type || ESNT_ANY == type)\r
1022                 outNodes.push_back(start);\r
1023 \r
1024         const ISceneNodeList& list = start->getChildren();\r
1025         ISceneNodeList::const_iterator it = list.begin();\r
1026 \r
1027         for (; it!=list.end(); ++it)\r
1028         {\r
1029                 getSceneNodesFromType(type, outNodes, *it);\r
1030         }\r
1031 }\r
1032 \r
1033 \r
1034 //! Posts an input event to the environment. Usually you do not have to\r
1035 //! use this method, it is used by the internal engine.\r
1036 bool CSceneManager::postEventFromUser(const SEvent& event)\r
1037 {\r
1038         bool ret = false;\r
1039         ICameraSceneNode* cam = getActiveCamera();\r
1040         if (cam)\r
1041                 ret = cam->OnEvent(event);\r
1042 \r
1043         return ret;\r
1044 }\r
1045 \r
1046 \r
1047 //! Removes all children of this scene node\r
1048 void CSceneManager::removeAll()\r
1049 {\r
1050         ISceneNode::removeAll();\r
1051         setActiveCamera(0);\r
1052         // Make sure the driver is reset, might need a more complex method at some point\r
1053         if (Driver)\r
1054                 Driver->setMaterial(video::SMaterial());\r
1055 }\r
1056 \r
1057 \r
1058 //! Clears the whole scene. All scene nodes are removed.\r
1059 void CSceneManager::clear()\r
1060 {\r
1061         removeAll();\r
1062 }\r
1063 \r
1064 \r
1065 //! Returns interface to the parameters set in this scene.\r
1066 io::IAttributes* CSceneManager::getParameters()\r
1067 {\r
1068         return Parameters;\r
1069 }\r
1070 \r
1071 \r
1072 //! Returns current render pass.\r
1073 E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const\r
1074 {\r
1075         return CurrentRenderPass;\r
1076 }\r
1077 \r
1078 \r
1079 //! Returns an interface to the mesh cache which is shared between all existing scene managers.\r
1080 IMeshCache* CSceneManager::getMeshCache()\r
1081 {\r
1082         return MeshCache;\r
1083 }\r
1084 \r
1085 \r
1086 //! Creates a new scene manager.\r
1087 ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent)\r
1088 {\r
1089         CSceneManager* manager = new CSceneManager(Driver, CursorControl, MeshCache);\r
1090 \r
1091         if (cloneContent)\r
1092                 manager->cloneMembers(this, manager);\r
1093 \r
1094         return manager;\r
1095 }\r
1096 \r
1097 \r
1098 //! Sets ambient color of the scene\r
1099 void CSceneManager::setAmbientLight(const video::SColorf &ambientColor)\r
1100 {\r
1101         AmbientLight = ambientColor;\r
1102 }\r
1103 \r
1104 \r
1105 //! Returns ambient color of the scene\r
1106 const video::SColorf& CSceneManager::getAmbientLight() const\r
1107 {\r
1108         return AmbientLight;\r
1109 }\r
1110 \r
1111 \r
1112 //! Get a skinned mesh, which is not available as header-only code\r
1113 ISkinnedMesh* CSceneManager::createSkinnedMesh()\r
1114 {\r
1115         return new CSkinnedMesh();\r
1116 }\r
1117 \r
1118 //! Returns a mesh writer implementation if available\r
1119 IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type)\r
1120 {\r
1121         return 0;\r
1122 }\r
1123 \r
1124 \r
1125 // creates a scenemanager\r
1126 ISceneManager* createSceneManager(video::IVideoDriver* driver, gui::ICursorControl* cursorcontrol)\r
1127 {\r
1128         return new CSceneManager(driver, cursorcontrol, nullptr);\r
1129 }\r
1130 \r
1131 \r
1132 } // end namespace scene\r
1133 } // end namespace irr\r
1134 \r