--- /dev/null
+// Written by Colin MacDonald - all rights assigned to Nikolaus Gebhardt\r
+// Copyright (C) 2008-2012 Nikolaus Gebhardt\r
+// This file is part of the "Irrlicht Engine".\r
+// For conditions of distribution and use, see copyright notice in irrlicht.h\r
+\r
+#ifndef IRR_I_LIGHT_MANAGER_H_INCLUDED\r
+#define IRR_I_LIGHT_MANAGER_H_INCLUDED\r
+\r
+#include "IReferenceCounted.h"\r
+#include "irrArray.h"\r
+#include "ISceneManager.h" // for E_SCENE_NODE_RENDER_PASS, could probably move that to own header?\r
+\r
+namespace irr\r
+{\r
+namespace scene\r
+{\r
+ class ISceneNode;\r
+\r
+ //! ILightManager provides an interface for user applications to manipulate the list of lights in the scene.\r
+ /** The light list can be trimmed or re-ordered before device/ hardware\r
+ lights are created, and/or individual lights can be switched on and off\r
+ before or after each scene node is rendered. It is assumed that the\r
+ ILightManager implementation will store any data that it wishes to\r
+ retain, i.e. the ISceneManager to which it is assigned, the lightList,\r
+ the current render pass, and the current scene node. \r
+ \r
+ It can also be useful for shaders as it allows finding out the currently rendered SceneNode.\r
+ */\r
+ class ILightManager : public IReferenceCounted\r
+ {\r
+ public:\r
+ //! Called after the scene's light list has been built, but before rendering has begun.\r
+ /** As actual device/hardware lights are not created until the\r
+ ESNRP_LIGHT render pass, this provides an opportunity for the\r
+ light manager to trim or re-order the light list, before any\r
+ device/hardware lights have actually been created.\r
+ \param lightList: the Scene Manager's light list, which\r
+ the light manager may modify. This reference will remain valid\r
+ until OnPostRender().\r
+ */\r
+ virtual void OnPreRender(core::array<ISceneNode*> & lightList) {};\r
+\r
+ //! Called after the last scene node is rendered.\r
+ /** After this call returns, the lightList passed to OnPreRender() becomes invalid. */\r
+ virtual void OnPostRender(void) {};\r
+\r
+ //! Called before a render pass begins\r
+ /** \param renderPass: the render pass that's about to begin */\r
+ virtual void OnRenderPassPreRender(E_SCENE_NODE_RENDER_PASS renderPass) {};\r
+\r
+ //! Called after the render pass specified in OnRenderPassPreRender() ends\r
+ /** \param[in] renderPass: the render pass that has finished */\r
+ virtual void OnRenderPassPostRender(E_SCENE_NODE_RENDER_PASS renderPass) {};\r
+\r
+ //! Called before the given scene node is rendered\r
+ /** \param[in] node: the scene node that's about to be rendered */\r
+ virtual void OnNodePreRender(ISceneNode* node) {};\r
+\r
+ //! Called after the the node specified in OnNodePreRender() has been rendered\r
+ /** \param[in] node: the scene node that has just been rendered */\r
+ virtual void OnNodePostRender(ISceneNode* node) {};\r
+ };\r
+} // end namespace scene\r
+} // end namespace irr\r
+\r
+#endif\r
: ISceneNode(0, 0), Driver(driver),\r
CursorControl(cursorControl),\r
ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), Parameters(0),\r
- MeshCache(cache), CurrentRenderPass(ESNRP_NONE)\r
+ MeshCache(cache), CurrentRenderPass(ESNRP_NONE), LightManager(0)\r
{\r
#ifdef _DEBUG\r
ISceneManager::setDebugName("CSceneManager ISceneManager");\r
if (Parameters)\r
Parameters->drop();\r
\r
+ if (LightManager)\r
+ LightManager->drop();\r
+\r
// remove all nodes before dropping the driver\r
// as render targets may be destroyed twice\r
\r
// let all nodes register themselves\r
OnRegisterSceneNode();\r
\r
+ if (LightManager)\r
+ LightManager->OnPreRender(LightList);\r
+\r
//render camera scenes\r
{\r
CurrentRenderPass = ESNRP_CAMERA;\r
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+\r
for (i=0; i<CameraList.size(); ++i)\r
CameraList[i]->render();\r
\r
CameraList.set_used(0);\r
+\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
}\r
\r
//render lights scenes\r
CurrentRenderPass = ESNRP_LIGHT;\r
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
\r
- core::vector3df camWorldPos(0, 0, 0);\r
- if (ActiveCamera)\r
- camWorldPos = ActiveCamera->getAbsolutePosition();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+ }\r
+ else\r
+ {\r
+ // Sort the lights by distance from the camera\r
+ core::vector3df camWorldPos(0, 0, 0);\r
+ if (ActiveCamera)\r
+ camWorldPos = ActiveCamera->getAbsolutePosition();\r
\r
- core::array<DistanceNodeEntry> SortedLights;\r
- SortedLights.set_used(LightList.size());\r
- for (s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
- SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos);\r
+ core::array<DistanceNodeEntry> SortedLights;\r
+ SortedLights.set_used(LightList.size());\r
+ for (s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
+ SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos);\r
\r
- SortedLights.set_sorted(false);\r
- SortedLights.sort();\r
+ SortedLights.set_sorted(false);\r
+ SortedLights.sort();\r
\r
- for(s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
- LightList[light] = SortedLights[light].Node;\r
+ for(s32 light = (s32)LightList.size() - 1; light >= 0; --light)\r
+ LightList[light] = SortedLights[light].Node;\r
+ }\r
\r
Driver->deleteAllDynamicLights();\r
\r
\r
u32 maxLights = LightList.size();\r
\r
+ if (!LightManager)\r
+ maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights);\r
+\r
for (i=0; i< maxLights; ++i)\r
LightList[i]->render();\r
+\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
}\r
\r
// render skyboxes\r
CurrentRenderPass = ESNRP_SKY_BOX;\r
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
\r
- for (i=0; i<SkyBoxList.size(); ++i)\r
- SkyBoxList[i]->render();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+ for (i=0; i<SkyBoxList.size(); ++i)\r
+ {\r
+ ISceneNode* node = SkyBoxList[i];\r
+ LightManager->OnNodePreRender(node);\r
+ node->render();\r
+ LightManager->OnNodePostRender(node);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i=0; i<SkyBoxList.size(); ++i)\r
+ SkyBoxList[i]->render();\r
+ }\r
\r
SkyBoxList.set_used(0);\r
+\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
}\r
\r
// render default objects\r
\r
SolidNodeList.sort(); // sort by textures\r
\r
- for (i=0; i<SolidNodeList.size(); ++i)\r
- SolidNodeList[i].Node->render();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+ for (i=0; i<SolidNodeList.size(); ++i)\r
+ {\r
+ ISceneNode* node = SolidNodeList[i].Node;\r
+ LightManager->OnNodePreRender(node);\r
+ node->render();\r
+ LightManager->OnNodePostRender(node);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i=0; i<SolidNodeList.size(); ++i)\r
+ SolidNodeList[i].Node->render();\r
+ }\r
\r
SolidNodeList.set_used(0);\r
+\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
}\r
\r
// render shadows\r
CurrentRenderPass = ESNRP_SHADOW;\r
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
\r
- for (i=0; i<ShadowNodeList.size(); ++i)\r
- ShadowNodeList[i]->render();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+ for (i=0; i<ShadowNodeList.size(); ++i)\r
+ {\r
+ ISceneNode* node = ShadowNodeList[i];\r
+ LightManager->OnNodePreRender(node);\r
+ node->render();\r
+ LightManager->OnNodePostRender(node);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i=0; i<ShadowNodeList.size(); ++i)\r
+ ShadowNodeList[i]->render();\r
+ }\r
\r
if (!ShadowNodeList.empty())\r
Driver->drawStencilShadow(true,ShadowColor, ShadowColor,\r
ShadowColor, ShadowColor);\r
\r
ShadowNodeList.set_used(0);\r
+\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
}\r
\r
// render transparent objects.\r
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
\r
TransparentNodeList.sort(); // sort by distance from camera\r
- for (i=0; i<TransparentNodeList.size(); ++i)\r
- TransparentNodeList[i].Node->render();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+\r
+ for (i=0; i<TransparentNodeList.size(); ++i)\r
+ {\r
+ ISceneNode* node = TransparentNodeList[i].Node;\r
+ LightManager->OnNodePreRender(node);\r
+ node->render();\r
+ LightManager->OnNodePostRender(node);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i=0; i<TransparentNodeList.size(); ++i)\r
+ TransparentNodeList[i].Node->render();\r
+ }\r
\r
TransparentNodeList.set_used(0);\r
+\r
+ if (LightManager)\r
+ LightManager->OnRenderPassPostRender(CurrentRenderPass);\r
}\r
\r
// render transparent effect objects.\r
\r
TransparentEffectNodeList.sort(); // sort by distance from camera\r
\r
- for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
- TransparentEffectNodeList[i].Node->render();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+\r
+ for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
+ {\r
+ ISceneNode* node = TransparentEffectNodeList[i].Node;\r
+ LightManager->OnNodePreRender(node);\r
+ node->render();\r
+ LightManager->OnNodePostRender(node);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i=0; i<TransparentEffectNodeList.size(); ++i)\r
+ TransparentEffectNodeList[i].Node->render();\r
+ }\r
\r
TransparentEffectNodeList.set_used(0);\r
}\r
CurrentRenderPass = ESNRP_GUI;\r
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);\r
\r
- for (i=0; i<GuiNodeList.size(); ++i)\r
- GuiNodeList[i]->render();\r
+ if (LightManager)\r
+ {\r
+ LightManager->OnRenderPassPreRender(CurrentRenderPass);\r
+\r
+ for (i=0; i<GuiNodeList.size(); ++i)\r
+ {\r
+ ISceneNode* node = GuiNodeList[i];\r
+ LightManager->OnNodePreRender(node);\r
+ node->render();\r
+ LightManager->OnNodePostRender(node);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (i=0; i<GuiNodeList.size(); ++i)\r
+ GuiNodeList[i]->render();\r
+ }\r
\r
GuiNodeList.set_used(0);\r
}\r
\r
+\r
+ if (LightManager)\r
+ LightManager->OnPostRender();\r
+\r
LightList.set_used(0);\r
clearDeletionList();\r
\r
CurrentRenderPass = ESNRP_NONE;\r
}\r
\r
+void CSceneManager::setLightManager(ILightManager* lightManager)\r
+{\r
+ if (lightManager)\r
+ lightManager->grab();\r
+ if (LightManager)\r
+ LightManager->drop();\r
+\r
+ LightManager = lightManager;\r
+}\r
+\r
\r
//! Sets the color of stencil buffers shadows drawn by the scene manager.\r
void CSceneManager::setShadowColor(video::SColor color)\r