Browse Source

Transition to xml-defined rendering path. Pass names changed. Likely caused a large number of regressions to postprocessing, texture rendering & multisampling, which need to be sorted out. The renderpath feature also needs to be documented.

Lasse Öörni 13 years ago
parent
commit
ffe65cf885
52 changed files with 626 additions and 654 deletions
  1. 20 0
      Bin/CoreData/RenderPaths/Deferred.xml
  2. 8 0
      Bin/CoreData/RenderPaths/Forward.xml
  3. 21 0
      Bin/CoreData/RenderPaths/Prepass.xml
  4. 1 1
      Bin/CoreData/Shaders/GLSL/Samplers.frag
  5. 4 4
      Bin/CoreData/Shaders/HLSL/Samplers.hlsl
  6. 2 2
      Bin/CoreData/Techniques/DiffAlpha.xml
  7. 2 2
      Bin/CoreData/Techniques/DiffEnvCubeAlpha.xml
  8. 2 2
      Bin/CoreData/Techniques/DiffLitParticleAlpha.xml
  9. 1 1
      Bin/CoreData/Techniques/DiffMultiply.xml
  10. 2 2
      Bin/CoreData/Techniques/DiffNormalAlpha.xml
  11. 2 2
      Bin/CoreData/Techniques/DiffNormalEnvCubeAlpha.xml
  12. 2 2
      Bin/CoreData/Techniques/DiffNormalSpecAlpha.xml
  13. 2 2
      Bin/CoreData/Techniques/DiffSpecAlpha.xml
  14. 1 1
      Bin/CoreData/Techniques/DiffUnlitAlpha.xml
  15. 1 1
      Bin/CoreData/Techniques/DiffVColAdd.xml
  16. 1 1
      Bin/CoreData/Techniques/DiffVColMultiply.xml
  17. 1 1
      Bin/CoreData/Techniques/DiffVColUnlitAlpha.xml
  18. 1 1
      Bin/CoreData/Techniques/NoTextureAdd.xml
  19. 2 2
      Bin/CoreData/Techniques/NoTextureAlpha.xml
  20. 2 2
      Bin/CoreData/Techniques/NoTextureEnvCubeAlpha.xml
  21. 1 1
      Bin/CoreData/Techniques/NoTextureMultiply.xml
  22. 1 1
      Bin/CoreData/Techniques/NoTextureUnlitAlpha.xml
  23. 1 1
      Bin/CoreData/Techniques/NoTextureVColAdd.xml
  24. 1 1
      Bin/CoreData/Techniques/NoTextureVColMultiply.xml
  25. 0 2
      Bin/Data/Scripts/Editor.as
  26. 0 10
      Bin/Data/Scripts/Editor/EditorSettings.as
  27. 0 3
      Bin/Data/Scripts/LightTest.as
  28. 7 10
      Bin/Data/Scripts/Physics.as
  29. 7 10
      Bin/Data/Scripts/Terrain.as
  30. 7 10
      Bin/Data/Scripts/TestScene.as
  31. 7 10
      Bin/Data/Scripts/TestSceneOld.as
  32. 0 32
      Bin/Data/UI/EditorSettingsDialog.xml
  33. 2 2
      Docs/GettingStarted.dox
  34. 8 4
      Docs/Reference.dox
  35. 1 9
      Engine/Engine/DebugHud.cpp
  36. 5 4
      Engine/Engine/Engine.cpp
  37. 0 7
      Engine/Engine/GraphicsAPI.cpp
  38. 2 0
      Engine/Graphics/Direct3D9/D3D9Graphics.cpp
  39. 1 1
      Engine/Graphics/Direct3D9/D3D9Shader.cpp
  40. 2 0
      Engine/Graphics/GraphicsDefs.cpp
  41. 6 4
      Engine/Graphics/GraphicsDefs.h
  42. 12 3
      Engine/Graphics/Material.cpp
  43. 2 0
      Engine/Graphics/OpenGL/OGLGraphics.cpp
  44. 6 6
      Engine/Graphics/PostProcess.cpp
  45. 1 1
      Engine/Graphics/PostProcess.h
  46. 38 68
      Engine/Graphics/Renderer.cpp
  47. 9 11
      Engine/Graphics/Renderer.h
  48. 271 334
      Engine/Graphics/View.cpp
  49. 46 19
      Engine/Graphics/View.h
  50. 86 54
      Engine/Graphics/Viewport.cpp
  51. 18 5
      Engine/Graphics/Viewport.h
  52. 0 2
      Urho3D/Urho3D.cpp

+ 20 - 0
Bin/CoreData/RenderPaths/Deferred.xml

@@ -0,0 +1,20 @@
+<renderpath>
+    <rendertarget name="albedo" format="rgba" />
+    <rendertarget name="normal" format="rgba" />
+    <rendertarget name="depth" format="lineardepth" />
+    <command type="clear" color="fog" depth="1.0" stencil="0" />
+    <command type="scenepass" pass="deferred" marktostencil="true" vertexlights="true" sort="fronttoback">
+        <output index="0" name="viewport" />
+        <output index="1" name="albedo" />
+        <output index="2" name="normal" />
+        <output index="3" name="depth" />
+    </command>
+    <command type="lightvolumes" vs="DeferredLight" ps="DeferredLight">
+        <texture unit="albedo" name="albedo" />
+        <texture unit="normal" name="normal" />
+        <texture unit="depth" name="depth" />
+    </command>
+    <command type="scenepass" pass="prealpha" sort="fronttoback" />
+    <command type="scenepass" pass="alpha" usescissor="true" vertexlights="true" sort="backtofront" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" />
+</renderpath>

+ 8 - 0
Bin/CoreData/RenderPaths/Forward.xml

@@ -0,0 +1,8 @@
+<renderpath>
+    <command type="clear" color="fog" depth="1.0" stencil="0" />
+    <command type="scenepass" pass="base" vertexlights="true" sort="state" />
+    <command type="forwardlights" />
+    <command type="scenepass" pass="prealpha" sort="state" />
+    <command type="scenepass" pass="alpha" usescissor="true" vertexlights="true" sort="backtofront" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" />
+</renderpath>

+ 21 - 0
Bin/CoreData/RenderPaths/Prepass.xml

@@ -0,0 +1,21 @@
+<renderpath>
+    <rendertarget name="light" format="rgba" />
+    <rendertarget name="normal" format="rgba" />
+    <rendertarget name="depth" format="lineardepth" />
+    <command type="clear" color="fog" depth="1.0" stencil="0" />
+    <command type="scenepass" pass="prepass" marktostencil="true" sort="fronttoback">
+        <output index="0" name="normal" />
+        <output index="1" name="depth" />
+    </command>
+    <command type="clear" color="0 0 0 0" output="light" />
+    <command type="lightvolumes" vs="PrepassLight" ps="PrepassLight" output="light">
+        <texture unit="normal" name="normal" />
+        <texture unit="depth" name="depth" />
+    </command>
+    <command type="scenepass" pass="material" vertexlights="true" sort="fronttoback">
+        <texture unit="light" name="light" />
+    </command>
+    <command type="scenepass" pass="prealpha" sort="fronttoback" />
+    <command type="scenepass" pass="alpha" usescissor="true" vertexlights="true" sort="backtofront" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" />
+</renderpath>

+ 1 - 1
Bin/CoreData/Shaders/GLSL/Samplers.frag

@@ -8,11 +8,11 @@ uniform samplerCube sEnvCubeMap;
 uniform sampler2D sLightRampMap;
 uniform sampler2D sLightRampMap;
 uniform sampler2D sLightSpotMap;
 uniform sampler2D sLightSpotMap;
 uniform samplerCube sLightCubeMap;
 uniform samplerCube sLightCubeMap;
+#ifndef GL_ES
 uniform sampler2D sAlbedoBuffer;
 uniform sampler2D sAlbedoBuffer;
 uniform sampler2D sNormalBuffer;
 uniform sampler2D sNormalBuffer;
 uniform sampler2D sDepthBuffer;
 uniform sampler2D sDepthBuffer;
 uniform sampler2D sLightBuffer;
 uniform sampler2D sLightBuffer;
-#ifndef GL_ES
 uniform sampler2DShadow sShadowMap;
 uniform sampler2DShadow sShadowMap;
 uniform samplerCube sFaceSelectCubeMap;
 uniform samplerCube sFaceSelectCubeMap;
 uniform samplerCube sIndirectionCubeMap;
 uniform samplerCube sIndirectionCubeMap;

+ 4 - 4
Bin/CoreData/Shaders/HLSL/Samplers.hlsl

@@ -1,6 +1,8 @@
 sampler2D sDiffMap : register(S0);
 sampler2D sDiffMap : register(S0);
 samplerCUBE sDiffCubeMap : register(S0);
 samplerCUBE sDiffCubeMap : register(S0);
+sampler2D sAlbedoBuffer : register(S0);
 sampler2D sNormalMap : register(S1);
 sampler2D sNormalMap : register(S1);
+sampler2D sNormalBuffer : register(S1);
 sampler2D sSpecMap : register(S2);
 sampler2D sSpecMap : register(S2);
 sampler2D sEmissiveMap : register(S3);
 sampler2D sEmissiveMap : register(S3);
 sampler2D sEnvMap : register(S4);
 sampler2D sEnvMap : register(S4);
@@ -11,10 +13,8 @@ samplerCUBE sLightCubeMap : register(S6);
 sampler2D sShadowMap : register(S7);
 sampler2D sShadowMap : register(S7);
 samplerCUBE sFaceSelectCubeMap : register(S8);
 samplerCUBE sFaceSelectCubeMap : register(S8);
 samplerCUBE sIndirectionCubeMap : register(S9);
 samplerCUBE sIndirectionCubeMap : register(S9);
-sampler2D sAlbedoBuffer : register(S0);
-sampler2D sNormalBuffer : register(S1);
-sampler2D sDepthBuffer : register(S2);
-sampler2D sLightBuffer : register(S5);
+sampler2D sDepthBuffer : register(S10);
+sampler2D sLightBuffer : register(S11);
 
 
 float4 Sample(sampler2D map, float2 texCoord)
 float4 Sample(sampler2D map, float2 texCoord)
 {
 {

+ 2 - 2
Bin/CoreData/Techniques/DiffAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/DiffEnvCubeAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid_EnvCube" ps="LitSolid_DiffEnvCube" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid_EnvCube" ps="LitSolid_DiffEnvCube" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/DiffLitParticleAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitParticle" ps="LitParticle_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitParticle" ps="LitParticle_Diff" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitParticle" ps="LitParticle_Diff" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitParticle" ps="LitParticle_Diff" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/DiffMultiply.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit" ps="Unlit_Diff" depthwrite="false" blend="multiply" />
+    <pass name="alpha" vs="Unlit" ps="Unlit_Diff" depthwrite="false" blend="multiply" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/DiffNormalAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid_Normal" ps="LitSolid_DiffNormal" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid_Normal" ps="LitSolid_DiffNormal" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/DiffNormalEnvCubeAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid_NormalEnvCube" ps="LitSolid_DiffNormalEnvCube" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid_Normal" ps="LitSolid_DiffNormal" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid_NormalEnvCube" ps="LitSolid_DiffNormalEnvCube" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid_Normal" ps="LitSolid_DiffNormal" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/DiffNormalSpecAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid_Normal" ps="LitSolid_DiffNormalSpecMap" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid_Normal" ps="LitSolid_DiffNormalSpecMap" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/DiffSpecAlpha.xml

@@ -1,5 +1,5 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid" ps="LitSolid_DiffSpecMap" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid" ps="LitSolid_Diff" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid" ps="LitSolid_DiffSpecMap" depthwrite="false" blend="addalpha" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
     <pass name="shadow" vs="Shadow" ps="Shadow" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/DiffUnlitAlpha.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit" ps="Unlit_Diff" depthwrite="false" blend="alpha" />
+    <pass name="alpha" vs="Unlit" ps="Unlit_Diff" depthwrite="false" blend="alpha" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/DiffVColAdd.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit_VCol" ps="Unlit_DiffVCol" depthwrite="false" blend="add" />
+    <pass name="alpha" vs="Unlit_VCol" ps="Unlit_DiffVCol" depthwrite="false" blend="add" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/DiffVColMultiply.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit_VCol" ps="Unlit_DiffVCol" depthwrite="false" blend="multiply" />
+    <pass name="alpha" vs="Unlit_VCol" ps="Unlit_DiffVCol" depthwrite="false" blend="multiply" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/DiffVColUnlitAlpha.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit_VCol" ps="Unlit_DiffVCol" depthwrite="false" blend="alpha" />
+    <pass name="alpha" vs="Unlit_VCol" ps="Unlit_DiffVCol" depthwrite="false" blend="alpha" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/NoTextureAdd.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit" ps="Unlit" depthwrite="false" blend="add" />
+    <pass name="alpha" vs="Unlit" ps="Unlit" depthwrite="false" blend="add" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/NoTextureAlpha.xml

@@ -1,4 +1,4 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid" ps="LitSolid" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid" ps="LitSolid" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid" ps="LitSolid" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid" ps="LitSolid" depthwrite="false" blend="addalpha" />
 </technique>
 </technique>

+ 2 - 2
Bin/CoreData/Techniques/NoTextureEnvCubeAlpha.xml

@@ -1,4 +1,4 @@
 <technique>
 <technique>
-    <pass name="base" vs="LitSolid_EnvCube" ps="LitSolid_EnvCube" depthwrite="false" blend="alpha" />
-    <pass name="light" vs="LitSolid" ps="LitSolid" depthwrite="false" blend="addalpha" />
+    <pass name="alpha" vs="LitSolid_EnvCube" ps="LitSolid_EnvCube" depthwrite="false" blend="alpha" />
+    <pass name="litalpha" vs="LitSolid" ps="LitSolid" depthwrite="false" blend="addalpha" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/NoTextureMultiply.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit" ps="Unlit" depthwrite="false" blend="multiply" />
+    <pass name="alpha" vs="Unlit" ps="Unlit" depthwrite="false" blend="multiply" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/NoTextureUnlitAlpha.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit" ps="Unlit" depthwrite="false" blend="alpha" />
+    <pass name="alpha" vs="Unlit" ps="Unlit" depthwrite="false" blend="alpha" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/NoTextureVColAdd.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit_VCol" ps="Unlit_VCol" depthwrite="false" blend="add" />
+    <pass name="alpha" vs="Unlit_VCol" ps="Unlit_VCol" depthwrite="false" blend="add" />
 </technique>
 </technique>

+ 1 - 1
Bin/CoreData/Techniques/NoTextureVColMultiply.xml

@@ -1,3 +1,3 @@
 <technique>
 <technique>
-    <pass name="base" vs="Unlit_VCol" ps="Unlit_VCol" depthwrite="false" blend="multiply" />
+    <pass name="alpha" vs="Unlit_VCol" ps="Unlit_VCol" depthwrite="false" blend="multiply" />
 </technique>
 </technique>

+ 0 - 2
Bin/Data/Scripts/Editor.as

@@ -104,7 +104,6 @@ void LoadConfig()
 
 
     if (!renderingElem.isNull)
     if (!renderingElem.isNull)
     {
     {
-        renderer.renderMode = RenderMode(renderingElem.GetInt("rendermode"));
         renderer.textureQuality = renderingElem.GetInt("texturequality");
         renderer.textureQuality = renderingElem.GetInt("texturequality");
         renderer.materialQuality = renderingElem.GetInt("materialquality");
         renderer.materialQuality = renderingElem.GetInt("materialquality");
         SetShadowResolution(renderingElem.GetInt("shadowresolution"));
         SetShadowResolution(renderingElem.GetInt("shadowresolution"));
@@ -143,7 +142,6 @@ void SaveConfig()
     objectElem.SetBool("generatetangents", generateTangents);
     objectElem.SetBool("generatetangents", generateTangents);
     objectElem.SetInt("pickmode", pickMode);
     objectElem.SetInt("pickmode", pickMode);
 
 
-    renderingElem.SetInt("rendermode", renderer.renderMode);
     renderingElem.SetInt("texturequality", renderer.textureQuality);
     renderingElem.SetInt("texturequality", renderer.textureQuality);
     renderingElem.SetInt("materialquality", renderer.materialQuality);
     renderingElem.SetInt("materialquality", renderer.materialQuality);
     renderingElem.SetInt("shadowresolution", GetShadowResolution());
     renderingElem.SetInt("shadowresolution", GetShadowResolution());

+ 0 - 10
Bin/Data/Scripts/Editor/EditorSettings.as

@@ -58,9 +58,6 @@ void UpdateEditorSettingsDialog()
     DropDownList@ pickModeEdit = settingsDialog.GetChild("PickModeEdit", true);
     DropDownList@ pickModeEdit = settingsDialog.GetChild("PickModeEdit", true);
     pickModeEdit.selection = pickMode;
     pickModeEdit.selection = pickMode;
 
 
-    DropDownList@ renderModeEdit = settingsDialog.GetChild("RenderModeEdit", true);
-    renderModeEdit.selection = renderer.renderMode;
-
     DropDownList@ textureQualityEdit = settingsDialog.GetChild("TextureQualityEdit", true);
     DropDownList@ textureQualityEdit = settingsDialog.GetChild("TextureQualityEdit", true);
     textureQualityEdit.selection = renderer.textureQuality;
     textureQualityEdit.selection = renderer.textureQuality;
 
 
@@ -109,7 +106,6 @@ void UpdateEditorSettingsDialog()
         SubscribeToEvent(localIDToggle, "Toggled", "EditUseLocalIDs");
         SubscribeToEvent(localIDToggle, "Toggled", "EditUseLocalIDs");
         SubscribeToEvent(generateTangentsToggle, "Toggled", "EditGenerateTangents");
         SubscribeToEvent(generateTangentsToggle, "Toggled", "EditGenerateTangents");
         SubscribeToEvent(pickModeEdit, "ItemSelected", "EditPickMode");
         SubscribeToEvent(pickModeEdit, "ItemSelected", "EditPickMode");
-        SubscribeToEvent(renderModeEdit, "ItemSelected", "EditRenderMode");
         SubscribeToEvent(textureQualityEdit, "ItemSelected", "EditTextureQuality");
         SubscribeToEvent(textureQualityEdit, "ItemSelected", "EditTextureQuality");
         SubscribeToEvent(materialQualityEdit, "ItemSelected", "EditMaterialQuality");
         SubscribeToEvent(materialQualityEdit, "ItemSelected", "EditMaterialQuality");
         SubscribeToEvent(shadowResolutionEdit, "ItemSelected", "EditShadowResolution");
         SubscribeToEvent(shadowResolutionEdit, "ItemSelected", "EditShadowResolution");
@@ -236,12 +232,6 @@ void EditPickMode(StringHash eventType, VariantMap& eventData)
     pickMode = edit.selection;
     pickMode = edit.selection;
 }
 }
 
 
-void EditRenderMode(StringHash eventType, VariantMap& eventData)
-{
-    DropDownList@ edit = eventData["Element"].GetUIElement();
-    renderer.renderMode = RenderMode(edit.selection);
-}
-
 void EditTextureQuality(StringHash eventType, VariantMap& eventData)
 void EditTextureQuality(StringHash eventType, VariantMap& eventData)
 {
 {
     DropDownList@ edit = eventData["Element"].GetUIElement();
     DropDownList@ edit = eventData["Element"].GetUIElement();

+ 0 - 3
Bin/Data/Scripts/LightTest.as

@@ -191,9 +191,6 @@ void HandleUpdate(StringHash eventType, VariantMap& eventData)
         if (input.keyDown['D'])
         if (input.keyDown['D'])
             cameraNode.TranslateRelative(Vector3(10, 0, 0) * timeStep * speedMultiplier);
             cameraNode.TranslateRelative(Vector3(10, 0, 0) * timeStep * speedMultiplier);
 
 
-        if (input.keyPress['1'])
-            renderer.renderMode = RenderMode((renderer.renderMode + 1) % 3);
-
         if (input.keyPress['2'])
         if (input.keyPress['2'])
         {
         {
             int quality = renderer.textureQuality;
             int quality = renderer.textureQuality;

+ 7 - 10
Bin/Data/Scripts/Physics.as

@@ -254,9 +254,6 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
     if (ui.focusElement is null)
     if (ui.focusElement is null)
     {
     {
         if (key == '1')
         if (key == '1')
-            renderer.renderMode = RenderMode((renderer.renderMode + 1) % 3);
-        
-        if (key == '2')
         {
         {
             int quality = renderer.textureQuality;
             int quality = renderer.textureQuality;
             ++quality;
             ++quality;
@@ -265,7 +262,7 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.textureQuality = quality;
             renderer.textureQuality = quality;
         }
         }
 
 
-        if (key == '3')
+        if (key == '2')
         {
         {
             int quality = renderer.materialQuality;
             int quality = renderer.materialQuality;
             ++quality;
             ++quality;
@@ -274,13 +271,13 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.materialQuality = quality;
             renderer.materialQuality = quality;
         }
         }
 
 
-        if (key == '4')
+        if (key == '3')
             renderer.specularLighting = !renderer.specularLighting;
             renderer.specularLighting = !renderer.specularLighting;
 
 
-        if (key == '5')
+        if (key == '4')
             renderer.drawShadows = !renderer.drawShadows;
             renderer.drawShadows = !renderer.drawShadows;
 
 
-        if (key == '6')
+        if (key == '5')
         {
         {
             int size = renderer.shadowMapSize;
             int size = renderer.shadowMapSize;
             size *= 2;
             size *= 2;
@@ -289,17 +286,17 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.shadowMapSize = size;
             renderer.shadowMapSize = size;
         }
         }
 
 
-        if (key == '7')
+        if (key == '6')
             renderer.shadowQuality = renderer.shadowQuality + 1;
             renderer.shadowQuality = renderer.shadowQuality + 1;
 
 
-        if (key == '8')
+        if (key == '7')
         {
         {
             bool occlusion = renderer.maxOccluderTriangles > 0;
             bool occlusion = renderer.maxOccluderTriangles > 0;
             occlusion = !occlusion;
             occlusion = !occlusion;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
         }
         }
 
 
-        if (key == '9')
+        if (key == '8')
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
 
 
         if (key == ' ')
         if (key == ' ')

+ 7 - 10
Bin/Data/Scripts/Terrain.as

@@ -243,9 +243,6 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
     if (ui.focusElement is null)
     if (ui.focusElement is null)
     {
     {
         if (key == '1')
         if (key == '1')
-            renderer.renderMode = RenderMode((renderer.renderMode + 1) % 3);
-
-        if (key == '2')
         {
         {
             int quality = renderer.textureQuality;
             int quality = renderer.textureQuality;
             ++quality;
             ++quality;
@@ -254,7 +251,7 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.textureQuality = quality;
             renderer.textureQuality = quality;
         }
         }
 
 
-        if (key == '3')
+        if (key == '2')
         {
         {
             int quality = renderer.materialQuality;
             int quality = renderer.materialQuality;
             ++quality;
             ++quality;
@@ -263,13 +260,13 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.materialQuality = quality;
             renderer.materialQuality = quality;
         }
         }
 
 
-        if (key == '4')
+        if (key == '3')
             renderer.specularLighting = !renderer.specularLighting;
             renderer.specularLighting = !renderer.specularLighting;
 
 
-        if (key == '5')
+        if (key == '4')
             renderer.drawShadows = !renderer.drawShadows;
             renderer.drawShadows = !renderer.drawShadows;
 
 
-        if (key == '6')
+        if (key == '5')
         {
         {
             int size = renderer.shadowMapSize;
             int size = renderer.shadowMapSize;
             size *= 2;
             size *= 2;
@@ -278,17 +275,17 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.shadowMapSize = size;
             renderer.shadowMapSize = size;
         }
         }
 
 
-        if (key == '7')
+        if (key == '6')
             renderer.shadowQuality = renderer.shadowQuality + 1;
             renderer.shadowQuality = renderer.shadowQuality + 1;
 
 
-        if (key == '8')
+        if (key == '7')
         {
         {
             bool occlusion = renderer.maxOccluderTriangles > 0;
             bool occlusion = renderer.maxOccluderTriangles > 0;
             occlusion = !occlusion;
             occlusion = !occlusion;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
         }
         }
 
 
-        if (key == '9')
+        if (key == '8')
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
 
 
         if (key == ' ')
         if (key == ' ')

+ 7 - 10
Bin/Data/Scripts/TestScene.as

@@ -293,9 +293,6 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
     if (ui.focusElement is null)
     if (ui.focusElement is null)
     {
     {
         if (key == '1')
         if (key == '1')
-            renderer.renderMode = RenderMode((renderer.renderMode + 1) % 3);
-        
-        if (key == '2')
         {
         {
             int quality = renderer.textureQuality;
             int quality = renderer.textureQuality;
             ++quality;
             ++quality;
@@ -304,7 +301,7 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.textureQuality = quality;
             renderer.textureQuality = quality;
         }
         }
 
 
-        if (key == '3')
+        if (key == '2')
         {
         {
             int quality = renderer.materialQuality;
             int quality = renderer.materialQuality;
             ++quality;
             ++quality;
@@ -313,13 +310,13 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.materialQuality = quality;
             renderer.materialQuality = quality;
         }
         }
 
 
-        if (key == '4')
+        if (key == '3')
             renderer.specularLighting = !renderer.specularLighting;
             renderer.specularLighting = !renderer.specularLighting;
 
 
-        if (key == '5')
+        if (key == '4')
             renderer.drawShadows = !renderer.drawShadows;
             renderer.drawShadows = !renderer.drawShadows;
 
 
-        if (key == '6')
+        if (key == '5')
         {
         {
             int size = renderer.shadowMapSize;
             int size = renderer.shadowMapSize;
             size *= 2;
             size *= 2;
@@ -328,17 +325,17 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.shadowMapSize = size;
             renderer.shadowMapSize = size;
         }
         }
 
 
-        if (key == '7')
+        if (key == '6')
             renderer.shadowQuality = renderer.shadowQuality + 1;
             renderer.shadowQuality = renderer.shadowQuality + 1;
 
 
-        if (key == '8')
+        if (key == '7')
         {
         {
             bool occlusion = renderer.maxOccluderTriangles > 0;
             bool occlusion = renderer.maxOccluderTriangles > 0;
             occlusion = !occlusion;
             occlusion = !occlusion;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
         }
         }
 
 
-        if (key == '9')
+        if (key == '8')
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
 
 
         if (key == ' ')
         if (key == ' ')

+ 7 - 10
Bin/Data/Scripts/TestSceneOld.as

@@ -380,9 +380,6 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
     if (ui.focusElement is null)
     if (ui.focusElement is null)
     {
     {
         if (key == '1')
         if (key == '1')
-            renderer.renderMode = RenderMode((renderer.renderMode + 1) % 3);
-
-        if (key == '2')
         {
         {
             int quality = renderer.textureQuality;
             int quality = renderer.textureQuality;
             ++quality;
             ++quality;
@@ -391,7 +388,7 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.textureQuality = quality;
             renderer.textureQuality = quality;
         }
         }
 
 
-        if (key == '3')
+        if (key == '2')
         {
         {
             int quality = renderer.materialQuality;
             int quality = renderer.materialQuality;
             ++quality;
             ++quality;
@@ -400,13 +397,13 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.materialQuality = quality;
             renderer.materialQuality = quality;
         }
         }
 
 
-        if (key == '4')
+        if (key == '3')
             renderer.specularLighting = !renderer.specularLighting;
             renderer.specularLighting = !renderer.specularLighting;
 
 
-        if (key == '5')
+        if (key == '4')
             renderer.drawShadows = !renderer.drawShadows;
             renderer.drawShadows = !renderer.drawShadows;
 
 
-        if (key == '6')
+        if (key == '5')
         {
         {
             int size = renderer.shadowMapSize;
             int size = renderer.shadowMapSize;
             size *= 2;
             size *= 2;
@@ -415,17 +412,17 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
             renderer.shadowMapSize = size;
             renderer.shadowMapSize = size;
         }
         }
 
 
-        if (key == '7')
+        if (key == '6')
             renderer.shadowQuality = renderer.shadowQuality + 1;
             renderer.shadowQuality = renderer.shadowQuality + 1;
 
 
-        if (key == '8')
+        if (key == '7')
         {
         {
             bool occlusion = renderer.maxOccluderTriangles > 0;
             bool occlusion = renderer.maxOccluderTriangles > 0;
             occlusion = !occlusion;
             occlusion = !occlusion;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
             renderer.maxOccluderTriangles = occlusion ? 5000 : 0;
         }
         }
 
 
-        if (key == '9')
+        if (key == '8')
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
             renderer.dynamicInstancing = !renderer.dynamicInstancing;
 
 
         if (key == ' ')
         if (key == ' ')

+ 0 - 32
Bin/Data/UI/EditorSettingsDialog.xml

@@ -234,38 +234,6 @@
         <attribute name="Min Size" value="0 4" />
         <attribute name="Min Size" value="0 4" />
         <attribute name="Max Size" value="2147483647 4" />
         <attribute name="Max Size" value="2147483647 4" />
     </element>
     </element>
-    <element>
-        <attribute name="Min Size" value="0 17" />
-        <attribute name="Max Size" value="2147483647 17" />
-        <attribute name="Layout Mode" value="Horizontal" />
-        <attribute name="Layout Spacing" value="8" />
-        <element type="Text">
-            <attribute name="Text" value="Rendering mode" />
-        </element>
-        <element type="DropDownList">
-            <attribute name="Name" value="RenderModeEdit" />
-            <attribute name="Min Size" value="100 0" />
-            <attribute name="Max Size" value="100 2147483647" />
-            <attribute name="Resize Popup" value="true" />
-            <element type="Window" internal="true" popup="true">
-                <element type="ListView" internal="true">
-                    <element type="BorderImage" internal="true">
-                        <element internal="true">
-                            <element type="Text" style="FileSelectorFilterText">
-                                <attribute name="Text" value="Forward" />
-                            </element>
-                            <element type="Text" style="FileSelectorFilterText">
-                                <attribute name="Text" value="Pre-pass" />
-                            </element>
-                            <element type="Text" style="FileSelectorFilterText">
-                                <attribute name="Text" value="Deferred" />
-                            </element>
-                        </element>
-                    </element>
-                </element>
-            </element>
-        </element>
-    </element>
     <element>
     <element>
         <attribute name="Min Size" value="0 17" />
         <attribute name="Min Size" value="0 17" />
         <attribute name="Max Size" value="2147483647 17" />
         <attribute name="Max Size" value="2147483647 17" />

+ 2 - 2
Docs/GettingStarted.dox

@@ -124,7 +124,7 @@ Space       Toggle debug geometry
 F1          Toggle AngelScript console
 F1          Toggle AngelScript console
 F5          Save scene
 F5          Save scene
 F7          Load scene
 F7          Load scene
-1 to 9      Toggle rendering options
+1 to 8      Toggle rendering options
 T           Toggle profiling display
 T           Toggle profiling display
 O           Toggle orthographic camera
 O           Toggle orthographic camera
 F           Toggle FXAA edge filter
 F           Toggle FXAA edge filter
@@ -173,7 +173,7 @@ Arrows      Add or remove lights and objects
 Pageup/down Add or remove 10 lights
 Pageup/down Add or remove 10 lights
 Right mouse Hold and move mouse to rotate view
 Right mouse Hold and move mouse to rotate view
 F1          Toggle AngelScript console
 F1          Toggle AngelScript console
-1 to 9      Toggle rendering options
+1 to 8      Toggle rendering options
 T           Toggle profiling display
 T           Toggle profiling display
 O           Toggle orthographic camera
 O           Toggle orthographic camera
 V           Toggle vertex lighting
 V           Toggle vertex lighting

+ 8 - 4
Docs/Reference.dox

@@ -644,7 +644,7 @@ A technique definition looks like this:
 
 
 \code
 \code
 <technique>
 <technique>
-    <pass name="base|litbase|light|prealpha|postalpha|prepass|material|deferred|shadow" vs="VertexShaderName" ps="PixelShaderName"
+    <pass name="base|litbase|light|alpha|litalpha|prealpha|postalpha|prepass|material|deferred|shadow" vs="VertexShaderName" ps="PixelShaderName"
         alphatest="true|false" blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha"
         alphatest="true|false" blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha"
         depthtest="always|equal|less|lessequal|greater|greaterequal" depthwrite="true|false" alphamask="true|false" />
         depthtest="always|equal|less|lessequal|greater|greaterequal" depthwrite="true|false" alphamask="true|false" />
     <pass ... />
     <pass ... />
@@ -654,9 +654,11 @@ A technique definition looks like this:
 
 
 The purposes of the different passes are:
 The purposes of the different passes are:
 
 
-- base: Renders ambient light, per-vertex lights and fog.
-- litbase: Renders the first per-pixel light, ambient light and fog. This is an optional pass for optimization.
-- light: Renders one per-pixel light's contribution additively.
+- base: Renders ambient light, per-vertex lights and fog for an opaque object.
+- litbase: Renders the first per-pixel light, ambient light and fog for an opaque object. This is an optional pass for optimization.
+- light: Renders one per-pixel light's contribution additively for an opaque object.
+- alpha: Renders ambient light, per-vertex lights and fog for a transparent object.
+- litalpha: Renders one per-pixel light's contribution additively for a transparent object
 - prealpha: Custom rendering pass after opaque geometry. Can be used for example to render the skybox.
 - prealpha: Custom rendering pass after opaque geometry. Can be used for example to render the skybox.
 - postalpha: Custom rendering pass after transparent geometry.
 - postalpha: Custom rendering pass after transparent geometry.
 - prepass: %Light pre-pass only - renders normals, specular power and depth to the G-buffer.
 - prepass: %Light pre-pass only - renders normals, specular power and depth to the G-buffer.
@@ -664,6 +666,8 @@ The purposes of the different passes are:
 - deferred: Deferred rendering only - renders ambient light and per-vertex lights to the output rendertarget, and diffuse albedo, normals, specular intensity + power and depth to the G-buffer.
 - deferred: Deferred rendering only - renders ambient light and per-vertex lights to the output rendertarget, and diffuse albedo, normals, specular intensity + power and depth to the G-buffer.
 - shadow: Renders depth only for shadow map generation.
 - shadow: Renders depth only for shadow map generation.
 
 
+More custom passes can be defined and referred to in the render path definition.
+
 By default draw calls within passes are sorted by render state, but transparent base and light passes, as well as the postalpha pass, are sorted by distance back to front.
 By default draw calls within passes are sorted by render state, but transparent base and light passes, as well as the postalpha pass, are sorted by distance back to front.
 
 
 Note that the technique does not need to enumerate shaders used for different geometry types (non-skinned, skinned, instanced, billboard) and different per-vertex and per-pixel light combinations. Instead specific hardcoded shader variations are assumed to exist. See the file LitSolid.xml in either Bin/CoreData/Shaders/HLSL or Bin/CoreData/Shaders/GLSL to see which variations are required.
 Note that the technique does not need to enumerate shaders used for different geometry types (non-skinned, skinned, instanced, billboard) and different per-vertex and per-pixel light combinations. Instead specific hardcoded shader variations are assumed to exist. See the file LitSolid.xml in either Bin/CoreData/Shaders/HLSL or Bin/CoreData/Shaders/GLSL to see which variations are required.

+ 1 - 9
Engine/Engine/DebugHud.cpp

@@ -38,13 +38,6 @@
 namespace Urho3D
 namespace Urho3D
 {
 {
 
 
-static const char* renderModeTexts[] =
-{
-    "Forward",
-    "Prepass",
-    "Deferred"
-};
-
 static const char* qualityTexts[] =
 static const char* qualityTexts[] =
 {
 {
     "Low",
     "Low",
@@ -135,8 +128,7 @@ void DebugHud::Update()
     if (modeText_->IsVisible())
     if (modeText_->IsVisible())
     {
     {
         String mode;
         String mode;
-        mode.AppendWithFormat("Render:%s Tex:%s Mat:%s Spec:%s Shadows:%s Size:%i Quality:%s Occlusion:%s Instancing:%s Mode:%s",
-            renderModeTexts[renderer->GetRenderMode()],
+        mode.AppendWithFormat("Tex:%s Mat:%s Spec:%s Shadows:%s Size:%i Quality:%s Occlusion:%s Instancing:%s Mode:%s",
             qualityTexts[renderer->GetTextureQuality()],
             qualityTexts[renderer->GetTextureQuality()],
             qualityTexts[renderer->GetMaterialQuality()],
             qualityTexts[renderer->GetMaterialQuality()],
             renderer->GetSpecularLighting() ? "On" : "Off",
             renderer->GetSpecularLighting() ? "On" : "Off",

+ 5 - 4
Engine/Engine/Engine.cpp

@@ -106,7 +106,7 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
     if (initialized_)
     if (initialized_)
         return true;
         return true;
     
     
-    RenderMode mode = RENDER_FORWARD;
+    String renderPath;
     int width = 0;
     int width = 0;
     int height = 0;
     int height = 0;
     int multiSample = 1;
     int multiSample = 1;
@@ -143,9 +143,9 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
             else if (argument == "mono")
             else if (argument == "mono")
                 stereo = false;
                 stereo = false;
             else if (argument == "prepass")
             else if (argument == "prepass")
-                mode = RENDER_PREPASS;
+                renderPath = "CoreData/RenderPaths/Prepass.xml";
             else if (argument == "deferred")
             else if (argument == "deferred")
-                mode = RENDER_DEFERRED;
+                renderPath = "CoreData/RenderPaths/Deferred.xml";
             else if (argument == "noshadows")
             else if (argument == "noshadows")
                 shadows = false;
                 shadows = false;
             else if (argument == "lqshadows")
             else if (argument == "lqshadows")
@@ -264,7 +264,8 @@ bool Engine::Initialize(const String& windowTitle, const String& logName, const
         if (!graphics->SetMode(width, height, fullscreen, vsync, tripleBuffer, multiSample))
         if (!graphics->SetMode(width, height, fullscreen, vsync, tripleBuffer, multiSample))
             return false;
             return false;
         
         
-        renderer->SetRenderMode(mode);
+        if (!renderPath.Empty())
+            renderer->SetDefaultRenderPathName(renderPath);
         renderer->SetDrawShadows(shadows);
         renderer->SetDrawShadows(shadows);
         if (shadows && lqShadows)
         if (shadows && lqShadows)
             renderer->SetShadowQuality(SHADOWQUALITY_LOW_16BIT);
             renderer->SetShadowQuality(SHADOWQUALITY_LOW_16BIT);

+ 0 - 7
Engine/Engine/GraphicsAPI.cpp

@@ -912,11 +912,6 @@ static Renderer* GetRenderer()
 
 
 static void RegisterRenderer(asIScriptEngine* engine)
 static void RegisterRenderer(asIScriptEngine* engine)
 {
 {
-    engine->RegisterEnum("RenderMode");
-    engine->RegisterEnumValue("RenderMode", "RENDER_FORWARD", RENDER_FORWARD);
-    engine->RegisterEnumValue("RenderMode", "RENDER_PREPASS", RENDER_PREPASS);
-    engine->RegisterEnumValue("RenderMode", "RENDER_DEFERRED", RENDER_DEFERRED);
-    
     engine->RegisterGlobalProperty("const int QUALITY_LOW", (void*)&QUALITY_LOW);
     engine->RegisterGlobalProperty("const int QUALITY_LOW", (void*)&QUALITY_LOW);
     engine->RegisterGlobalProperty("const int QUALITY_MEDIUM", (void*)&QUALITY_MEDIUM);
     engine->RegisterGlobalProperty("const int QUALITY_MEDIUM", (void*)&QUALITY_MEDIUM);
     engine->RegisterGlobalProperty("const int QUALITY_HIGH", (void*)&QUALITY_HIGH);
     engine->RegisterGlobalProperty("const int QUALITY_HIGH", (void*)&QUALITY_HIGH);
@@ -933,8 +928,6 @@ static void RegisterRenderer(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Renderer", "uint get_numViewports() const", asMETHOD(Renderer, GetNumViewports), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "uint get_numViewports() const", asMETHOD(Renderer, GetNumViewports), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool set_viewports(uint, Viewport@+)", asMETHOD(Renderer, SetViewport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool set_viewports(uint, Viewport@+)", asMETHOD(Renderer, SetViewport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "Viewport@+ get_viewports(uint) const", asMETHOD(Renderer, GetViewport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "Viewport@+ get_viewports(uint) const", asMETHOD(Renderer, GetViewport), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Renderer", "void set_renderMode(RenderMode)", asMETHOD(Renderer, SetRenderMode), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Renderer", "RenderMode get_renderMode() const", asMETHOD(Renderer, GetRenderMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_specularLighting(bool)", asMETHOD(Renderer, SetSpecularLighting), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_specularLighting(bool)", asMETHOD(Renderer, SetSpecularLighting), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool get_specularLighting() const", asMETHOD(Renderer, GetSpecularLighting), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool get_specularLighting() const", asMETHOD(Renderer, GetSpecularLighting), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_textureAnisotropy(int)", asMETHOD(Renderer, SetTextureAnisotropy), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_textureAnisotropy(int)", asMETHOD(Renderer, SetTextureAnisotropy), asCALL_THISCALL);

+ 2 - 0
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -2003,6 +2003,8 @@ unsigned Graphics::GetFormat(const String& formatName)
         return GetFloat16Format();
         return GetFloat16Format();
     if (nameLower == "r32f" || nameLower == "float")
     if (nameLower == "r32f" || nameLower == "float")
         return GetFloat32Format();
         return GetFloat32Format();
+    if (nameLower == "lineardepth" || nameLower == "depth")
+        return GetLinearDepthFormat();
     if (nameLower == "d24s8")
     if (nameLower == "d24s8")
         return GetDepthStencilFormat();
         return GetDepthStencilFormat();
     
     

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9Shader.cpp

@@ -284,7 +284,7 @@ bool Shader::PrepareVariation(ShaderVariation* variation)
         unsigned sampler = file->ReadUByte();
         unsigned sampler = file->ReadUByte();
         
         
         TextureUnit tuIndex = graphics->GetTextureUnit(unitName);
         TextureUnit tuIndex = graphics->GetTextureUnit(unitName);
-        if (tuIndex != MAX_TEXTURE_UNITS)
+        if (tuIndex < MAX_TEXTURE_UNITS)
             variation->AddTextureUnit(tuIndex);
             variation->AddTextureUnit(tuIndex);
         else if (sampler < MAX_TEXTURE_UNITS)
         else if (sampler < MAX_TEXTURE_UNITS)
             variation->AddTextureUnit((TextureUnit)sampler);
             variation->AddTextureUnit((TextureUnit)sampler);

+ 2 - 0
Engine/Graphics/GraphicsDefs.cpp

@@ -72,6 +72,8 @@ StringHash PSP_LIGHTMATRICES("LightMatricesPS");
 StringHash PASS_BASE("base");
 StringHash PASS_BASE("base");
 StringHash PASS_LITBASE("litbase");
 StringHash PASS_LITBASE("litbase");
 StringHash PASS_LIGHT("light");
 StringHash PASS_LIGHT("light");
+StringHash PASS_ALPHA("alpha");
+StringHash PASS_LITALPHA("litalpha");
 StringHash PASS_SHADOW("shadow");
 StringHash PASS_SHADOW("shadow");
 StringHash PASS_DEFERRED("deferred");
 StringHash PASS_DEFERRED("deferred");
 StringHash PASS_PREPASS("prepass");
 StringHash PASS_PREPASS("prepass");

+ 6 - 4
Engine/Graphics/GraphicsDefs.h

@@ -236,10 +236,12 @@ extern StringHash PSP_SHADOWMAPINVSIZE;
 extern StringHash PSP_SHADOWSPLITS;
 extern StringHash PSP_SHADOWSPLITS;
 extern StringHash PSP_LIGHTMATRICES;
 extern StringHash PSP_LIGHTMATRICES;
 
 
-// Inbuild pass types
+// Inbuilt pass types
 extern StringHash PASS_BASE;
 extern StringHash PASS_BASE;
 extern StringHash PASS_LITBASE;
 extern StringHash PASS_LITBASE;
 extern StringHash PASS_LIGHT;
 extern StringHash PASS_LIGHT;
+extern StringHash PASS_ALPHA;
+extern StringHash PASS_LITALPHA;
 extern StringHash PASS_SHADOW;
 extern StringHash PASS_SHADOW;
 extern StringHash PASS_DEFERRED;
 extern StringHash PASS_DEFERRED;
 extern StringHash PASS_PREPASS;
 extern StringHash PASS_PREPASS;
@@ -258,17 +260,17 @@ enum TextureUnit
     TU_NORMAL = 1,
     TU_NORMAL = 1,
     TU_NORMALBUFFER = 1,
     TU_NORMALBUFFER = 1,
     TU_SPECULAR = 2,
     TU_SPECULAR = 2,
-    TU_DEPTHBUFFER = 2,
     TU_EMISSIVE = 3,
     TU_EMISSIVE = 3,
     TU_ENVIRONMENT = 4,
     TU_ENVIRONMENT = 4,
     MAX_MATERIAL_TEXTURE_UNITS = 5,
     MAX_MATERIAL_TEXTURE_UNITS = 5,
     TU_LIGHTRAMP = 5,
     TU_LIGHTRAMP = 5,
-    TU_LIGHTBUFFER = 5,
     TU_LIGHTSHAPE = 6,
     TU_LIGHTSHAPE = 6,
     TU_SHADOWMAP = 7,
     TU_SHADOWMAP = 7,
     TU_FACESELECT = 8,
     TU_FACESELECT = 8,
     TU_INDIRECTION = 9,
     TU_INDIRECTION = 9,
-    MAX_TEXTURE_UNITS = 10
+    TU_DEPTHBUFFER = 10,
+    TU_LIGHTBUFFER = 11,
+    MAX_TEXTURE_UNITS = 12
 };
 };
 
 
 /// Shader parameter groups for determining need to update.
 /// Shader parameter groups for determining need to update.

+ 12 - 3
Engine/Graphics/Material.cpp

@@ -48,6 +48,13 @@ const String textureUnitNames[] =
     "specular",
     "specular",
     "emissive",
     "emissive",
     "environment",
     "environment",
+    "lightramp",
+    "lightshape",
+    "shadowmap",
+    "faceselect",
+    "indirection",
+    "depth",
+    "light",
     ""
     ""
 };
 };
 
 
@@ -61,9 +68,11 @@ static const String cullModeNames[] =
 
 
 TextureUnit ParseTextureUnitName(const String& name)
 TextureUnit ParseTextureUnitName(const String& name)
 {
 {
-    TextureUnit unit = (TextureUnit)GetStringListIndex(name, textureUnitNames, MAX_MATERIAL_TEXTURE_UNITS);
+    TextureUnit unit = (TextureUnit)GetStringListIndex(name, textureUnitNames, MAX_TEXTURE_UNITS);
     if (name == "diff")
     if (name == "diff")
         unit = TU_DIFFUSE;
         unit = TU_DIFFUSE;
+    else if (name == "albedo")
+        unit = TU_DIFFUSE;
     else if (name == "norm")
     else if (name == "norm")
         unit = TU_NORMAL;
         unit = TU_NORMAL;
     else if (name == "spec")
     else if (name == "spec")
@@ -168,8 +177,8 @@ bool Material::Load(Deserializer& source)
             if (unitName.Length() > 1)
             if (unitName.Length() > 1)
             {
             {
                 unit = ParseTextureUnitName(unitName);
                 unit = ParseTextureUnitName(unitName);
-                if (unit == MAX_MATERIAL_TEXTURE_UNITS)
-                    LOGERROR("Unknown texture unit " + unitName);
+                if (unit >= MAX_MATERIAL_TEXTURE_UNITS)
+                    LOGERROR("Unknown or illegal texture unit " + unitName);
             }
             }
             else
             else
                 unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_MATERIAL_TEXTURE_UNITS - 1);
                 unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_MATERIAL_TEXTURE_UNITS - 1);

+ 2 - 0
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -2148,6 +2148,8 @@ unsigned Graphics::GetFormat(const String& formatName)
         return GetFloat16Format();
         return GetFloat16Format();
     if (nameLower == "r32f" || nameLower == "float")
     if (nameLower == "r32f" || nameLower == "float")
         return GetFloat32Format();
         return GetFloat32Format();
+    if (nameLower == "lineardepth" || nameLower == "depth")
+        return GetLinearDepthFormat();
     if (nameLower == "d24s8")
     if (nameLower == "d24s8")
         return GetDepthStencilFormat();
         return GetDepthStencilFormat();
     
     

+ 6 - 6
Engine/Graphics/PostProcess.cpp

@@ -56,7 +56,7 @@ void PostProcessPass::SetPixelShader(const String& name)
 
 
 void PostProcessPass::SetTexture(TextureUnit unit, const String& name)
 void PostProcessPass::SetTexture(TextureUnit unit, const String& name)
 {
 {
-    if (unit < MAX_MATERIAL_TEXTURE_UNITS)
+    if (unit < MAX_TEXTURE_UNITS)
         textureNames_[unit] = name;
         textureNames_[unit] = name;
 }
 }
 
 
@@ -81,7 +81,7 @@ SharedPtr<PostProcessPass> PostProcessPass::Clone()
     clone->vertexShaderName_ = vertexShaderName_;
     clone->vertexShaderName_ = vertexShaderName_;
     clone->pixelShaderName_ = pixelShaderName_;
     clone->pixelShaderName_ = pixelShaderName_;
     clone->shaderParameters_ = shaderParameters_;
     clone->shaderParameters_ = shaderParameters_;
-    for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i)
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         clone->textureNames_[i] = textureNames_[i];
         clone->textureNames_[i] = textureNames_[i];
     clone->outputName_ = outputName_;
     clone->outputName_ = outputName_;
     
     
@@ -90,7 +90,7 @@ SharedPtr<PostProcessPass> PostProcessPass::Clone()
 
 
 const String& PostProcessPass::GetTexture(TextureUnit unit) const
 const String& PostProcessPass::GetTexture(TextureUnit unit) const
 {
 {
-    return unit < MAX_MATERIAL_TEXTURE_UNITS ? textureNames_[unit] : String::EMPTY;
+    return unit < MAX_TEXTURE_UNITS ? textureNames_[unit] : String::EMPTY;
 }
 }
 
 
 const Vector4& PostProcessPass::GetShaderParameter(const String& name) const
 const Vector4& PostProcessPass::GetShaderParameter(const String& name) const
@@ -190,13 +190,13 @@ bool PostProcess::LoadParameters(XMLFile* file)
                 if (unitName.Length() > 1)
                 if (unitName.Length() > 1)
                 {
                 {
                     unit = ParseTextureUnitName(unitName);
                     unit = ParseTextureUnitName(unitName);
-                    if (unit == MAX_MATERIAL_TEXTURE_UNITS)
+                    if (unit >= MAX_TEXTURE_UNITS)
                         LOGERROR("Unknown texture unit " + unitName);
                         LOGERROR("Unknown texture unit " + unitName);
                 }
                 }
                 else
                 else
-                    unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_MATERIAL_TEXTURE_UNITS - 1);
+                    unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_TEXTURE_UNITS - 1);
             }
             }
-            if (unit != MAX_MATERIAL_TEXTURE_UNITS)
+            if (unit < MAX_TEXTURE_UNITS)
             {
             {
                 String name = textureElem.GetAttribute("name");
                 String name = textureElem.GetAttribute("name");
                 pass->SetTexture(unit, name);
                 pass->SetTexture(unit, name);

+ 1 - 1
Engine/Graphics/PostProcess.h

@@ -77,7 +77,7 @@ private:
     /// Pixel shader name.
     /// Pixel shader name.
     String pixelShaderName_;
     String pixelShaderName_;
     /// Textures.
     /// Textures.
-    String textureNames_[MAX_MATERIAL_TEXTURE_UNITS];
+    String textureNames_[MAX_TEXTURE_UNITS];
     /// %Shader parameters.
     /// %Shader parameters.
     HashMap<StringHash, Vector4> shaderParameters_;
     HashMap<StringHash, Vector4> shaderParameters_;
     /// Output rendertarget name.
     /// Output rendertarget name.

+ 38 - 68
Engine/Graphics/Renderer.cpp

@@ -259,7 +259,7 @@ Renderer::Renderer(Context* context) :
     Object(context),
     Object(context),
     defaultZone_(new Zone(context)),
     defaultZone_(new Zone(context)),
     quadDirLight_(new Light(context)),
     quadDirLight_(new Light(context)),
-    renderMode_(RENDER_FORWARD),
+    defaultRenderPathName_("CoreData/RenderPaths/Forward.xml"),
     textureAnisotropy_(4),
     textureAnisotropy_(4),
     textureFilterMode_(FILTER_TRILINEAR),
     textureFilterMode_(FILTER_TRILINEAR),
     textureQuality_(QUALITY_HIGH),
     textureQuality_(QUALITY_HIGH),
@@ -329,33 +329,11 @@ bool Renderer::SetViewport(unsigned index, Viewport* viewport)
     return true;
     return true;
 }
 }
 
 
-void Renderer::SetRenderMode(RenderMode mode)
+void Renderer::SetDefaultRenderPathName(const String& name)
 {
 {
-    if (!initialized_)
-    {
-        LOGERROR("Can not switch rendering mode before setting initial screen mode");
-        return;
-    }
-    
-    if (mode == RENDER_PREPASS && !graphics_->GetLightPrepassSupport())
-        mode = RENDER_FORWARD;
-    if (mode == RENDER_DEFERRED && !graphics_->GetDeferredSupport())
-        mode = RENDER_FORWARD;
-    
-    if (mode != renderMode_)
-    {
-        // Deferred rendering is incompatible with hardware multisampling, so set new screen mode with 1x sampling if in use
-        if (mode != RENDER_FORWARD && graphics_->GetMultiSample() > 1)
-        {
-            graphics_->SetMode(graphics_->GetWidth(), graphics_->GetHeight(), graphics_->GetFullscreen(), graphics_->GetVSync(),
-                graphics_->GetTripleBuffer(), 1);
-        }
-        
-        ResetBuffers();
-        ResetShadowMaps();
-        renderMode_ = mode;
-        shadersDirty_ = true;
-    }
+    String nameTrimmed = name.Trimmed();
+    if (!nameTrimmed.Empty())
+        defaultRenderPathName_ = name;
 }
 }
 
 
 void Renderer::SetSpecularLighting(bool enable)
 void Renderer::SetSpecularLighting(bool enable)
@@ -458,12 +436,7 @@ void Renderer::SetMaxShadowMaps(int shadowMaps)
 
 
 void Renderer::SetMaxShadowCascades(int cascades)
 void Renderer::SetMaxShadowCascades(int cascades)
 {
 {
-    #ifndef USE_OPENGL
-    // Due to instruction count limits, deferred modes in SM2.0 can only support up to 3 cascades
-    cascades = Clamp(cascades, 1, renderMode_ != RENDER_FORWARD && !graphics_->GetSM3Support() ? 3 : MAX_CASCADE_SPLITS);
-    #else
     cascades = Clamp(cascades, 1, MAX_CASCADE_SPLITS);
     cascades = Clamp(cascades, 1, MAX_CASCADE_SPLITS);
-    #endif
     
     
     if (cascades != maxShadowCascades_)
     if (cascades != maxShadowCascades_)
     {
     {
@@ -758,6 +731,32 @@ bool Renderer::AddView(RenderSurface* renderTarget, Viewport* viewport)
         return false;
         return false;
 }
 }
 
 
+void Renderer::GetLightVolumeShaders(PODVector<ShaderVariation*>& lightVS, PODVector<ShaderVariation*>& lightPS, const String& vsName, const String& psName)
+{
+    lightVS.Resize(MAX_DEFERRED_LIGHT_VS_VARIATIONS);
+    lightPS.Resize(MAX_DEFERRED_LIGHT_PS_VARIATIONS);
+    
+    unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
+    
+    for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_VS_VARIATIONS; ++i)
+        lightVS[i] = GetVertexShader(vsName + "_" + deferredLightVSVariations[i]);
+    
+    for (unsigned i = 0; i < lightPS.Size(); ++i)
+    {
+        String ortho;
+        if (i >= DLPS_ORTHO)
+            ortho = "Ortho";
+        
+        if (i & DLPS_SHADOW)
+        {
+            lightPS[i] = GetPixelShader(psName + "_" + ortho + lightPSVariations[i % DLPS_ORTHO] +
+                shadowVariations[shadows]);
+        }
+        else
+            lightPS[i] = GetPixelShader(psName + "_" + ortho + lightPSVariations[i % DLPS_ORTHO]);
+    }
+}
+
 Geometry* Renderer::GetLightGeometry(Light* light)
 Geometry* Renderer::GetLightGeometry(Light* light)
 {
 {
     switch (light->GetLightType())
     switch (light->GetLightType())
@@ -1051,7 +1050,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
         
         
         //  Check whether is a pixel lit forward pass. If not, there is only one pixel shader
         //  Check whether is a pixel lit forward pass. If not, there is only one pixel shader
         const StringHash& type = batch.pass_->GetType();
         const StringHash& type = batch.pass_->GetType();
-        if (type == PASS_LIGHT || type == PASS_LITBASE)
+        if (type == PASS_LIGHT || type == PASS_LITBASE || type == PASS_LITALPHA)
         {
         {
             LightBatchQueue* lightQueue = batch.lightQueue_;
             LightBatchQueue* lightQueue = batch.lightQueue_;
             if (!lightQueue)
             if (!lightQueue)
@@ -1121,7 +1120,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
         else
         else
         {
         {
             // Check if pass has vertex lighting support
             // Check if pass has vertex lighting support
-            if (type == PASS_BASE || type == PASS_MATERIAL || type == PASS_DEFERRED)
+            if (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
             {
             {
                 unsigned numVertexLights = 0;
                 unsigned numVertexLights = 0;
                 if (batch.lightQueue_)
                 if (batch.lightQueue_)
@@ -1157,7 +1156,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
     }
     }
 }
 }
 
 
-void Renderer::SetLightVolumeBatchShaders(Batch& batch)
+void Renderer::SetLightVolumeBatchShaders(Batch& batch, PODVector<ShaderVariation*>& lightVS, PODVector<ShaderVariation*>& lightPS)
 {
 {
     unsigned vsi = DLVS_NONE;
     unsigned vsi = DLVS_NONE;
     unsigned psi = DLPS_NONE;
     unsigned psi = DLPS_NONE;
@@ -1193,8 +1192,8 @@ void Renderer::SetLightVolumeBatchShaders(Batch& batch)
         psi += DLPS_ORTHO;
         psi += DLPS_ORTHO;
     }
     }
     
     
-    batch.vertexShader_ = lightVS_[vsi];
-    batch.pixelShader_ = lightPS_[psi];
+    batch.vertexShader_ = lightVS[vsi];
+    batch.pixelShader_ = lightPS[psi];
 }
 }
 
 
 void Renderer::SetCullMode(CullMode mode, Camera* camera)
 void Renderer::SetCullMode(CullMode mode, Camera* camera)
@@ -1464,35 +1463,6 @@ void Renderer::LoadShaders()
     // Load inbuilt shaders
     // Load inbuilt shaders
     stencilVS_ = GetVertexShader("Stencil");
     stencilVS_ = GetVertexShader("Stencil");
     stencilPS_ = GetPixelShader("Stencil");
     stencilPS_ = GetPixelShader("Stencil");
-    lightVS_.Clear();
-    lightPS_.Clear();
-    
-    if (renderMode_ != RENDER_FORWARD)
-    {
-        lightVS_.Resize(MAX_DEFERRED_LIGHT_VS_VARIATIONS);
-        lightPS_.Resize(MAX_DEFERRED_LIGHT_PS_VARIATIONS);
-        
-        unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
-        String shaderName = renderMode_ == RENDER_PREPASS ? "PrepassLight_" : "DeferredLight_";
-        
-        for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_VS_VARIATIONS; ++i)
-            lightVS_[i] = GetVertexShader(shaderName + deferredLightVSVariations[i]);
-        
-        for (unsigned i = 0; i < lightPS_.Size(); ++i)
-        {
-            String ortho;
-            if (i >= DLPS_ORTHO)
-                ortho = "Ortho";
-            
-            if (i & DLPS_SHADOW)
-            {
-                lightPS_[i] = GetPixelShader(shaderName + ortho + lightPSVariations[i % DLPS_ORTHO] +
-                    shadowVariations[shadows]);
-            }
-            else
-                lightPS_[i] = GetPixelShader(shaderName + ortho + lightPSVariations[i % DLPS_ORTHO]);
-        }
-    }
     
     
     shadersDirty_ = false;
     shadersDirty_ = false;
 }
 }
@@ -1528,7 +1498,7 @@ void Renderer::LoadPassShaders(Technique* tech, StringHash type)
     vertexShaders.Clear();
     vertexShaders.Clear();
     pixelShaders.Clear();
     pixelShaders.Clear();
     
     
-    if (type == PASS_LIGHT || type == PASS_LITBASE)
+    if (type == PASS_LIGHT || type == PASS_LITBASE || type == PASS_LITALPHA)
     {
     {
         // Load forward pixel lit variations
         // Load forward pixel lit variations
         vertexShaders.Resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
         vertexShaders.Resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
@@ -1551,7 +1521,7 @@ void Renderer::LoadPassShaders(Technique* tech, StringHash type)
     else
     else
     {
     {
         // Load vertex light variations for forward ambient pass, deferred G-buffer pass and pre-pass material pass
         // Load vertex light variations for forward ambient pass, deferred G-buffer pass and pre-pass material pass
-        if (type == PASS_BASE || type == PASS_MATERIAL || type == PASS_DEFERRED)
+        if (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
         {
         {
             vertexShaders.Resize(MAX_VERTEXLIGHT_VS_VARIATIONS * MAX_GEOMETRYTYPES);
             vertexShaders.Resize(MAX_VERTEXLIGHT_VS_VARIATIONS * MAX_GEOMETRYTYPES);
             for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_VERTEXLIGHT_VS_VARIATIONS; ++j)
             for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_VERTEXLIGHT_VS_VARIATIONS; ++j)

+ 9 - 11
Engine/Graphics/Renderer.h

@@ -167,8 +167,8 @@ public:
     void SetNumViewports(unsigned num);
     void SetNumViewports(unsigned num);
     /// Set a viewport. Return true if successful.
     /// Set a viewport. Return true if successful.
     bool SetViewport(unsigned index, Viewport* viewport);
     bool SetViewport(unsigned index, Viewport* viewport);
-    /// Set rendering mode (forward / light pre-pass / deferred.)
-    void SetRenderMode(RenderMode mode);
+    /// Set default renderpath resource name.
+    void SetDefaultRenderPathName(const String& name);
     /// Set specular lighting on/off.
     /// Set specular lighting on/off.
     void SetSpecularLighting(bool enable);
     void SetSpecularLighting(bool enable);
     /// Set texture anisotropy.
     /// Set texture anisotropy.
@@ -210,8 +210,8 @@ public:
     unsigned GetNumViewports() const { return viewports_.Size(); }
     unsigned GetNumViewports() const { return viewports_.Size(); }
     /// Return viewport.
     /// Return viewport.
     Viewport* GetViewport(unsigned index) const;
     Viewport* GetViewport(unsigned index) const;
-    /// Return rendering mode.
-    RenderMode GetRenderMode() const { return renderMode_; }
+    /// Return default renderpath resource name.
+    const String& GetDefaultRenderPathName() const { return defaultRenderPathName_; }
     /// Return whether specular lighting is enabled.
     /// Return whether specular lighting is enabled.
     bool GetSpecularLighting() const { return specularLighting_; }
     bool GetSpecularLighting() const { return specularLighting_; }
     /// Return whether drawing shadows is enabled.
     /// Return whether drawing shadows is enabled.
@@ -295,6 +295,8 @@ public:
     void DrawDebugGeometry(bool depthTest);
     void DrawDebugGeometry(bool depthTest);
     /// Add a view. Return true if successful.
     /// Add a view. Return true if successful.
     bool AddView(RenderSurface* renderTarget, Viewport* viewport);
     bool AddView(RenderSurface* renderTarget, Viewport* viewport);
+    /// Populate light volume shaders.
+    void GetLightVolumeShaders(PODVector<ShaderVariation*>& lightVS, PODVector<ShaderVariation*>& lightPS, const String& vsName, const String& psName);
     /// Return volume geometry for a light.
     /// Return volume geometry for a light.
     Geometry* GetLightGeometry(Light* light);
     Geometry* GetLightGeometry(Light* light);
     /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time.
     /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time.
@@ -312,7 +314,7 @@ public:
     /// Choose shaders for a forward rendering batch.
     /// Choose shaders for a forward rendering batch.
     void SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows = true);
     void SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows = true);
     /// Choose shaders for a light volume batch.
     /// Choose shaders for a light volume batch.
-    void SetLightVolumeBatchShaders(Batch& batch);
+    void SetLightVolumeBatchShaders(Batch& batch, PODVector<ShaderVariation*>& lightVS, PODVector<ShaderVariation*>& lightPS);
     /// Set cull mode while taking possible projection flipping into account.
     /// Set cull mode while taking possible projection flipping into account.
     void SetCullMode(CullMode mode, Camera* camera);
     void SetCullMode(CullMode mode, Camera* camera);
     /// Ensure sufficient size of the instancing vertex buffer. Return true if successful.
     /// Ensure sufficient size of the instancing vertex buffer. Return true if successful.
@@ -398,10 +400,6 @@ private:
     SharedPtr<ShaderVariation> stencilVS_;
     SharedPtr<ShaderVariation> stencilVS_;
     /// Stencil rendering pixel shader.
     /// Stencil rendering pixel shader.
     SharedPtr<ShaderVariation> stencilPS_;
     SharedPtr<ShaderVariation> stencilPS_;
-    /// Light vertex shaders.
-    Vector<SharedPtr<ShaderVariation> > lightVS_;
-    /// Light pixel shaders.
-    Vector<SharedPtr<ShaderVariation> > lightPS_;
     /// Reusable scene nodes with shadow camera components.
     /// Reusable scene nodes with shadow camera components.
     Vector<SharedPtr<Node> > shadowCameraNodes_;
     Vector<SharedPtr<Node> > shadowCameraNodes_;
     /// Reusable occlusion buffers.
     /// Reusable occlusion buffers.
@@ -430,12 +428,12 @@ private:
     HashSet<Technique*> shaderErrorDisplayed_;
     HashSet<Technique*> shaderErrorDisplayed_;
     /// Mutex for shadow camera allocation.
     /// Mutex for shadow camera allocation.
     Mutex rendererMutex_;
     Mutex rendererMutex_;
+    /// Default renderpath resource name.
+    String defaultRenderPathName_;
     /// Base directory for shaders.
     /// Base directory for shaders.
     String shaderPath_;
     String shaderPath_;
     /// Frame info for rendering.
     /// Frame info for rendering.
     FrameInfo frame_;
     FrameInfo frame_;
-    /// Rendering mode.
-    RenderMode renderMode_;
     /// Texture anisotropy level.
     /// Texture anisotropy level.
     int textureAnisotropy_;
     int textureAnisotropy_;
     /// Texture filtering mode.
     /// Texture filtering mode.

+ 271 - 334
Engine/Graphics/View.cpp

@@ -294,12 +294,13 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
     if (!camera->IsProjectionValid())
     if (!camera->IsProjectionValid())
         return false;
         return false;
     
     
-    renderMode_ = renderer_->GetRenderMode();
     scene_ = scene;
     scene_ = scene;
     octree_ = octree;
     octree_ = octree;
     camera_ = camera;
     camera_ = camera;
     cameraNode_ = camera->GetNode();
     cameraNode_ = camera->GetNode();
     renderTarget_ = renderTarget;
     renderTarget_ = renderTarget;
+    depthStencil_ = GetDepthStencil(renderTarget_);
+    renderPath_ = &viewport->GetRenderPath();
     
     
     // Get active post-processing effects on the viewport
     // Get active post-processing effects on the viewport
     const Vector<SharedPtr<PostProcess> >& postProcesses = viewport->GetPostProcesses();
     const Vector<SharedPtr<PostProcess> >& postProcesses = viewport->GetPostProcesses();
@@ -311,6 +312,47 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
             postProcesses_.Push(*i);
             postProcesses_.Push(*i);
     }
     }
     
     
+    // Make sure that all necessary batch queues exist
+    scenePasses_.Clear();
+    for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
+    {
+        const RenderPathCommand& command = renderPath_->commands_[i];
+        
+        if (command.type_ == CMD_SCENEPASS)
+        {
+            ScenePassInfo info;
+            info.pass_ = command.pass_;
+            info.allowInstancing_ = command.sortMode_ != SORT_BACKTOFRONT;
+            info.markToStencil_ = command.markToStencil_;
+            info.useScissor_ = command.useScissor_;
+            info.vertexLights_ = command.vertexLights_;
+            
+            HashMap<StringHash, BatchQueue>::Iterator j = batchQueues_.Find(command.pass_);
+            if (j == batchQueues_.End())
+                j = batchQueues_.Insert(Pair<StringHash, BatchQueue>(command.pass_, BatchQueue()));
+            info.batchQueue_ = &j->second_;
+            
+            scenePasses_.Push(info);
+        }
+    }
+    
+    // Get light volume shaders according to the renderpath, if it needs them
+    deferred_ = false;
+    for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
+    {
+        const RenderPathCommand& command = renderPath_->commands_[i];
+        if (command.type_ == CMD_LIGHTVOLUMES)
+        {
+            renderer_->GetLightVolumeShaders(lightVS_, lightPS_, command.vertexShaderName_, command.pixelShaderName_);
+            deferred_ = true;
+        }
+    }
+    if (!deferred_)
+    {
+        lightVS_.Clear();
+        lightPS_.Clear();
+    }
+    
     // Validate the rect and calculate size. If zero rect, use whole rendertarget size
     // Validate the rect and calculate size. If zero rect, use whole rendertarget size
     int rtWidth = renderTarget ? renderTarget->GetWidth() : graphics_->GetWidth();
     int rtWidth = renderTarget ? renderTarget->GetWidth() : graphics_->GetWidth();
     int rtHeight = renderTarget ? renderTarget->GetHeight() : graphics_->GetHeight();
     int rtHeight = renderTarget ? renderTarget->GetHeight() : graphics_->GetHeight();
@@ -368,17 +410,15 @@ void View::Update(const FrameInfo& frame)
     
     
     // Clear screen buffers, geometry, light, occluder & batch lists
     // Clear screen buffers, geometry, light, occluder & batch lists
     screenBuffers_.Clear();
     screenBuffers_.Clear();
+    renderTargets_.Clear();
     geometries_.Clear();
     geometries_.Clear();
     shadowGeometries_.Clear();
     shadowGeometries_.Clear();
     lights_.Clear();
     lights_.Clear();
     zones_.Clear();
     zones_.Clear();
     occluders_.Clear();
     occluders_.Clear();
-    baseQueue_.Clear(maxSortedInstances);
-    preAlphaQueue_.Clear(maxSortedInstances);
-    gbufferQueue_.Clear(maxSortedInstances);
-    alphaQueue_.Clear(maxSortedInstances);
-    postAlphaQueue_.Clear(maxSortedInstances);
     vertexLightQueues_.Clear();
     vertexLightQueues_.Clear();
+    for (HashMap<StringHash, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
+        i->second_.Clear(maxSortedInstances);
     
     
     // Set automatic aspect ratio if required
     // Set automatic aspect ratio if required
     if (camera_->GetAutoAspectRatio())
     if (camera_->GetAutoAspectRatio())
@@ -434,10 +474,7 @@ void View::Render()
     #endif
     #endif
     
     
     // Render
     // Render
-    if (renderMode_ == RENDER_FORWARD)
-        RenderBatchesForward();
-    else
-        RenderBatchesDeferred();
+    ExecuteRenderPathCommands();
     
     
     #ifdef USE_OPENGL
     #ifdef USE_OPENGL
     camera_->SetFlipVertical(false);
     camera_->SetFlipVertical(false);
@@ -658,6 +695,7 @@ void View::GetBatches()
 {
 {
     WorkQueue* queue = GetSubsystem<WorkQueue>();
     WorkQueue* queue = GetSubsystem<WorkQueue>();
     PODVector<Light*> vertexLights;
     PODVector<Light*> vertexLights;
+    BatchQueue* alphaQueue = batchQueues_.Contains(PASS_ALPHA) ? &batchQueues_[PASS_ALPHA] : (BatchQueue*)0;
     
     
     // Process lit geometries and shadow casters for each light
     // Process lit geometries and shadow casters for each light
     {
     {
@@ -792,13 +830,13 @@ void View::GetBatches()
                     
                     
                     // If drawable limits maximum lights, only record the light, and check maximum count / build batches later
                     // If drawable limits maximum lights, only record the light, and check maximum count / build batches later
                     if (!drawable->GetMaxLights())
                     if (!drawable->GetMaxLights())
-                        GetLitBatches(drawable, lightQueue);
+                        GetLitBatches(drawable, lightQueue, alphaQueue);
                     else
                     else
                         maxLightsDrawables_.Insert(drawable);
                         maxLightsDrawables_.Insert(drawable);
                 }
                 }
                 
                 
                 // In deferred modes, store the light volume batch now
                 // In deferred modes, store the light volume batch now
-                if (renderMode_ != RENDER_FORWARD)
+                if (deferred_)
                 {
                 {
                     Batch volumeBatch;
                     Batch volumeBatch;
                     volumeBatch.geometry_ = renderer_->GetLightGeometry(light);
                     volumeBatch.geometry_ = renderer_->GetLightGeometry(light);
@@ -810,7 +848,7 @@ void View::GetBatches()
                     volumeBatch.material_ = 0;
                     volumeBatch.material_ = 0;
                     volumeBatch.pass_ = 0;
                     volumeBatch.pass_ = 0;
                     volumeBatch.zone_ = 0;
                     volumeBatch.zone_ = 0;
-                    renderer_->SetLightVolumeBatchShaders(volumeBatch);
+                    renderer_->SetLightVolumeBatchShaders(volumeBatch, lightVS_, lightPS_);
                     lightQueue.volumeBatches_.Push(volumeBatch);
                     lightQueue.volumeBatches_.Push(volumeBatch);
                 }
                 }
             }
             }
@@ -844,7 +882,7 @@ void View::GetBatches()
                 // Find the correct light queue again
                 // Find the correct light queue again
                 LightBatchQueue* queue = light->GetLightQueue();
                 LightBatchQueue* queue = light->GetLightQueue();
                 if (queue)
                 if (queue)
-                    GetLitBatches(drawable, *queue);
+                    GetLitBatches(drawable, *queue, alphaQueue);
             }
             }
         }
         }
     }
     }
@@ -853,8 +891,6 @@ void View::GetBatches()
     {
     {
         PROFILE(GetBaseBatches);
         PROFILE(GetBaseBatches);
         
         
-        hasZeroLightMask_ = false;
-        
         for (PODVector<Drawable*>::ConstIterator i = geometries_.Begin(); i != geometries_.End(); ++i)
         for (PODVector<Drawable*>::ConstIterator i = geometries_.Begin(); i != geometries_.End(); ++i)
         {
         {
             Drawable* drawable = *i;
             Drawable* drawable = *i;
@@ -874,10 +910,6 @@ void View::GetBatches()
                 if (srcBatch.material_ && srcBatch.material_->GetAuxViewFrameNumber() != frame_.frameNumber_ && !renderTarget_)
                 if (srcBatch.material_ && srcBatch.material_->GetAuxViewFrameNumber() != frame_.frameNumber_ && !renderTarget_)
                     CheckMaterialForAuxView(srcBatch.material_);
                     CheckMaterialForAuxView(srcBatch.material_);
                 
                 
-                // If already has a lit base pass, skip (forward rendering only)
-                if (j < 32 && drawable->HasBasePass(j))
-                    continue;
-                
                 Technique* tech = GetTechnique(drawable, srcBatch.material_);
                 Technique* tech = GetTechnique(drawable, srcBatch.material_);
                 if (!srcBatch.geometry_ || !tech)
                 if (!srcBatch.geometry_ || !tech)
                     continue;
                     continue;
@@ -889,37 +921,23 @@ void View::GetBatches()
                 destBatch.pass_ = 0;
                 destBatch.pass_ = 0;
                 destBatch.lightMask_ = GetLightMask(drawable);
                 destBatch.lightMask_ = GetLightMask(drawable);
                 
                 
-                // In deferred modes check for G-buffer and material passes first
-                if (renderMode_ == RENDER_PREPASS)
-                {
-                    destBatch.pass_ = tech->GetPass(PASS_PREPASS);
-                    if (destBatch.pass_)
-                    {
-                        // If the opaque object has a zero lightmask, have to skip light buffer optimization
-                        if (!hasZeroLightMask_ && (!(GetLightMask(drawable) & 0xff)))
-                            hasZeroLightMask_ = true;
-                        
-                        // Allow G-buffer pass instancing only if lightmask matches zone lightmask
-                        AddBatchToQueue(gbufferQueue_, destBatch, tech, destBatch.lightMask_ == (zone->GetLightMask() & 0xff));
-                        destBatch.pass_ = tech->GetPass(PASS_MATERIAL);
-                    }
-                }
-                
-                if (renderMode_ == RENDER_DEFERRED)
-                    destBatch.pass_ = tech->GetPass(PASS_DEFERRED);
-                
-                // Next check for forward unlit base pass
-                if (!destBatch.pass_)
-                    destBatch.pass_ = tech->GetPass(PASS_BASE);
-                
-                if (destBatch.pass_)
+                // Check each of the scene passes
+                for (unsigned k = 0; k < scenePasses_.Size(); ++k)
                 {
                 {
-                    // Check for vertex lights (both forward unlit, light pre-pass material pass, and deferred G-buffer)
-                    if (!drawableVertexLights.Empty())
+                    ScenePassInfo& info = scenePasses_[k];
+                    destBatch.pass_ = tech->GetPass(info.pass_);
+                    if (!destBatch.pass_)
+                        continue;
+                    
+                    // Skip forward base pass if the corresponding litbase pass already exists
+                    if (info.pass_ == PASS_BASE && j < 32 && drawable->HasBasePass(j))
+                        continue;
+                    
+                    if (info.vertexLights_ && !drawableVertexLights.Empty())
                     {
                     {
                         // For a deferred opaque batch, check if the vertex lights include converted per-pixel lights, and remove
                         // For a deferred opaque batch, check if the vertex lights include converted per-pixel lights, and remove
                         // them to prevent double-lighting
                         // them to prevent double-lighting
-                        if (renderMode_ != RENDER_FORWARD && destBatch.pass_->GetBlendMode() == BLEND_REPLACE)
+                        if (deferred_ && destBatch.pass_->GetBlendMode() == BLEND_REPLACE)
                         {
                         {
                             vertexLights.Clear();
                             vertexLights.Clear();
                             for (unsigned i = 0; i < drawableVertexLights.Size(); ++i)
                             for (unsigned i = 0; i < drawableVertexLights.Size(); ++i)
@@ -947,40 +965,14 @@ void View::GetBatches()
                             destBatch.lightQueue_ = &(i->second_);
                             destBatch.lightQueue_ = &(i->second_);
                         }
                         }
                     }
                     }
-                    
-                    // Check whether batch is opaque or transparent
-                    if (destBatch.pass_->GetBlendMode() == BLEND_REPLACE)
-                    {
-                        if (destBatch.pass_->GetType() != PASS_DEFERRED)
-                            AddBatchToQueue(baseQueue_, destBatch, tech);
-                        else
-                        {
-                            // Allow G-buffer pass instancing only if lightmask matches zone lightmask
-                            AddBatchToQueue(gbufferQueue_, destBatch, tech, destBatch.lightMask_ == (destBatch.zone_->GetLightMask() & 0xff));
-                        }
-                    }
                     else
                     else
-                    {
-                        // Transparent batches can not be instanced
-                        AddBatchToQueue(alphaQueue_, destBatch, tech, false);
-                    }
-                    continue;
-                }
-                
-                // If no pass found so far, finally check for pre-alpha / post-alpha custom passes
-                destBatch.pass_ = tech->GetPass(PASS_PREALPHA);
-                if (destBatch.pass_)
-                {
-                    AddBatchToQueue(preAlphaQueue_, destBatch, tech);
-                    continue;
-                }
-                
-                destBatch.pass_ = tech->GetPass(PASS_POSTALPHA);
-                if (destBatch.pass_)
-                {
-                    // Post-alpha pass is treated similarly as alpha, and is not instanced
-                    AddBatchToQueue(postAlphaQueue_, destBatch, tech, false);
-                    continue;
+                        destBatch.lightQueue_ = 0;
+                    
+                    bool allowInstancing = info.allowInstancing_;
+                    if (allowInstancing && info.markToStencil_ && destBatch.lightMask_ != (zone->GetLightMask() & 0xff))
+                        allowInstancing = false;
+                    
+                    AddBatchToQueue(*info.batchQueue_, destBatch, tech, allowInstancing);
                 }
                 }
             }
             }
         }
         }
@@ -997,23 +989,19 @@ void View::UpdateGeometries()
     {
     {
         WorkItem item;
         WorkItem item;
         
         
-        item.workFunction_ = SortBatchQueueFrontToBackWork;
-        item.start_ = &baseQueue_;
-        queue->AddWorkItem(item);
-        item.start_ = &preAlphaQueue_;
-        queue->AddWorkItem(item);
-        if (renderMode_ != RENDER_FORWARD)
+        for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
         {
         {
-            item.start_ = &gbufferQueue_;
-            queue->AddWorkItem(item);
+            const RenderPathCommand& command = renderPath_->commands_[i];
+            
+            if (command.type_ == CMD_SCENEPASS)
+            {
+                item.workFunction_ = command.sortMode_ == SORT_FRONTTOBACK ? SortBatchQueueFrontToBackWork :
+                    SortBatchQueueBackToFrontWork;
+                item.start_ = &batchQueues_[command.pass_];
+                queue->AddWorkItem(item);
+            }
         }
         }
         
         
-        item.workFunction_ = SortBatchQueueBackToFrontWork;
-        item.start_ = &alphaQueue_;
-        queue->AddWorkItem(item);
-        item.start_ = &postAlphaQueue_;
-        queue->AddWorkItem(item);
-        
         for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
             item.workFunction_ = SortLightQueueWork;
             item.workFunction_ = SortLightQueueWork;
@@ -1079,7 +1067,7 @@ void View::UpdateGeometries()
     queue->Complete();
     queue->Complete();
 }
 }
 
 
-void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
+void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQueue* alphaQueue)
 {
 {
     Light* light = lightQueue.light_;
     Light* light = lightQueue.light_;
     Zone* zone = GetZone(drawable);
     Zone* zone = GetZone(drawable);
@@ -1099,11 +1087,11 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
             continue;
             continue;
         
         
         // Do not create pixel lit forward passes for materials that render into the G-buffer
         // Do not create pixel lit forward passes for materials that render into the G-buffer
-        if ((renderMode_ == RENDER_PREPASS && tech->HasPass(PASS_PREPASS)) || (renderMode_ == RENDER_DEFERRED &&
-            tech->HasPass(PASS_DEFERRED)))
+        if (deferred_ && (tech->HasPass(PASS_PREPASS) || tech->HasPass(PASS_DEFERRED)))
             continue;
             continue;
         
         
         Batch destBatch(srcBatch);
         Batch destBatch(srcBatch);
+        bool isLitAlpha = false;
         
         
         // Check for lit base pass. Because it uses the replace blend mode, it must be ensured to be the first light
         // Check for lit base pass. Because it uses the replace blend mode, it must be ensured to be the first light
         // Also vertex lighting or ambient gradient require the non-lit base pass, so skip in those cases
         // Also vertex lighting or ambient gradient require the non-lit base pass, so skip in those cases
@@ -1121,6 +1109,13 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
         else
         else
             destBatch.pass_ = tech->GetPass(PASS_LIGHT);
             destBatch.pass_ = tech->GetPass(PASS_LIGHT);
         
         
+        // If no lit pass, check for lit alpha
+        if (!destBatch.pass_)
+        {
+            destBatch.pass_ = tech->GetPass(PASS_LITALPHA);
+            isLitAlpha = true;
+        }
+        
         // Skip if material does not receive light at all
         // Skip if material does not receive light at all
         if (!destBatch.pass_)
         if (!destBatch.pass_)
             continue;
             continue;
@@ -1129,24 +1124,29 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue)
         destBatch.lightQueue_ = &lightQueue;
         destBatch.lightQueue_ = &lightQueue;
         destBatch.zone_ = zone;
         destBatch.zone_ = zone;
         
         
-        // Check from the ambient pass whether the object is opaque or transparent
-        Pass* ambientPass = tech->GetPass(PASS_BASE);
-        if (!ambientPass || ambientPass->GetBlendMode() == BLEND_REPLACE)
+        if (!isLitAlpha)
             AddBatchToQueue(lightQueue.litBatches_, destBatch, tech);
             AddBatchToQueue(lightQueue.litBatches_, destBatch, tech);
-        else
+        else if (alphaQueue)
         {
         {
             // Transparent batches can not be instanced
             // Transparent batches can not be instanced
-            AddBatchToQueue(alphaQueue_, destBatch, tech, false, allowTransparentShadows);
+            AddBatchToQueue(*alphaQueue, destBatch, tech, false, allowTransparentShadows);
         }
         }
     }
     }
 }
 }
 
 
-void View::RenderBatchesForward()
+void View::ExecuteRenderPathCommands()
 {
 {
     // If using hardware multisampling with post-processing, render to the backbuffer first and then resolve
     // If using hardware multisampling with post-processing, render to the backbuffer first and then resolve
-    bool resolve = screenBuffers_.Size() && !renderTarget_ && graphics_->GetMultiSample() > 1;
-    RenderSurface* renderTarget = (screenBuffers_.Size() && !resolve) ? screenBuffers_[0]->GetRenderSurface() : renderTarget_;
-    RenderSurface* depthStencil = GetDepthStencil(renderTarget);
+    if (screenBuffers_.Size())
+    {
+        usedRenderTarget_ = screenBuffers_[0]->GetRenderSurface();
+        usedDepthStencil_ = GetDepthStencil(usedRenderTarget_);
+    }
+    else
+    {
+        usedRenderTarget_ = renderTarget_;
+        usedDepthStencil_ = depthStencil_;
+    }
     
     
     // If not reusing shadowmaps, render all of them first
     // If not reusing shadowmaps, render all of them first
     if (!renderer_->GetReuseShadowMaps() && renderer_->GetDrawShadows() && !lightQueues_.Empty())
     if (!renderer_->GetReuseShadowMaps() && renderer_->GetDrawShadows() && !lightQueues_.Empty())
@@ -1160,252 +1160,173 @@ void View::RenderBatchesForward()
         }
         }
     }
     }
     
     
-    graphics_->SetRenderTarget(0, renderTarget);
-    graphics_->SetDepthStencil(depthStencil);
-    graphics_->SetViewport(viewRect_);
-    #ifndef GL_ES_VERSION_2_0
-    graphics_->Clear(CLEAR_DEPTH | CLEAR_STENCIL);
-    #else
-    graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH, farClipZone_->GetFogColor());
-    #endif
-    
     graphics_->SetFillMode(camera_->GetFillMode());
     graphics_->SetFillMode(camera_->GetFillMode());
     
     
-    // Render opaque object unlit base pass
-    if (!baseQueue_.IsEmpty())
     {
     {
-        PROFILE(RenderBase);
-        baseQueue_.Draw(this);
-    }
-    
-    // Render shadow maps + opaque objects' additive lighting
-    if (!lightQueues_.Empty())
-    {
-        PROFILE(RenderLights);
+        PROFILE(RenderCommands);
         
         
-        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
         {
         {
-            // If reusing shadowmaps, render each of them before the lit batches
-            if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
+            const RenderPathCommand& command = renderPath_->commands_[i];
+            
+            switch (command.type_)
             {
             {
-                RenderShadowMap(*i);
-                graphics_->SetRenderTarget(0, renderTarget);
-                graphics_->SetDepthStencil(depthStencil);
-                graphics_->SetViewport(viewRect_);
-                graphics_->SetFillMode(camera_->GetFillMode());
+            case CMD_CLEAR:
+                {
+                    PROFILE(ClearRenderTarget);
+                    
+                    Color clearColor = command.clearColor_;
+                    if (clearColor.r_ < 0.0f)
+                        clearColor = farClipZone_->GetFogColor();
+                    
+                    SetRenderTargets(command);
+                    graphics_->Clear(command.clearFlags_, clearColor, command.clearDepth_, command.clearStencil_);
+                }
+                break;
+                
+            case CMD_SCENEPASS:
+                if (!batchQueues_[command.pass_].IsEmpty())
+                {
+                    PROFILE(RenderScenePass);
+                    
+                    SetRenderTargets(command);
+                    SetTextures(command);
+                    batchQueues_[command.pass_].Draw(this, command.useScissor_, command.markToStencil_);
+                }
+                break;
+                
+            case CMD_FORWARDLIGHTS:
+                // Render shadow maps + opaque objects' additive lighting
+                if (!lightQueues_.Empty())
+                {
+                    PROFILE(RenderLights);
+                    
+                    SetRenderTargets(command);
+                    
+                    for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+                    {
+                        // If reusing shadowmaps, render each of them before the lit batches
+                        if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
+                        {
+                            RenderShadowMap(*i);
+                            SetRenderTargets(command);
+                            graphics_->SetFillMode(camera_->GetFillMode());
+                        }
+                        
+                        SetTextures(command);
+                        i->litBatches_.Draw(i->light_, this);
+                    }
+                    
+                    graphics_->SetScissorTest(false);
+                    graphics_->SetStencilTest(false);
+                }
+                break;
+                
+            case CMD_LIGHTVOLUMES:
+                // Render shadow maps + light volumes
+                if (!lightQueues_.Empty())
+                {
+                    PROFILE(RenderLightVolumes);
+                    
+                    SetRenderTargets(command);
+                    
+                    for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+                    {
+                        // If reusing shadowmaps, render each of them before the lit batches
+                        if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
+                        {
+                            RenderShadowMap(*i);
+                            SetRenderTargets(command);
+                        }
+                        
+                        SetTextures(command);
+                        
+                        for (unsigned j = 0; j < i->volumeBatches_.Size(); ++j)
+                        {
+                            SetupLightVolumeBatch(i->volumeBatches_[j]);
+                            i->volumeBatches_[j].Draw(this);
+                        }
+                    }
+                    
+                    graphics_->SetScissorTest(false);
+                    graphics_->SetStencilTest(false);
+                }
+                break;
             }
             }
-            
-            i->litBatches_.Draw(i->light_, this);
         }
         }
     }
     }
     
     
-    graphics_->SetScissorTest(false);
-    graphics_->SetStencilTest(false);
-    
-    #ifndef GL_ES_VERSION_2_0
-    // At this point clear the parts of viewport not occupied by opaque geometry with fog color.
-    // On OpenGL ES an ordinary color clear has been performed beforehand instead
-    graphics_->SetBlendMode(BLEND_REPLACE);
-    graphics_->SetColorWrite(true);
-    graphics_->SetDepthTest(CMP_LESSEQUAL);
-    graphics_->SetDepthWrite(false);
-    graphics_->SetFillMode(FILL_SOLID);
-    graphics_->SetScissorTest(false);
-    graphics_->SetStencilTest(false);
-    graphics_->SetShaders(renderer_->GetVertexShader("Basic"), renderer_->GetPixelShader("Basic"));
-    graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, farClipZone_->GetFogColor());
-    graphics_->ClearParameterSource(SP_MATERIAL);
-    DrawFullscreenQuad(false);
-    #endif
-    
-    graphics_->SetFillMode(camera_->GetFillMode());
-    
-    // Render pre-alpha custom pass
-    if (!preAlphaQueue_.IsEmpty())
-    {
-        PROFILE(RenderPreAlpha);
-        preAlphaQueue_.Draw(this);
-    }
-    
-    // Render transparent objects (both base passes & additive lighting)
-    if (!alphaQueue_.IsEmpty())
-    {
-        PROFILE(RenderAlpha);
-        alphaQueue_.Draw(this, true);
-    }
-    
-    // Render post-alpha custom pass
-    if (!postAlphaQueue_.IsEmpty())
-    {
-        PROFILE(RenderPostAlpha);
-        postAlphaQueue_.Draw(this);
-    }
-    
+    graphics_->SetRenderTarget(0, renderTarget_);
+    for (unsigned i = 1; i < MAX_RENDERTARGETS; ++i)
+        graphics_->SetRenderTarget(i, (RenderSurface*)0);
+    graphics_->SetDepthStencil(depthStencil_);
+    graphics_->SetViewport(viewRect_);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
     
     
     // Resolve multisampled backbuffer now if necessary
     // Resolve multisampled backbuffer now if necessary
-    if (resolve)
-        graphics_->ResolveToTexture(screenBuffers_[0], viewRect_);
+    //if (resolve)
+    //    graphics_->ResolveToTexture(screenBuffers_[0], viewRect_);
 }
 }
 
 
-void View::RenderBatchesDeferred()
+void View::SetRenderTargets(const RenderPathCommand& command)
 {
 {
-    // If not reusing shadowmaps, render all of them first
-    if (!renderer_->GetReuseShadowMaps() && renderer_->GetDrawShadows() && !lightQueues_.Empty())
+    unsigned index = 0;
+    
+    while (index < command.outputs_.Size())
     {
     {
-        PROFILE(RenderShadowMaps);
-        
-        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        if (!command.outputs_[index].Compare("viewport", false))
+            graphics_->SetRenderTarget(index, usedRenderTarget_);
+        else
         {
         {
-            if (i->shadowMap_)
-                RenderShadowMap(*i);
+            StringHash nameHash(command.outputs_[index]);
+            if (renderTargets_.Contains(nameHash))
+                graphics_->SetRenderTarget(index, renderTargets_[nameHash]);
+            else
+                graphics_->SetRenderTarget(0, (RenderSurface*)0);
         }
         }
+        
+        ++index;
     }
     }
     
     
-    // In light prepass mode the albedo buffer is used for light accumulation instead
-    Texture2D* albedoBuffer = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBAFormat());
-    Texture2D* normalBuffer = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBAFormat());
-    Texture2D* depthBuffer = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetLinearDepthFormat());
-    
-    RenderSurface* renderTarget = screenBuffers_.Size() ? screenBuffers_[0]->GetRenderSurface() : renderTarget_;
-    RenderSurface* depthStencil = renderer_->GetDepthStencil(rtSize_.x_, rtSize_.y_);
-    
-    if (renderMode_ == RENDER_PREPASS)
+    while (index < MAX_RENDERTARGETS)
     {
     {
-        graphics_->SetRenderTarget(0, normalBuffer);
-        graphics_->SetRenderTarget(1, depthBuffer);
-    }
-    else
-    {
-        graphics_->SetRenderTarget(0, renderTarget);
-        graphics_->SetRenderTarget(1, albedoBuffer);
-        graphics_->SetRenderTarget(2, normalBuffer);
-        graphics_->SetRenderTarget(3, depthBuffer);
+        graphics_->SetRenderTarget(index, (RenderSurface*)0);
+        ++index;
     }
     }
     
     
-    graphics_->SetDepthStencil(depthStencil);
+    graphics_->SetDepthStencil(usedDepthStencil_);
     graphics_->SetViewport(viewRect_);
     graphics_->SetViewport(viewRect_);
-    graphics_->Clear(CLEAR_DEPTH | CLEAR_STENCIL);
-    
-    graphics_->SetFillMode(camera_->GetFillMode());
-    
-    // Render G-buffer batches
-    if (!gbufferQueue_.IsEmpty())
-    {
-        PROFILE(RenderGBuffer);
-        gbufferQueue_.Draw(this, false, true);
-    }
-    
-    graphics_->SetFillMode(FILL_SOLID);
-    
-    // Clear the light accumulation buffer (light pre-pass only.) However, skip the clear if the first light is a directional
-    // light with full mask
-    RenderSurface* lightRenderTarget = renderMode_ == RENDER_PREPASS ? albedoBuffer->GetRenderSurface() : renderTarget;
-    if (renderMode_ == RENDER_PREPASS)
-    {
-        bool optimizeLightBuffer = !hasZeroLightMask_ && !lightQueues_.Empty() && lightQueues_.Front().light_->GetLightType() ==
-            LIGHT_DIRECTIONAL && (lightQueues_.Front().light_->GetLightMask() & 0xff) == 0xff;
-        
-        graphics_->SetRenderTarget(0, lightRenderTarget);
-        graphics_->ResetRenderTarget(1);
-        graphics_->SetDepthStencil(depthStencil);
-        graphics_->SetViewport(viewRect_);
-        if (!optimizeLightBuffer)
-            graphics_->Clear(CLEAR_COLOR);
-    }
-    else
-    {
-        graphics_->ResetRenderTarget(1);
-        graphics_->ResetRenderTarget(2);
-        graphics_->ResetRenderTarget(3);
-    }
+}
+
+void View::SetTextures(const RenderPathCommand& command)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
     
     
-    // Render shadow maps + light volumes
-    if (!lightQueues_.Empty())
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
     {
     {
-        PROFILE(RenderLights);
-        
-        for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
+        if (!command.textureNames_[i].Empty())
         {
         {
-            // If reusing shadowmaps, render each of them before the lit batches
-            if (renderer_->GetReuseShadowMaps() && i->shadowMap_)
-            {
-                RenderShadowMap(*i);
-                graphics_->SetRenderTarget(0, lightRenderTarget);
-                graphics_->SetDepthStencil(depthStencil);
-                graphics_->SetViewport(viewRect_);
-            }
-            
-            if (renderMode_ == RENDER_DEFERRED)
-                graphics_->SetTexture(TU_ALBEDOBUFFER, albedoBuffer);
-            graphics_->SetTexture(TU_NORMALBUFFER, normalBuffer);
-            graphics_->SetTexture(TU_DEPTHBUFFER, depthBuffer);
-            
-            for (unsigned j = 0; j < i->volumeBatches_.Size(); ++j)
+            /// \todo allow referring to the current pingpong target
+            HashMap<StringHash, Texture2D*>::ConstIterator j = renderTargets_.Find(StringHash(command.textureNames_[i]));
+            if (j != renderTargets_.End())
+                graphics_->SetTexture(i, j->second_);
+            else
             {
             {
-                SetupLightVolumeBatch(i->volumeBatches_[j]);
-                i->volumeBatches_[j].Draw(this);
+                if (cache)
+                {
+                    Texture2D* texture = cache->GetResource<Texture2D>(command.textureNames_[i]);
+                    if (texture)
+                        graphics_->SetTexture(i, texture);
+                    else
+                    {
+                        // If requesting a texture fails, clear the texture name to prevent redundant attempts
+                        RenderPathCommand& cmdWrite = const_cast<RenderPathCommand&>(command);
+                        cmdWrite.textureNames_[i] = String();
+                    }
+                }
             }
             }
         }
         }
     }
     }
-    
-    graphics_->SetTexture(TU_ALBEDOBUFFER, 0);
-    graphics_->SetTexture(TU_NORMALBUFFER, 0);
-    graphics_->SetTexture(TU_DEPTHBUFFER, 0);
-    
-    if (renderMode_ == RENDER_PREPASS)
-    {
-        graphics_->SetRenderTarget(0, renderTarget);
-        graphics_->SetDepthStencil(depthStencil);
-        graphics_->SetViewport(viewRect_);
-    }
-    
-    // At this point clear the parts of viewport not occupied by opaque geometry with fog color
-    graphics_->SetBlendMode(BLEND_REPLACE);
-    graphics_->SetColorWrite(true);
-    graphics_->SetDepthTest(CMP_ALWAYS);
-    graphics_->SetDepthWrite(false);
-    graphics_->SetScissorTest(false);
-    graphics_->SetStencilTest(true, CMP_EQUAL, OP_KEEP, OP_KEEP, OP_KEEP, 0);
-    graphics_->SetShaders(renderer_->GetVertexShader("Basic"), renderer_->GetPixelShader("Basic"));
-    graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, farClipZone_->GetFogColor());
-    graphics_->ClearParameterSource(SP_MATERIAL);
-    DrawFullscreenQuad(false);
-    
-    graphics_->SetFillMode(camera_->GetFillMode());
-    
-    // Render opaque objects with deferred lighting result (light pre-pass only)
-    if (!baseQueue_.IsEmpty())
-    {
-        PROFILE(RenderBase);
-        
-        graphics_->SetTexture(TU_LIGHTBUFFER, renderMode_ == RENDER_PREPASS ? albedoBuffer : 0);
-        baseQueue_.Draw(this);
-        graphics_->SetTexture(TU_LIGHTBUFFER, 0);
-    }
-    
-    // Render pre-alpha custom pass
-    if (!preAlphaQueue_.IsEmpty())
-    {
-        PROFILE(RenderPreAlpha);
-        preAlphaQueue_.Draw(this);
-    }
-    
-    // Render transparent objects (both base passes & additive lighting)
-    if (!alphaQueue_.IsEmpty())
-    {
-        PROFILE(RenderAlpha);
-        alphaQueue_.Draw(this, true);
-    }
-    
-    // Render post-alpha custom pass
-    if (!postAlphaQueue_.IsEmpty())
-    {
-        PROFILE(RenderPostAlpha);
-        postAlphaQueue_.Draw(this);
-    }
-    
-    graphics_->SetFillMode(FILL_SOLID);
 }
 }
 
 
 void View::AllocateScreenBuffers()
 void View::AllocateScreenBuffers()
@@ -1414,8 +1335,8 @@ void View::AllocateScreenBuffers()
     #ifdef USE_OPENGL
     #ifdef USE_OPENGL
     // Due to FBO limitations, in OpenGL deferred modes need to render to texture first and then blit to the backbuffer
     // Due to FBO limitations, in OpenGL deferred modes need to render to texture first and then blit to the backbuffer
     // Also, if rendering to a texture with deferred rendering, it must be RGBA to comply with the rest of the buffers.
     // Also, if rendering to a texture with deferred rendering, it must be RGBA to comply with the rest of the buffers.
-    if (renderMode_ != RENDER_FORWARD && (!renderTarget_ || (renderMode_ == RENDER_DEFERRED &&
-        renderTarget_->GetParentTexture()->GetFormat() != Graphics::GetRGBAFormat())))
+    if (deferred_ && (!renderTarget_ || (deferred_ && renderTarget_->GetParentTexture()->GetFormat() != 
+        Graphics::GetRGBAFormat())))
         neededBuffers = 1;
         neededBuffers = 1;
     #endif
     #endif
     
     
@@ -1429,13 +1350,34 @@ void View::AllocateScreenBuffers()
     
     
     unsigned format = Graphics::GetRGBFormat();
     unsigned format = Graphics::GetRGBFormat();
     #ifdef USE_OPENGL
     #ifdef USE_OPENGL
-    if (renderMode_ == RENDER_DEFERRED)
+    if (deferred_)
         format = Graphics::GetRGBAFormat();
         format = Graphics::GetRGBAFormat();
     #endif
     #endif
     
     
     // Allocate screen buffers with filtering active in case the post-processing effects need that
     // Allocate screen buffers with filtering active in case the post-processing effects need that
     for (unsigned i = 0; i < neededBuffers; ++i)
     for (unsigned i = 0; i < neededBuffers; ++i)
         screenBuffers_.Push(renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, format, true));
         screenBuffers_.Push(renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, format, true));
+    
+    // Allocate extra render targets defined by the rendering path
+    for (unsigned i = 0; i < renderPath_->renderTargets_.Size(); ++i)
+    {
+        const RenderTargetInfo& rtInfo = renderPath_->renderTargets_[i];
+        unsigned width = rtInfo.size_.x_;
+        unsigned height = rtInfo.size_.y_;
+        if (!width || !height)
+        {
+            width = rtSize_.x_;
+            height = rtSize_.y_;
+        }
+        
+        if (rtInfo.sizeDivisor_)
+        {
+            width = rtSize_.x_ / width;
+            height = rtSize_.y_ / height;
+        }
+        
+        renderTargets_[StringHash(rtInfo.name_)] = renderer_->GetScreenBuffer(width, height, rtInfo.format_, rtInfo.filtered_);
+    }
 }
 }
 
 
 void View::BlitFramebuffer()
 void View::BlitFramebuffer()
@@ -1593,7 +1535,7 @@ void View::RunPostProcesses()
             }
             }
             
             
             const String* textureNames = pass->GetTextures();
             const String* textureNames = pass->GetTextures();
-            for (unsigned k = 0; k < MAX_MATERIAL_TEXTURE_UNITS; ++k)
+            for (unsigned k = 0; k < MAX_TEXTURE_UNITS; ++k)
             {
             {
                 if (!textureNames[k].Empty())
                 if (!textureNames[k].Empty())
                 {
                 {
@@ -2380,10 +2322,8 @@ void View::PrepareInstancingBuffer()
     
     
     unsigned totalInstances = 0;
     unsigned totalInstances = 0;
     
     
-    totalInstances += baseQueue_.GetNumInstances();
-    totalInstances += preAlphaQueue_.GetNumInstances();
-    if (renderMode_ != RENDER_FORWARD)
-        totalInstances += gbufferQueue_.GetNumInstances();
+    for (HashMap<StringHash, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
+        totalInstances += i->second_.GetNumInstances();
     
     
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
     {
     {
@@ -2401,10 +2341,8 @@ void View::PrepareInstancingBuffer()
         if (!dest)
         if (!dest)
             return;
             return;
         
         
-        baseQueue_.SetTransforms(this, dest, freeIndex);
-        preAlphaQueue_.SetTransforms(this, dest, freeIndex);
-        if (renderMode_ != RENDER_FORWARD)
-            gbufferQueue_.SetTransforms(this, dest, freeIndex);
+        for (HashMap<StringHash, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
+            i->second_.SetTransforms(this, dest, freeIndex);
         
         
         for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
         {
         {
@@ -2424,8 +2362,7 @@ void View::SetupLightVolumeBatch(Batch& batch)
     Vector3 cameraPos = cameraNode_->GetWorldPosition();
     Vector3 cameraPos = cameraNode_->GetWorldPosition();
     float lightDist;
     float lightDist;
     
     
-    // Use replace blend mode for the first pre-pass light volume, and additive for the rest
-    graphics_->SetBlendMode(renderMode_ == RENDER_PREPASS && light == lightQueues_.Front().light_ ? BLEND_REPLACE : BLEND_ADD);
+    graphics_->SetBlendMode(BLEND_ADD);
     graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetDepthWrite(false);
     graphics_->SetDepthWrite(false);
     
     

+ 46 - 19
Engine/Graphics/View.h

@@ -43,6 +43,8 @@ class Technique;
 class Texture2D;
 class Texture2D;
 class Viewport;
 class Viewport;
 class Zone;
 class Zone;
+struct RenderPath;
+struct RenderPathCommand;
 struct WorkItem;
 struct WorkItem;
 
 
 /// Intermediate light processing result.
 /// Intermediate light processing result.
@@ -70,6 +72,23 @@ struct LightQueryResult
     unsigned numSplits_;
     unsigned numSplits_;
 };
 };
 
 
+/// Scene render pass info.
+struct ScenePassInfo
+{
+    /// Pass name hash.
+    StringHash pass_;
+    /// Allow instancing flag.
+    bool allowInstancing_;
+    /// Mark to stencil flag.
+    bool markToStencil_;
+    /// Light scissor optimization flag.
+    bool useScissor_;
+    /// Vertex light flag.
+    bool vertexLights_;
+    /// Batch queue.
+    BatchQueue* batchQueue_;
+};
+
 /// 3D rendering view. Includes the main view(s) and any auxiliary views, but not shadow cameras.
 /// 3D rendering view. Includes the main view(s) and any auxiliary views, but not shadow cameras.
 class View : public Object
 class View : public Object
 {
 {
@@ -120,11 +139,13 @@ private:
     /// Update geometries and sort batches.
     /// Update geometries and sort batches.
     void UpdateGeometries();
     void UpdateGeometries();
     /// Get pixel lit batches for a certain light and drawable.
     /// Get pixel lit batches for a certain light and drawable.
-    void GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue);
-    /// Render batches using forward rendering.
-    void RenderBatchesForward();
-    /// Render batches using light pre-pass or deferred rendering.
-    void RenderBatchesDeferred();
+    void GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQueue* alphaQueue);
+    /// Execute render commands.
+    void ExecuteRenderPathCommands();
+    /// Set rendertargets for current render command.
+    void SetRenderTargets(const RenderPathCommand& command);
+    /// Set textures for current render command.
+    void SetTextures(const RenderPathCommand& command);
     /// Allocate needed screen buffers for post-processing and/or framebuffer blitting.
     /// Allocate needed screen buffers for post-processing and/or framebuffer blitting.
     void AllocateScreenBuffers();
     void AllocateScreenBuffers();
     /// Blit the framebuffer to destination. Used in OpenGL deferred rendering modes.
     /// Blit the framebuffer to destination. Used in OpenGL deferred rendering modes.
@@ -198,6 +219,12 @@ private:
     OcclusionBuffer* occlusionBuffer_;
     OcclusionBuffer* occlusionBuffer_;
     /// Color rendertarget to use.
     /// Color rendertarget to use.
     RenderSurface* renderTarget_;
     RenderSurface* renderTarget_;
+    /// Depth stencil to use.
+    RenderSurface* depthStencil_;
+    /// Effective color rendertarget to use, may be different if screenbuffers are used.
+    RenderSurface* usedRenderTarget_;
+    /// Effective depth stencil to use, may be different if screenbuffers are used.
+    RenderSurface* usedDepthStencil_;
     /// Viewport rectangle.
     /// Viewport rectangle.
     IntRect viewRect_;
     IntRect viewRect_;
     /// Viewport size.
     /// Viewport size.
@@ -212,8 +239,6 @@ private:
     float minZ_;
     float minZ_;
     /// Maximum Z value of the visible scene.
     /// Maximum Z value of the visible scene.
     float maxZ_;
     float maxZ_;
-    /// Rendering mode.
-    RenderMode renderMode_;
     /// Material quality level.
     /// Material quality level.
     int materialQuality_;
     int materialQuality_;
     /// Maximum number of occluder triangles.
     /// Maximum number of occluder triangles.
@@ -224,8 +249,10 @@ private:
     bool cameraZoneOverride_;
     bool cameraZoneOverride_;
     /// Draw shadows flag.
     /// Draw shadows flag.
     bool drawShadows_;
     bool drawShadows_;
-    /// Whether objects with zero lightmask exist. In light pre-pass mode this means skipping some optimizations.
-    bool hasZeroLightMask_;
+    /// Deferred flag. Inferred from the existence of a light volume command in the renderpath.
+    bool deferred_;
+    /// Renderpath.
+    const RenderPath* renderPath_;
     /// Post-processing effects.
     /// Post-processing effects.
     Vector<SharedPtr<PostProcess> > postProcesses_;
     Vector<SharedPtr<PostProcess> > postProcesses_;
     /// Intermediate screen buffers used in postprocessing and OpenGL deferred framebuffer blit.
     /// Intermediate screen buffers used in postprocessing and OpenGL deferred framebuffer blit.
@@ -246,24 +273,24 @@ private:
     PODVector<Drawable*> occluders_;
     PODVector<Drawable*> occluders_;
     /// Lights.
     /// Lights.
     PODVector<Light*> lights_;
     PODVector<Light*> lights_;
+    /// Light volume vertex shaders.
+    PODVector<ShaderVariation*> lightVS_;
+    /// Light volume pixel shaders.
+    PODVector<ShaderVariation*> lightPS_;
     /// Drawables that limit their maximum light count.
     /// Drawables that limit their maximum light count.
     HashSet<Drawable*> maxLightsDrawables_;
     HashSet<Drawable*> maxLightsDrawables_;
+    /// Rendertargets defined by the renderpath.
+    HashMap<StringHash, Texture2D*> renderTargets_;
     /// Intermediate light processing results.
     /// Intermediate light processing results.
     Vector<LightQueryResult> lightQueryResults_;
     Vector<LightQueryResult> lightQueryResults_;
+    /// Info for scene render passes defined by the renderpath.
+    Vector<ScenePassInfo> scenePasses_;
     /// Per-pixel light queues.
     /// Per-pixel light queues.
     Vector<LightBatchQueue> lightQueues_;
     Vector<LightBatchQueue> lightQueues_;
     /// Per-vertex light queues.
     /// Per-vertex light queues.
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
-    /// Base pass batches.
-    BatchQueue baseQueue_;
-    /// Deferred rendering G-buffer batches.
-    BatchQueue gbufferQueue_;
-    /// Pre-transparent pass batches.
-    BatchQueue preAlphaQueue_;
-    /// Transparent geometry batches.
-    BatchQueue alphaQueue_;
-    /// Post-transparent pass batches.
-    BatchQueue postAlphaQueue_;
+    /// Batch queues.
+    HashMap<StringHash, BatchQueue> batchQueues_;
 };
 };
 
 
 }
 }

+ 86 - 54
Engine/Graphics/Viewport.cpp

@@ -26,6 +26,7 @@
 #include "Graphics.h"
 #include "Graphics.h"
 #include "Log.h"
 #include "Log.h"
 #include "PostProcess.h"
 #include "PostProcess.h"
+#include "Renderer.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
 #include "Scene.h"
 #include "Scene.h"
 #include "StringUtils.h"
 #include "StringUtils.h"
@@ -38,7 +39,7 @@ namespace Urho3D
 
 
 TextureUnit ParseTextureUnitName(const String& name);
 TextureUnit ParseTextureUnitName(const String& name);
 
 
-static const String cmdNames[] =
+static const String commandTypeNames[] =
 {
 {
     "clear",
     "clear",
     "scenepass",
     "scenepass",
@@ -48,6 +49,13 @@ static const String cmdNames[] =
     ""
     ""
 };
 };
 
 
+static const String sortModeNames[] =
+{
+    "fronttoback"
+    "backtofront",
+    ""
+};
+
 OBJECTTYPESTATIC(Viewport);
 OBJECTTYPESTATIC(Viewport);
 
 
 Viewport::Viewport(Context* context) :
 Viewport::Viewport(Context* context) :
@@ -117,8 +125,9 @@ void Viewport::SetRect(const IntRect& rect)
 bool Viewport::SetRenderPath(XMLFile* file)
 bool Viewport::SetRenderPath(XMLFile* file)
 {
 {
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     ResourceCache* cache = GetSubsystem<ResourceCache>();
-    if (!file && cache)
-        file = cache->GetResource<XMLFile>("Data/RenderPaths/Forward.xml");
+    Renderer* renderer = GetSubsystem<Renderer>();
+    if (!file && cache && renderer)
+        file = cache->GetResource<XMLFile>(renderer->GetDefaultRenderPathName());
     if (!file)
     if (!file)
         return false;
         return false;
     
     
@@ -126,6 +135,9 @@ bool Viewport::SetRenderPath(XMLFile* file)
     if (!rootElem)
     if (!rootElem)
         return false;
         return false;
     
     
+    renderPath_.renderTargets_.Clear();
+    renderPath_.commands_.Clear();
+    
     XMLElement rtElem = rootElem.GetChild("rendertarget");
     XMLElement rtElem = rootElem.GetChild("rendertarget");
     while (rtElem)
     while (rtElem)
     {
     {
@@ -161,83 +173,101 @@ bool Viewport::SetRenderPath(XMLFile* file)
         
         
         if (!name.Trimmed().Empty())
         if (!name.Trimmed().Empty())
         {
         {
-            RenderTargetInfo target;
-            target.name_ = name;
-            target.format_ = format;
-            target.size_ = IntVector2(width, height),
-            target.sizeDivisor_ = sizeDivisor;
-            target.filtered_ = filtered;
-            renderPath_.renderTargets_[StringHash(name)] = target;
+            RenderTargetInfo rtInfo;
+            rtInfo.name_ = name;
+            rtInfo.format_ = format;
+            rtInfo.size_ = IntVector2(width, height),
+            rtInfo.sizeDivisor_ = sizeDivisor;
+            rtInfo.filtered_ = filtered;
+            renderPath_.renderTargets_.Push(rtInfo);
         }
         }
         
         
         rtElem = rtElem.GetNext("rendertarget");
         rtElem = rtElem.GetNext("rendertarget");
     }
     }
     
     
-    XMLElement cmdElem = rootElem.GetChild("command");
-    while (cmdElem)
+    XMLElement commandElem = rootElem.GetChild("command");
+    while (commandElem)
     {
     {
-        RenderCommandType type = (RenderCommandType)GetStringListIndex(cmdElem.GetAttributeLower("type"), cmdNames, CMD_UNKNOWN);
+        RenderCommandType type = (RenderCommandType)GetStringListIndex(commandElem.GetAttributeLower("type"), commandTypeNames,
+            CMD_UNKNOWN);
         if (type != CMD_UNKNOWN)
         if (type != CMD_UNKNOWN)
         {
         {
-            RenderPathCommand cmd;
-            cmd.type_ = type;
-            cmd.passName_ = cmdElem.GetAttribute("pass");
-            cmd.vertexShaderName_ = cmdElem.GetAttribute("vs");
-            cmd.pixelShaderName_ = cmdElem.GetAttribute("ps");
+            RenderPathCommand command;
+            command.type_ = type;
             
             
-            if (type == CMD_CLEAR)
+            switch (type)
             {
             {
-                cmd.clearFlags_ = 0;
-                if (cmdElem.HasAttribute("color"))
+            case CMD_CLEAR:
+                if (commandElem.HasAttribute("color"))
                 {
                 {
-                    cmd.clearFlags_ |= CLEAR_COLOR;
+                    command.clearFlags_ |= CLEAR_COLOR;
                     // Mark fog color with negative values
                     // Mark fog color with negative values
-                    if (cmdElem.GetAttributeLower("color") == "fog")
-                        cmd.clearColor_ = Color(-1.0f, -1.0f, -1.0f, -1.0f);
+                    if (commandElem.GetAttributeLower("color") == "fog")
+                        command.clearColor_ = Color(-1.0f, -1.0f, -1.0f, -1.0f);
                     else
                     else
-                        cmd.clearColor_ = cmdElem.GetColor("color");
+                        command.clearColor_ = commandElem.GetColor("color");
+                }
+                if (commandElem.HasAttribute("depth"))
+                {
+                    command.clearFlags_ |= CLEAR_DEPTH;
+                    command.clearDepth_ = commandElem.GetFloat("depth");
                 }
                 }
-                if (cmdElem.HasAttribute("depth"))
+                if (commandElem.HasAttribute("stencil"))
                 {
                 {
-                    cmd.clearFlags_ |= CLEAR_DEPTH;
-                    cmd.clearDepth_ = cmdElem.GetFloat("depth");
+                    command.clearFlags_ |= CLEAR_STENCIL;
+                    command.clearStencil_ = commandElem.GetInt("stencil");
                 }
                 }
-                if (cmdElem.HasAttribute("stencil"))
+                break;
+            
+            case CMD_SCENEPASS:
+                command.pass_ = StringHash(commandElem.GetAttribute("pass"));
+                command.sortMode_ = (RenderCommandSortMode)GetStringListIndex(commandElem.GetAttributeLower("sort"), sortModeNames, SORT_FRONTTOBACK);
+                if (commandElem.HasAttribute("marktostencil"))
+                    command.markToStencil_ = commandElem.GetBool("marktostencil");
+                if (commandElem.HasAttribute("vertexlights"))
+                    command.vertexLights_ = commandElem.GetBool("vertexlights");
+                if (commandElem.HasAttribute("usescissor"))
+                    command.useScissor_ = commandElem.GetBool("usescissor");
+                break;
+                
+            case CMD_LIGHTVOLUMES:
+            case CMD_QUAD:
+                command.vertexShaderName_ = commandElem.GetAttribute("vs");
+                command.pixelShaderName_ = commandElem.GetAttribute("ps");
+                if (type == CMD_QUAD)
                 {
                 {
-                    cmd.clearFlags_ |= CLEAR_STENCIL;
-                    cmd.clearStencil_ = cmdElem.GetInt("stencil");
+                    XMLElement parameterElem = commandElem.GetChild("parameter");
+                    while (parameterElem)
+                    {
+                        String name = parameterElem.GetAttribute("name");
+                        Vector4 value = parameterElem.GetVector("value");
+                        command.shaderParameters_[StringHash(name)] = value;
+                        
+                        parameterElem = parameterElem.GetNext("parameter");
+                    }
                 }
                 }
+                break;
             }
             }
             
             
             // By default use 1 output, which is the viewport
             // By default use 1 output, which is the viewport
-            cmd.outputs_.Push("viewport");
-            if (cmdElem.HasAttribute("output"))
-                cmd.outputs_[0] = cmdElem.GetAttribute("output");
+            command.outputs_.Push("viewport");
+            if (commandElem.HasAttribute("output"))
+                command.outputs_[0] = commandElem.GetAttribute("output");
             // Check for defining multiple outputs
             // Check for defining multiple outputs
-            XMLElement outputElem = cmdElem.GetChild("output");
+            XMLElement outputElem = commandElem.GetChild("output");
             while (outputElem)
             while (outputElem)
             {
             {
                 unsigned index = outputElem.GetInt("index");
                 unsigned index = outputElem.GetInt("index");
                 if (index < MAX_RENDERTARGETS)
                 if (index < MAX_RENDERTARGETS)
                 {
                 {
-                    if (index >= cmd.outputs_.Size())
-                        cmd.outputs_.Resize(index + 1);
-                    cmd.outputs_[index] = outputElem.GetAttribute("name");
+                    if (index >= command.outputs_.Size())
+                        command.outputs_.Resize(index + 1);
+                    command.outputs_[index] = outputElem.GetAttribute("name");
                 }
                 }
                 outputElem = outputElem.GetNext("output");
                 outputElem = outputElem.GetNext("output");
             }
             }
             
             
-            XMLElement parameterElem = cmdElem.GetChild("parameter");
-            while (parameterElem)
-            {
-                String name = parameterElem.GetAttribute("name");
-                Vector4 value = parameterElem.GetVector("value");
-                cmd.shaderParameters_[StringHash(name)] = value;
-                
-                parameterElem = parameterElem.GetNext("parameter");
-            }
-            
-            XMLElement textureElem = cmdElem.GetChild("texture");
+            XMLElement textureElem = commandElem.GetChild("texture");
             while (textureElem)
             while (textureElem)
             {
             {
                 TextureUnit unit = TU_DIFFUSE;
                 TextureUnit unit = TU_DIFFUSE;
@@ -247,23 +277,25 @@ bool Viewport::SetRenderPath(XMLFile* file)
                     if (unitName.Length() > 1)
                     if (unitName.Length() > 1)
                     {
                     {
                         unit = ParseTextureUnitName(unitName);
                         unit = ParseTextureUnitName(unitName);
-                        if (unit == MAX_MATERIAL_TEXTURE_UNITS)
+                        if (unit >= MAX_TEXTURE_UNITS)
                             LOGERROR("Unknown texture unit " + unitName);
                             LOGERROR("Unknown texture unit " + unitName);
                     }
                     }
                     else
                     else
-                        unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_MATERIAL_TEXTURE_UNITS - 1);
+                        unit = (TextureUnit)Clamp(ToInt(unitName), 0, MAX_TEXTURE_UNITS - 1);
                 }
                 }
-                if (unit != MAX_TEXTURE_UNITS)
+                if (unit < MAX_TEXTURE_UNITS)
                 {
                 {
                     String name = textureElem.GetAttribute("name");
                     String name = textureElem.GetAttribute("name");
-                    cmd.textureNames_[unit] = name;
+                    command.textureNames_[unit] = name;
                 }
                 }
                 
                 
                 textureElem = textureElem.GetNext("texture");
                 textureElem = textureElem.GetNext("texture");
             }
             }
+            
+            renderPath_.commands_.Push(command);
         }
         }
         
         
-        cmdElem = cmdElem.GetNext("command");
+        commandElem = commandElem.GetNext("command");
     }
     }
     
     
     return true;
     return true;

+ 18 - 5
Engine/Graphics/Viewport.h

@@ -48,8 +48,7 @@ enum RenderCommandType
 /// Rendering path sorting modes.
 /// Rendering path sorting modes.
 enum RenderCommandSortMode
 enum RenderCommandSortMode
 {
 {
-    SORT_STATE = 0,
-    SORT_FRONTTOBACK,
+    SORT_FRONTTOBACK = 0,
     SORT_BACKTOFRONT
     SORT_BACKTOFRONT
 };
 };
 
 
@@ -71,12 +70,20 @@ struct RenderTargetInfo
 /// Rendering path command.
 /// Rendering path command.
 struct RenderPathCommand
 struct RenderPathCommand
 {
 {
+    RenderPathCommand() :
+        clearFlags_(0),
+        markToStencil_(false),
+        useScissor_(false),
+        vertexLights_(false)
+    {
+    }
+    
     /// Command type.
     /// Command type.
     RenderCommandType type_;
     RenderCommandType type_;
     /// Sorting mode.
     /// Sorting mode.
     RenderCommandSortMode sortMode_;
     RenderCommandSortMode sortMode_;
-    /// Scene pass name.
-    String passName_;
+    /// Scene pass hash.
+    StringHash pass_;
     /// Clear flags.
     /// Clear flags.
     unsigned clearFlags_;
     unsigned clearFlags_;
     /// Clear color.
     /// Clear color.
@@ -85,12 +92,18 @@ struct RenderPathCommand
     float clearDepth_;
     float clearDepth_;
     /// Clear stencil value.
     /// Clear stencil value.
     unsigned clearStencil_;
     unsigned clearStencil_;
+    /// Mark to stencil flag.
+    bool markToStencil_;
+    /// Vertex lights flag.
+    bool vertexLights_;
+    /// Scissor optimization flag.
+    bool useScissor_;
     /// Vertex shader name.
     /// Vertex shader name.
     String vertexShaderName_;
     String vertexShaderName_;
     /// Pixel shader name.
     /// Pixel shader name.
     String pixelShaderName_;
     String pixelShaderName_;
     /// Textures.
     /// Textures.
-    String textureNames_[MAX_MATERIAL_TEXTURE_UNITS];
+    String textureNames_[MAX_TEXTURE_UNITS];
     /// %Shader parameters.
     /// %Shader parameters.
     HashMap<StringHash, Vector4> shaderParameters_;
     HashMap<StringHash, Vector4> shaderParameters_;
     /// Output rendertarget names.
     /// Output rendertarget names.

+ 0 - 2
Urho3D/Urho3D.cpp

@@ -75,8 +75,6 @@ void Run()
                 "-r<freq>    Sound mixing frequency in Hz\n"
                 "-r<freq>    Sound mixing frequency in Hz\n"
                 "-headless   Headless mode. No application window will be created\n"
                 "-headless   Headless mode. No application window will be created\n"
                 "-logdebug   Display debug level log messages also in release mode\n"
                 "-logdebug   Display debug level log messages also in release mode\n"
-                "-prepass    Use light pre-pass rendering\n"
-                "-deferred   Use deferred rendering\n"
                 "-lqshadows  Use low-quality (1-sample) shadow filtering\n"
                 "-lqshadows  Use low-quality (1-sample) shadow filtering\n"
                 "-noshadows  Disable shadow rendering\n"
                 "-noshadows  Disable shadow rendering\n"
                 "-nolimit    Disable frame limiter\n"
                 "-nolimit    Disable frame limiter\n"