Browse Source

Merge pull request #1026 from AtomicGameEngine/JME-ATOMIC-UPDATES

Updating to Urho master
JoshEngebretson 9 years ago
parent
commit
bcece0b087
100 changed files with 885 additions and 825 deletions
  1. 4 1
      AUTHORS.md
  2. 2 2
      Resources/CoreData/Shaders/GLSL/BRDF.glsl
  3. 2 2
      Resources/CoreData/Shaders/GLSL/Lighting.glsl
  4. 2 5
      Resources/CoreData/Shaders/GLSL/Skydome.glsl
  5. 8 1
      Resources/CoreData/Shaders/GLSL/Water.glsl
  6. 3 3
      Resources/CoreData/Shaders/HLSL/Lighting.hlsl
  7. 0 9
      Resources/CoreData/Techniques/DiffAOAlphaMask.xml
  8. 0 10
      Resources/CoreData/Techniques/DiffAlphaMask.xml
  9. 0 10
      Resources/CoreData/Techniques/DiffAlphaMaskTranslucent.xml
  10. 0 9
      Resources/CoreData/Techniques/DiffLightMapEnvCube.xml
  11. 2 2
      Resources/CoreData/Techniques/DiffNormal.xml
  12. 2 2
      Resources/CoreData/Techniques/DiffNormalAO.xml
  13. 1 1
      Resources/CoreData/Techniques/DiffNormalAOAlpha.xml
  14. 0 9
      Resources/CoreData/Techniques/DiffNormalAOAlphaMask.xml
  15. 1 1
      Resources/CoreData/Techniques/DiffNormalAlpha.xml
  16. 0 10
      Resources/CoreData/Techniques/DiffNormalAlphaMask.xml
  17. 0 10
      Resources/CoreData/Techniques/DiffNormalAlphaMaskTranslucent.xml
  18. 1 1
      Resources/CoreData/Techniques/DiffNormalAlphaTranslucent.xml
  19. 2 2
      Resources/CoreData/Techniques/DiffNormalEmissive.xml
  20. 1 1
      Resources/CoreData/Techniques/DiffNormalEmissiveAlpha.xml
  21. 2 2
      Resources/CoreData/Techniques/DiffNormalEnvCube.xml
  22. 1 1
      Resources/CoreData/Techniques/DiffNormalEnvCubeAlpha.xml
  23. 0 10
      Resources/CoreData/Techniques/DiffNormalPacked.xml
  24. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedAO.xml
  25. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedAOAlpha.xml
  26. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedAOAlphaMask.xml
  27. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedAlpha.xml
  28. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedAlphaMask.xml
  29. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedAlphaMaskTranslucent.xml
  30. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedAlphaTranslucent.xml
  31. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedEmissive.xml
  32. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedEmissiveAlpha.xml
  33. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedEnvCube.xml
  34. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedEnvCubeAlpha.xml
  35. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedSpec.xml
  36. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedSpecAO.xml
  37. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedSpecAOAlpha.xml
  38. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedSpecAOAlphaMask.xml
  39. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedSpecAlpha.xml
  40. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedSpecAlphaMask.xml
  41. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedSpecEmissive.xml
  42. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedSpecEmissiveAlpha.xml
  43. 2 2
      Resources/CoreData/Techniques/DiffNormalSpec.xml
  44. 2 2
      Resources/CoreData/Techniques/DiffNormalSpecAO.xml
  45. 1 1
      Resources/CoreData/Techniques/DiffNormalSpecAOAlpha.xml
  46. 0 9
      Resources/CoreData/Techniques/DiffNormalSpecAOAlphaMask.xml
  47. 1 1
      Resources/CoreData/Techniques/DiffNormalSpecAlpha.xml
  48. 0 10
      Resources/CoreData/Techniques/DiffNormalSpecAlphaMask.xml
  49. 2 2
      Resources/CoreData/Techniques/DiffNormalSpecEmissive.xml
  50. 1 1
      Resources/CoreData/Techniques/DiffNormalSpecEmissiveAlpha.xml
  51. 0 10
      Resources/CoreData/Techniques/DiffSpecAlphaMask.xml
  52. 0 6
      Resources/CoreData/Techniques/DiffUnlitAlphaMask.xml
  53. 2 2
      Resources/CoreData/Techniques/NoTextureNormal.xml
  54. 1 1
      Resources/CoreData/Techniques/NoTextureNormalAlpha.xml
  55. 0 10
      Resources/CoreData/Techniques/NoTextureNormalPacked.xml
  56. 0 5
      Resources/CoreData/Techniques/NoTextureNormalPackedAlpha.xml
  57. 2 2
      Resources/CoreData/Techniques/PBR/DiffNormalSpecEmissive.xml
  58. 1 1
      Resources/CoreData/Techniques/PBR/DiffNormalSpecEmissiveAlpha.xml
  59. 2 2
      Resources/CoreData/Techniques/PBR/PBRDiffNormal.xml
  60. 1 1
      Resources/CoreData/Techniques/PBR/PBRDiffNormalAlpha.xml
  61. 2 2
      Resources/CoreData/Techniques/PBR/PBRDiffNormalEmissive.xml
  62. 1 1
      Resources/CoreData/Techniques/PBR/PBRDiffNormalEmissiveAlpha.xml
  63. 2 2
      Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpec.xml
  64. 2 2
      Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissive.xml
  65. 1 1
      Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissiveAlpha.xml
  66. 0 10
      Resources/CoreData/Techniques/VegetationDiffAlphaMask.xml
  67. 0 8
      Resources/CoreData/Techniques/VegetationDiffUnlitAlphaMask.xml
  68. 12 6
      Source/Atomic/Atomic2D/Constraint2D.cpp
  69. 2 2
      Source/Atomic/Atomic2D/Constraint2D.h
  70. 21 29
      Source/Atomic/Atomic2D/PhysicsEvents2D.h
  71. 51 11
      Source/Atomic/Atomic2D/PhysicsWorld2D.cpp
  72. 5 3
      Source/Atomic/Atomic2D/RigidBody2D.cpp
  73. 4 0
      Source/Atomic/Atomic2D/TileMapLayer2D.h
  74. 7 26
      Source/Atomic/Audio/SoundSource.cpp
  75. 6 8
      Source/Atomic/Audio/SoundSource.h
  76. 6 2
      Source/Atomic/Container/HashMap.h
  77. 6 2
      Source/Atomic/Container/HashSet.h
  78. 6 3
      Source/Atomic/Container/List.h
  79. 135 142
      Source/Atomic/Container/Vector.h
  80. 2 2
      Source/Atomic/Core/Context.cpp
  81. 6 8
      Source/Atomic/Graphics/AnimatedModel.cpp
  82. 6 1
      Source/Atomic/Graphics/AnimationController.cpp
  83. 4 6
      Source/Atomic/Graphics/Batch.cpp
  84. 12 3
      Source/Atomic/Graphics/BillboardSet.cpp
  85. 7 0
      Source/Atomic/Graphics/BillboardSet.h
  86. 183 141
      Source/Atomic/Graphics/Camera.cpp
  87. 26 12
      Source/Atomic/Graphics/Camera.h
  88. 2 1
      Source/Atomic/Graphics/DebugRenderer.cpp
  89. 2 0
      Source/Atomic/Graphics/DebugRenderer.h
  90. 13 9
      Source/Atomic/Graphics/Direct3D11/D3D11Graphics.cpp
  91. 1 1
      Source/Atomic/Graphics/Direct3D11/D3D11Texture.cpp
  92. 18 17
      Source/Atomic/Graphics/Direct3D9/D3D9Graphics.cpp
  93. 2 0
      Source/Atomic/Graphics/Direct3D9/D3D9GraphicsImpl.h
  94. 16 11
      Source/Atomic/Graphics/Graphics.h
  95. 3 2
      Source/Atomic/Graphics/GraphicsDefs.h
  96. 66 1
      Source/Atomic/Graphics/Light.cpp
  97. 30 6
      Source/Atomic/Graphics/Light.h
  98. 135 23
      Source/Atomic/Graphics/Material.cpp
  99. 29 5
      Source/Atomic/Graphics/Material.h
  100. 1 1
      Source/Atomic/Graphics/OcclusionBuffer.cpp

+ 4 - 1
AUTHORS.md

@@ -76,6 +76,7 @@ Urho3D development, contributions and bugfixes by:
 - Josh Engebretson
 - Chris Friesen
 - Alex Fuller
+- Henrik Heino
 - Mika Heinonen
 - Jukka Jylänki
 - Graham King
@@ -84,6 +85,7 @@ Urho3D development, contributions and bugfixes by:
 - Gunnar Kriik
 - Aliaksandr Kryvashein
 - Artem Kulyk
+- Rokas Kupstys
 - Ali Kämäräinen
 - Pete Leigh
 - Frode 'Modanung' Lindeijer
@@ -109,17 +111,18 @@ Urho3D development, contributions and bugfixes by:
 - Yusuf Umar
 - Daniel Wiberg
 - Steven Zhang
-- Rokas Kupstys
 - AGreatFish
 - BlueMagnificent
 - Enhex
 - Firegorilla
+- Gordon-F
 - Lumak
 - Magic.Lixin
 - Mike3D
 - MonkeyFirst
 - Newb I the Newbd
 - OvermindDL1
+- Scellow
 - Skrylar
 - TheComet93
 - Y-way

+ 2 - 2
Resources/CoreData/Shaders/GLSL/BRDF.glsl

@@ -113,8 +113,8 @@
         float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
         float fd90 = energyBias + 2.0 * VdotH * VdotH * roughness;
         float f0 = 1.0;
-        float lightScatter = f0 + (fd90 - f0) * pow(1.0f - NdotL, 5.0f);
-        float viewScatter = f0 + (fd90 - f0) * pow(1.0f - NdotV, 5.0f);
+        float lightScatter = f0 + (fd90 - f0) * pow(1.0 - NdotL, 5.0);
+        float viewScatter = f0 + (fd90 - f0) * pow(1.0 - NdotV, 5.0);
 
         return diffuseColor * lightScatter * viewScatter * energyFactor;
     }

+ 2 - 2
Resources/CoreData/Shaders/GLSL/Lighting.glsl

@@ -86,7 +86,7 @@ vec4 GetShadowPos(int index, vec3 normal, vec4 projWorldPos)
         #ifdef DIRLIGHT
             float cosAngle = clamp(1.0 - dot(normal, cLightDir), 0.0, 1.0);
         #else
-            float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPos - projWorldPos.xyz)), 0.0, 1.0);
+            float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPos.xyz - projWorldPos.xyz)), 0.0, 1.0);
         #endif
         projWorldPos.xyz += cosAngle * normalOffsetScale[index] * normal;
     #endif
@@ -353,7 +353,7 @@ float GetShadowDeferred(vec4 projWorldPos, vec3 normal, float depth)
         return GetDirShadowDeferred(projWorldPos, normal, depth);
     #else
         #ifdef NORMALOFFSET
-            float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPosPS - projWorldPos.xyz)), 0.0, 1.0);
+            float cosAngle = clamp(1.0 - dot(normal, normalize(cLightPosPS.xyz - projWorldPos.xyz)), 0.0, 1.0);
             projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
         #endif
 

+ 2 - 5
Resources/CoreData/Shaders/GLSL/Skydome.glsl

@@ -4,9 +4,6 @@
 
 varying vec2 vTexCoord;
 
-uniform mat4 gl_ModelViewMatrix;
-uniform mat4 gl_ProjectionMatrix;
-
 void VS()
 {
     mat4 modelMatrix = iModelMatrix;
@@ -17,6 +14,6 @@ void VS()
 }
 
 void PS()
-{   
-    gl_FragColor = texture2D(sDiffMap, vTexCoord);       
+{
+    gl_FragColor = texture2D(sDiffMap, vTexCoord);
 }

+ 8 - 1
Resources/CoreData/Shaders/GLSL/Water.glsl

@@ -4,11 +4,18 @@
 #include "ScreenPos.glsl"
 #include "Fog.glsl"
 
+#ifndef GL_ES
 varying vec4 vScreenPos;
 varying vec2 vReflectUV;
 varying vec2 vWaterUV;
-varying vec3 vNormal;
 varying vec4 vEyeVec;
+#else
+varying highp vec4 vScreenPos;
+varying highp vec2 vReflectUV;
+varying highp vec2 vWaterUV;
+varying highp vec4 vEyeVec;
+#endif
+varying vec3 vNormal;
 
 #ifdef COMPILEVS
 uniform vec2 cNoiseSpeed;

+ 3 - 3
Resources/CoreData/Shaders/HLSL/Lighting.hlsl

@@ -85,7 +85,7 @@ void GetShadowPos(float4 projWorldPos, float3 normal, out float4 shadowPos[NUMCA
         #ifdef DIRLIGHT
             float cosAngle = saturate(1.0 - dot(normal, cLightDir));
         #else
-            float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPos - projWorldPos.xyz)));
+            float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPos.xyz - projWorldPos.xyz)));
         #endif
 
         #if defined(DIRLIGHT)
@@ -191,7 +191,7 @@ float Chebyshev(float2 Moments, float depth)
 {  
     //One-tailed inequality valid if depth > Moments.x  
     float p = float(depth <= Moments.x);  
-    //Compute variance.  
+    //Compute variance.
     float Variance = Moments.y - (Moments.x * Moments.x); 
 
     float minVariance = cVSMShadowParams.x;
@@ -351,7 +351,7 @@ float GetShadowDeferred(float4 projWorldPos, float3 normal, float depth)
         return GetDirShadowDeferred(projWorldPos, normal, depth);
     #else
         #ifdef NORMALOFFSET
-            float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPosPS - projWorldPos.xyz)));
+            float cosAngle = saturate(1.0 - dot(normal, normalize(cLightPosPS.xyz - projWorldPos.xyz)));
             projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
         #endif
 

+ 0 - 9
Resources/CoreData/Techniques/DiffAOAlphaMask.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="AO" psdefines="DEFERRED AO" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" />
-    <pass name="litbase" psdefines="AMBIENT" />
-    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" psdefines="DEFERRED" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffAlphaMaskTranslucent.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" vsdefines="TRANSLUCENT" psdefines="DIFFMAP ALPHAMASK TRANSLUCENT" alphamask="true" >
-    <pass name="base" />
-    <pass name="litbase" psdefines="AMBIENT" />
-    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" psdefines="DEFERRED" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffLightMapEnvCube.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" vsdefines="ENVCUBEMAP LIGHTMAP" psdefines="ENVCUBEMAP LIGHTMAP" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="light" vsdefines="LIGHTMAP" psdefines="LIGHTMAP" depthtest="equal" depthwrite="false" blend="subtract" />
-    <pass name="material" vsdefines="ENVCUBEMAP LIGHTMAP" psdefines="MATERIAL ENVCUBEMAP LIGHTMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="ENVCUBEMAP LIGHTMAP" psdefines="DEFERRED ENVCUBEMAP LIGHTMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormal.xml

@@ -5,6 +5,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormalAO.xml

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP AO" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalAOAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalAOAlphaMask.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP AO" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalAlphaMaskTranslucent.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" vsdefines="TRANSLUCENT" psdefines="DIFFMAP ALPHAMASK TRANSLUCENT" alphamask="true">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalAlphaTranslucent.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" vsdefines="TRANSLUCENT" psdefines="DIFFMAP TRANSLUCENT">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormalEmissive.xml

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL EMISSIVEMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP EMISSIVEMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalEmissiveAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormalEnvCube.xml

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="MATERIAL NORMALMAP ENVCUBEMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="DEFERRED NORMALMAP ENVCUBEMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalEnvCubeAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="NORMALMAP ENVCUBEMAP" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalPacked.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedAO.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP PACKEDNORMAL AO" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedAOAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedAOAlphaMask.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP PACKEDNORMAL AO" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalPackedAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalPackedAlphaMaskTranslucent.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" vsdefines="TRANSLUCENT" psdefines="DIFFMAP ALPHAMASK TRANSLUCENT" alphamask="true">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedAlphaTranslucent.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" vsdefines="TRANSLUCENT" psdefines="DIFFMAP TRANSLUCENT">
-    <pass name="alpha" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedEmissive.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" psdefines="EMISSIVEMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" psdefines="MATERIAL EMISSIVEMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL EMISSIVEMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedEmissiveAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedEnvCube.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="NORMALMAP PACKEDNORMAL ENVCUBEMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="MATERIAL NORMALMAP PACKEDNORMAL ENVCUBEMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL ENVCUBEMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedEnvCubeAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="NORMALMAP PACKEDNORMAL ENVCUBEMAP" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalPackedSpec.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedSpecAO.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL SPECMAP AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP PACKEDNORMAL SPECMAP AO" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedSpecAOAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedSpecAOAlphaMask.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL SPECMAP AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP PACKEDNORMAL SPECMAP AO" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedSpecAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalPackedSpecAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalPackedSpecEmissive.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="base" psdefines="EMISSIVEMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL SPECMAP" />
-    <pass name="material" psdefines="MATERIAL SPECMAP EMISSIVEMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL SPECMAP EMISSIVEMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/DiffNormalPackedSpecEmissiveAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
-    <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL SPECMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormalSpec.xml

@@ -5,6 +5,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP SPECMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormalSpecAO.xml

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" vsdefines="AO" psdefines="MATERIAL SPECMAP AO" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP SPECMAP AO" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalSpecAOAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 9
Resources/CoreData/Techniques/DiffNormalSpecAOAlphaMask.xml

@@ -1,9 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" vsdefines="AO" psdefines="AO" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
-    <pass name="material" vsdefines="AO" psdefines="MATERIAL SPECMAP AO" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP SPECMAP AO" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalSpecAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffNormalSpecAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP SPECMAP" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
-    <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP SPECMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 2 - 2
Resources/CoreData/Techniques/DiffNormalSpecEmissive.xml

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP EMISSIVEMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP SPECMAP EMISSIVEMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/DiffNormalSpecEmissiveAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 10
Resources/CoreData/Techniques/DiffSpecAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" />
-    <pass name="litbase" psdefines="AMBIENT SPECMAP" />
-    <pass name="light" psdefines="SPECMAP" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" psdefines="PREPASS SPECMAP" />
-    <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" psdefines="DEFERRED SPECMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 6
Resources/CoreData/Techniques/DiffUnlitAlphaMask.xml

@@ -1,6 +0,0 @@
-<technique vs="Unlit" ps="Unlit" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="material" />
-    <pass name="deferred" psdefines="DEFERRED" />
-</technique>

+ 2 - 2
Resources/CoreData/Techniques/NoTextureNormal.xml

@@ -5,6 +5,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/NoTextureNormalAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid">
     <pass name="alpha"  depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 10
Resources/CoreData/Techniques/NoTextureNormalPacked.xml

@@ -1,10 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid">
-    <pass name="base" />
-    <pass name="litbase" vsdefines="NORMALMAP" psdefines="AMBIENT NORMALMAP PACKEDNORMAL" />
-    <pass name="light" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP PACKEDNORMAL" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP PACKEDNORMAL" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 0 - 5
Resources/CoreData/Techniques/NoTextureNormalPackedAlpha.xml

@@ -1,5 +0,0 @@
-<technique vs="LitSolid" ps="LitSolid">
-    <pass name="alpha"  depthwrite="false" blend="alpha" />
-    <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP PACKEDNORMAL" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
-</technique>

+ 2 - 2
Resources/CoreData/Techniques/PBR/DiffNormalSpecEmissive.xml

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />>
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/PBR/DiffNormalSpecEmissiveAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="PBRLitSolid" ps="PBRLitSolid" psdefines="DIFFMAP SPECMAP EMISSIVEMAP NORMALMAP">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/PBR/PBRDiffNormal.xml

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/PBR/PBRDiffNormalAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="PBRLitSolid" ps="PBRLitSolid" vsdefines="IBL" psdefines="DIFFMAP NORMALMAP PBR IBL">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/PBR/PBRDiffNormalEmissive.xml

@@ -2,6 +2,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add" />
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/PBR/PBRDiffNormalEmissiveAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="PBRLitSolid" ps="PBRLitSolid"  vsdefines="IBL" psdefines="DIFFMAP NORMALMAP EMISSIVEMAP PBR IBL">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpec.xml

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add"/>
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 2 - 2
Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissive.xml

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add"/>
-    <pass name="depth" vs="Depth" ps="Depth" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="depth" vs="Depth" ps="Depth" psexcludes="PACKEDNORMAL" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 1 - 1
Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissiveAlpha.xml

@@ -1,5 +1,5 @@
 <technique vs="PBRLitSolid" ps="PBRLitSolid" vsdefines="IBL" psdefines="DIFFMAP NORMALMAP EMISSIVEMAP PBR IBL METALLIC ROUGHNESS">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>

+ 0 - 10
Resources/CoreData/Techniques/VegetationDiffAlphaMask.xml

@@ -1,10 +0,0 @@
-<technique vs="Vegetation" ps="LitSolid" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" />
-    <pass name="litbase" psdefines="AMBIENT" />
-    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
-    <pass name="deferred" psdefines="DEFERRED" />
-    <pass name="depth" vs="VegetationDepth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="VegetationShadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 0 - 8
Resources/CoreData/Techniques/VegetationDiffUnlitAlphaMask.xml

@@ -1,8 +0,0 @@
-<technique vs="Vegetation" ps="Unlit" psdefines="DIFFMAP ALPHAMASK" alphamask="true" >
-    <pass name="base" />
-    <pass name="prepass" psdefines="PREPASS" />
-    <pass name="material" />
-    <pass name="deferred" psdefines="DEFERRED" />
-    <pass name="depth" vs="VegetationDepth" ps="Depth" psdefines="ALPHAMASK" />
-    <pass name="shadow" vs="VegetationShadow" ps="Shadow" psdefines="ALPHAMASK" />
-</technique>

+ 12 - 6
Source/Atomic/Atomic2D/Constraint2D.cpp

@@ -48,12 +48,6 @@ Constraint2D::Constraint2D(Context* context) :
 
 Constraint2D::~Constraint2D()
 {
-    if (ownerBody_)
-        ownerBody_->RemoveConstraint2D(this);
-
-    if (otherBody_)
-        otherBody_->RemoveConstraint2D(this);
-
     ReleaseJoint();
 }
 
@@ -80,6 +74,12 @@ void Constraint2D::CreateJoint()
     {
         joint_ = physicsWorld_->GetWorld()->CreateJoint(jointDef);
         joint_->SetUserData(this);
+
+        if (ownerBody_)
+            ownerBody_->AddConstraint2D(this);
+
+        if (otherBody_)
+            otherBody_->AddConstraint2D(this);
     }
 }
 
@@ -88,6 +88,12 @@ void Constraint2D::ReleaseJoint()
     if (!joint_)
         return;
 
+    if (ownerBody_)
+        ownerBody_->RemoveConstraint2D(this);
+
+    if (otherBody_)
+        otherBody_->RemoveConstraint2D(this);
+
     if (physicsWorld_)
         physicsWorld_->GetWorld()->DestroyJoint(joint_);
 

+ 2 - 2
Source/Atomic/Atomic2D/Constraint2D.h

@@ -47,9 +47,9 @@ public:
 
     /// Handle enabled/disabled state change.
     virtual void OnSetEnabled();
-    /// Create Joint.
+    /// Create joint.
     void CreateJoint();
-    /// Release Joint.
+    /// Release joint.
     void ReleaseJoint();
 
     /// Set other rigid body.

+ 21 - 29
Source/Atomic/Atomic2D/PhysicsEvents2D.h

@@ -24,40 +24,14 @@
 
 #include "../Core/Object.h"
 
-// ATOMIC BEGIN
-
-//  Discrete Physics2D Events
-
 // For prestep / poststep events, which are the same for 2D and 3D physics. The events themselves don't depend
 // on whether 3D physics support or Bullet has been compiled in.
-// #include "../Physics/PhysicsEvents.h"
-
-// ATOMIC END
+#include "../Physics/PhysicsEvents.h"
 
 namespace Atomic
 {
 
-
-// ATOMIC BEGIN
-
-/// Physics world is about to be stepped.
-ATOMIC_EVENT(E_PHYSICSPRESTEP2D, PhysicsPreStep2D)
-{
-    ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
-    ATOMIC_PARAM(P_TIMESTEP, TimeStep);            // float
-}
-
-/// Physics world has been stepped.
-ATOMIC_EVENT(E_PHYSICSPOSTSTEP2D, PhysicsPostStep2D)
-{
-    ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
-    ATOMIC_PARAM(P_TIMESTEP, TimeStep);            // float
-}
-
-// ATOMIC END
-
-
-/// Physics begin contact.
+/// Physics begin contact. Global event sent by PhysicsWorld2D.
 ATOMIC_EVENT(E_PHYSICSBEGINCONTACT2D, PhysicsBeginContact2D)
 {
     ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
@@ -68,7 +42,7 @@ ATOMIC_EVENT(E_PHYSICSBEGINCONTACT2D, PhysicsBeginContact2D)
     ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
 }
 
-/// Physics end contact.
+/// Physics end contact. Global event sent by PhysicsWorld2D.
 ATOMIC_EVENT(E_PHYSICSENDCONTACT2D, PhysicsEndContact2D)
 {
     ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
@@ -79,4 +53,22 @@ ATOMIC_EVENT(E_PHYSICSENDCONTACT2D, PhysicsEndContact2D)
     ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
 }
 
+/// Node begin contact. Sent by scene nodes participating in a collision.
+ATOMIC_EVENT(E_NODEBEGINCONTACT2D, NodeBeginContact2D)
+{
+    ATOMIC_PARAM(P_BODY, Body);                    // RigidBody2D pointer
+    ATOMIC_PARAM(P_OTHERNODE, OtherNode);          // Node pointer
+    ATOMIC_PARAM(P_OTHERBODY, OtherBody);          // RigidBody2D pointer
+    ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+}
+
+/// Node end contact. Sent by scene nodes participating in a collision.
+ATOMIC_EVENT(E_NODEENDCONTACT2D, NodeEndContact2D)
+{
+    ATOMIC_PARAM(P_BODY, Body);                    // RigidBody2D pointer
+    ATOMIC_PARAM(P_OTHERNODE, OtherNode);          // Node pointer
+    ATOMIC_PARAM(P_OTHERBODY, OtherBody);          // RigidBody2D pointer
+    ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
+}
+
 }

+ 51 - 11
Source/Atomic/Atomic2D/PhysicsWorld2D.cpp

@@ -95,7 +95,12 @@ void PhysicsWorld2D::RegisterObject(Context* context)
     ATOMIC_ACCESSOR_ATTRIBUTE("Draw CenterOfMass", GetDrawCenterOfMass, SetDrawCenterOfMass, bool, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Allow Sleeping", GetAllowSleeping, SetAllowSleeping, bool, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Warm Starting", GetWarmStarting, SetWarmStarting, bool, false, AM_DEFAULT);
+
+    // ATOMIC BEGIN
+    // default false
     ATOMIC_ACCESSOR_ATTRIBUTE("Continuous Physics", GetContinuousPhysics, SetContinuousPhysics, bool, false, AM_DEFAULT);
+    // ATOMIC END
+
     ATOMIC_ACCESSOR_ATTRIBUTE("Sub Stepping", GetSubStepping, SetSubStepping, bool, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Gravity", GetGravity, SetGravity, Vector2, DEFAULT_GRAVITY, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Auto Clear Forces", GetAutoClearForces, SetAutoClearForces, bool, false, AM_DEFAULT);
@@ -232,17 +237,12 @@ void PhysicsWorld2D::Update(float timeStep)
 {
     ATOMIC_PROFILE(UpdatePhysics2D);
 
-// ATOMIC BEGIN
-
-    using namespace PhysicsPreStep2D;
-
+    using namespace PhysicsPreStep;
 
     VariantMap& eventData = GetEventDataMap();
     eventData[P_WORLD] = this;
     eventData[P_TIMESTEP] = timeStep;
-    SendEvent(E_PHYSICSPRESTEP2D, eventData);
-
-// ATOMIC END
+    SendEvent(E_PHYSICSPRESTEP, eventData);
 
     physicsStepping_ = true;
     world_->Step(timeStep, velocityIterations_, positionIterations_);
@@ -285,10 +285,8 @@ void PhysicsWorld2D::Update(float timeStep)
     SendBeginContactEvents();
     SendEndContactEvents();
 
-// ATOMIC BEGIN
-    using namespace PhysicsPostStep2D;
-    SendEvent(E_PHYSICSPOSTSTEP2D, eventData);
-// ATOMIC END
+    using namespace PhysicsPostStep;
+    SendEvent(E_PHYSICSPOSTSTEP, eventData);
 }
 
 void PhysicsWorld2D::DrawDebugGeometry()
@@ -686,6 +684,7 @@ void PhysicsWorld2D::SendBeginContactEvents()
 
     using namespace PhysicsBeginContact2D;
     VariantMap& eventData = GetEventDataMap();
+    VariantMap nodeEventData;
     eventData[P_WORLD] = this;
 
     for (unsigned i = 0; i < beginContactInfos_.Size(); ++i)
@@ -698,6 +697,26 @@ void PhysicsWorld2D::SendBeginContactEvents()
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
 
         SendEvent(E_PHYSICSBEGINCONTACT2D, eventData);
+
+        nodeEventData[NodeBeginContact2D::P_CONTACT] = (void*)contactInfo.contact_;
+
+        if (contactInfo.nodeA_)
+        {
+            nodeEventData[NodeBeginContact2D::P_BODY] = contactInfo.bodyA_.Get();
+            nodeEventData[NodeBeginContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
+            nodeEventData[NodeBeginContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
+
+            contactInfo.nodeA_->SendEvent(E_NODEBEGINCONTACT2D, nodeEventData);
+        }
+
+        if (contactInfo.nodeB_)
+        {
+            nodeEventData[NodeBeginContact2D::P_BODY] = contactInfo.bodyB_.Get();
+            nodeEventData[NodeBeginContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
+            nodeEventData[NodeBeginContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
+
+            contactInfo.nodeB_->SendEvent(E_NODEBEGINCONTACT2D, nodeEventData);
+        }
     }
 
     beginContactInfos_.Clear();
@@ -710,6 +729,7 @@ void PhysicsWorld2D::SendEndContactEvents()
 
     using namespace PhysicsEndContact2D;
     VariantMap& eventData = GetEventDataMap();
+    VariantMap nodeEventData;
     eventData[P_WORLD] = this;
 
     for (unsigned i = 0; i < endContactInfos_.Size(); ++i)
@@ -722,6 +742,26 @@ void PhysicsWorld2D::SendEndContactEvents()
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
 
         SendEvent(E_PHYSICSENDCONTACT2D, eventData);
+
+        nodeEventData[NodeEndContact2D::P_CONTACT] = (void*)contactInfo.contact_;
+
+        if (contactInfo.nodeA_)
+        {
+            nodeEventData[NodeEndContact2D::P_BODY] = contactInfo.bodyA_.Get();
+            nodeEventData[NodeEndContact2D::P_OTHERNODE] = contactInfo.nodeB_.Get();
+            nodeEventData[NodeEndContact2D::P_OTHERBODY] = contactInfo.bodyB_.Get();
+
+            contactInfo.nodeA_->SendEvent(E_NODEENDCONTACT2D, nodeEventData);
+        }
+
+        if (contactInfo.nodeB_)
+        {
+            nodeEventData[NodeEndContact2D::P_BODY] = contactInfo.bodyB_.Get();
+            nodeEventData[NodeEndContact2D::P_OTHERNODE] = contactInfo.nodeA_.Get();
+            nodeEventData[NodeEndContact2D::P_OTHERBODY] = contactInfo.bodyA_.Get();
+
+            contactInfo.nodeB_->SendEvent(E_NODEENDCONTACT2D, nodeEventData);
+        }
     }
 
     endContactInfos_.Clear();

+ 5 - 3
Source/Atomic/Atomic2D/RigidBody2D.cpp

@@ -402,10 +402,12 @@ void RigidBody2D::ReleaseBody()
     if (!physicsWorld_ || !physicsWorld_->GetWorld())
         return;
 
-    for (unsigned i = 0; i < constraints_.Size(); ++i)
+    // Make a copy for iteration
+    Vector<WeakPtr<Constraint2D> > constraints = constraints_;
+    for (unsigned i = 0; i < constraints.Size(); ++i)
     {
-        if (constraints_[i])
-            constraints_[i]->ReleaseJoint();
+        if (constraints[i])
+            constraints[i]->ReleaseJoint();
     }
 
     for (unsigned i = 0; i < collisionShapes_.Size(); ++i)

+ 4 - 0
Source/Atomic/Atomic2D/TileMapLayer2D.h

@@ -25,6 +25,10 @@
 #include "../Scene/Component.h"
 #include "../Atomic2D/TileMapDefs2D.h"
 
+#ifdef GetObject
+#undef GetObject
+#endif
+
 namespace Atomic
 {
 

+ 7 - 26
Source/Atomic/Audio/SoundSource.cpp

@@ -94,12 +94,11 @@ namespace Atomic
 
 #define GET_IP_SAMPLE_RIGHT() (((((int)pos[3] - (int)pos[1]) * fractPos) / 65536) + (int)pos[1])
 
-static const float AUTOREMOVE_DELAY = 0.25f;
-
 static const int STREAM_SAFETY_SAMPLES = 4;
 
 extern const char* AUDIO_CATEGORY;
 
+extern const char* autoRemoveModeNames[];
 
 SoundSource::SoundSource(Context* context) :
     Component(context),
@@ -108,9 +107,8 @@ SoundSource::SoundSource(Context* context) :
     gain_(1.0f),
     attenuation_(1.0f),
     panning_(0.0f),
-    autoRemoveTimer_(0.0f),
-    autoRemove_(false),
     sendFinishedEvent_(false),
+    autoRemove_(REMOVE_DISABLED),
     position_(0),
     fractPosition_(0),
     timePosition_(0.0f),
@@ -142,7 +140,7 @@ void SoundSource::RegisterObject(Context* context)
     ATOMIC_ATTRIBUTE("Attenuation", float, attenuation_, 1.0f, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Panning", float, panning_, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Is Playing", IsPlaying, SetPlayingAttr, bool, false, AM_DEFAULT);
-    ATOMIC_ATTRIBUTE("Autoremove on Stop", bool, autoRemove_, false, AM_FILE);
+    ATOMIC_ENUM_ATTRIBUTE("Autoremove Mode", autoRemove_, autoRemoveModeNames, REMOVE_DISABLED, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Play Position", GetPositionAttr, SetPositionAttr, int, 0, AM_FILE);
 }
 
@@ -283,12 +281,10 @@ void SoundSource::SetPanning(float panning)
     MarkNetworkUpdate();
 }
 
-void SoundSource::SetAutoRemove(bool enable)
+void SoundSource::SetAutoRemoveMode(AutoRemoveMode mode)
 {
-    if (enable == true)
-        ATOMIC_LOGWARNING("SoundSource::SetAutoRemove is deprecated. Consider using the SoundFinished event instead");
-
-    autoRemove_ = enable;
+    autoRemove_ = mode;
+    MarkNetworkUpdate();
 }
 
 bool SoundSource::IsPlaying() const
@@ -338,23 +334,8 @@ void SoundSource::Update(float timeStep)
 
         if (self.Expired())
             return;
-    }
 
-    // Check for autoremove
-    if (autoRemove_)
-    {
-        if (!playing)
-        {
-            autoRemoveTimer_ += timeStep;
-            if (autoRemoveTimer_ > AUTOREMOVE_DELAY)
-            {
-                Remove();
-                // Note: this object is now deleted, so only returning immediately is safe
-                return;
-            }
-        }
-        else
-            autoRemoveTimer_ = 0.0f;
+        DoAutoRemove(autoRemove_);
     }
 }
 

+ 6 - 8
Source/Atomic/Audio/SoundSource.h

@@ -70,8 +70,8 @@ public:
     void SetAttenuation(float attenuation);
     /// Set stereo panning. -1.0 is full left and 1.0 is full right.
     void SetPanning(float panning);
-    /// \deprecated Set whether sound source will be automatically removed from the scene node when playback stops. Note: this is deprecated, consider subscribing to the SoundFinished event instead.
-    ATOMIC_DEPRECATED void SetAutoRemove(bool enable);
+    //// Set to remove either the sound source component or its owner node from the scene automatically on sound playback completion. Disabled by default.
+    void SetAutoRemoveMode(AutoRemoveMode mode);
     /// Set new playback position.
     void SetPlayPosition(signed char* pos);
 
@@ -99,8 +99,8 @@ public:
     /// Return stereo panning.
     float GetPanning() const { return panning_; }
 
-    /// \deprecated Return autoremove mode.
-    ATOMIC_DEPRECATED bool GetAutoRemove() const { return autoRemove_; }
+    /// Return automatic removal mode on sound playback completion.
+    AutoRemoveMode GetAutoRemoveMode() const { return autoRemove_; }
 
     /// Return whether is playing.
     bool IsPlaying() const;
@@ -138,14 +138,12 @@ protected:
     float attenuation_;
     /// Stereo panning.
     float panning_;
-    /// Autoremove timer.
-    float autoRemoveTimer_;
     /// Effective master gain.
     float masterGain_;
-    /// Autoremove flag.
-    bool autoRemove_;
     /// Whether finished event should be sent on playback stop.
     bool sendFinishedEvent_;
+    /// Automatic removal mode.
+    AutoRemoveMode autoRemove_;
 
 private:
     /// Play a sound without locking the audio mutex. Called internally.

+ 6 - 2
Source/Atomic/Container/HashMap.h

@@ -262,8 +262,12 @@ public:
     /// Assign a hash map.
     HashMap& operator =(const HashMap<T, U>& rhs)
     {
-        Clear();
-        Insert(rhs);
+        // In case of self-assignment do nothing
+        if (&rhs != this)
+        {
+            Clear();
+            Insert(rhs);
+        }
         return *this;
     }
 

+ 6 - 2
Source/Atomic/Container/HashSet.h

@@ -217,8 +217,12 @@ public:
     /// Assign a hash set.
     HashSet& operator =(const HashSet<T>& rhs)
     {
-        Clear();
-        Insert(rhs);
+        // In case of self-assignment do nothing
+        if (&rhs != this)
+        {
+            Clear();
+            Insert(rhs);
+        }
         return *this;
     }
 

+ 6 - 3
Source/Atomic/Container/List.h

@@ -209,9 +209,12 @@ public:
     /// Assign from another list.
     List& operator =(const List<T>& rhs)
     {
-        // Clear, then insert the nodes of the other list
-        Clear();
-        Insert(End(), rhs);
+        // Clear, then insert the nodes of the other list. In case of self-assignment do nothing
+        if (&rhs != this)
+        {
+            Clear();
+            Insert(End(), rhs);
+        }
         return *this;
     }
 

+ 135 - 142
Source/Atomic/Container/Vector.h

@@ -55,13 +55,21 @@ public:
     /// Construct with initial size.
     explicit Vector(unsigned size)
     {
-        Resize(size, 0);
+        Resize(size);
+    }
+
+    /// Construct with initial size and default value.
+    Vector(unsigned size, const T& value)
+    {
+        Resize(size);
+        for (unsigned i = 0; i < size; ++i)
+            At(i) = value;
     }
 
     /// Construct with initial data.
     Vector(const T* data, unsigned size)
     {
-        Resize(size, data);
+        InsertElements(0, data, data + size);
     }
 
     /// Construct from another vector.
@@ -82,15 +90,19 @@ public:
     /// Destruct.
     ~Vector()
     {
-        Clear();
+        DestructElements(Buffer(), size_);
         delete[] buffer_;
     }
 
     /// Assign from another vector.
     Vector<T>& operator =(const Vector<T>& rhs)
     {
-        Clear();
-        Resize(rhs.size_, rhs.Buffer());
+        // In case of self-assignment do nothing
+        if (&rhs != this)
+        {
+            Clear();
+            InsertElements(0, rhs.Begin(), rhs.End());
+        }
         return *this;
     }
 
@@ -188,105 +200,68 @@ public:
 
     /// Add an element at the end.
 #ifndef COVERITY_SCAN_MODEL
-    void Push(const T& value) { Resize(size_ + 1, &value); }
+    void Push(const T& value)
+    {
+        InsertElements(size_, &value, &value + 1);
+    }
 #else
     // FIXME: Attempt had been made to use this model in the Coverity-Scan model file without any success
     // Probably because the model had generated a different mangled name than the one used by static analyzer
     void Push(const T& value)
     {
         T array[] = {value};
-        Resize(size_ + 1, array);
+        InsertElements(size_, array, array + 1);
     }
 #endif
 
     /// Add another vector at the end.
-    void Push(const Vector<T>& vector) { Resize(size_ + vector.size_, vector.Buffer()); }
+    void Push(const Vector<T>& vector) { InsertElements(size_, vector.Begin(), vector.End()); }
 
     /// Remove the last element.
     void Pop()
     {
         if (size_)
-            Resize(size_ - 1, 0);
+            Resize(size_ - 1);
     }
 
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-        Resize(size_ + 1, 0);
-        MoveRange(pos + 1, pos, oldSize - pos);
-        Buffer()[pos] = value;
+        InsertElements(pos, &value, &value + 1);
     }
 
     /// Insert another vector at position.
     void Insert(unsigned pos, const Vector<T>& vector)
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-        Resize(size_ + vector.size_, 0);
-        MoveRange(pos + vector.size_, pos, oldSize - pos);
-        CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
+        InsertElements(pos, vector.Begin(), vector.End());
     }
 
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, value);
-
-        return Begin() + pos;
+        return InsertElements(pos, &value, &value + 1);
     }
 
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const Vector<T>& vector)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, vector);
-
-        return Begin() + pos;
+        return InsertElements(pos, vector.Begin(), vector.End());
     }
 
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length, 0);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (ConstIterator it = start; it != end; ++it)
-            *destPtr++ = *it;
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
 
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length, 0);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (const T* i = start; i != end; ++i)
-            *destPtr++ = *i;
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
 
     /// Erase a range of elements.
@@ -297,7 +272,7 @@ public:
             return;
 
         MoveRange(pos, pos + length, size_ - pos - length);
-        Resize(size_ - length, 0);
+        Resize(size_ - length);
     }
 
     /// Erase a range of elements by swapping elements from the end of the array.
@@ -320,7 +295,7 @@ public:
             // Swap elements from the end of the array into the empty space
             CopyElements(Buffer() + pos, Buffer() + newSize, length);
         }
-        Resize(newSize, 0);
+        Resize(newSize);
     }
 
     /// Erase an element by iterator. Return iterator to the next element.
@@ -376,7 +351,7 @@ public:
     void Clear() { Resize(0); }
 
     /// Resize the vector.
-    void Resize(unsigned newSize) { Resize(newSize, 0); }
+    void Resize(unsigned newSize) { Vector<T> tempBuffer; Resize(newSize, 0, tempBuffer); }
 
     /// Set new capacity.
     void Reserve(unsigned newCapacity)
@@ -480,8 +455,8 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 private:
-    /// Resize the vector and create/remove new elements as necessary.
-    void Resize(unsigned newSize, const T* src)
+    /// Resize the vector and create/remove new elements as necessary. Current buffer will be stored in tempBuffer in case of reallocation.
+    void Resize(unsigned newSize, const T* src, Vector<T>& tempBuffer)
     {
         // If size shrinks, destruct the removed elements
         if (newSize < size_)
@@ -491,6 +466,10 @@ private:
             // Allocate new buffer if necessary and copy the current elements
             if (newSize > capacity_)
             {
+                Swap(tempBuffer);
+                size_ = tempBuffer.size_;
+                capacity_ = tempBuffer.capacity_;
+
                 if (!capacity_)
                     capacity_ = newSize;
                 else
@@ -499,14 +478,11 @@ private:
                         capacity_ += (capacity_ + 1) >> 1;
                 }
 
-                unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
-                if (buffer_)
+                buffer_ = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
+                if (tempBuffer.Buffer())
                 {
-                    ConstructElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
-                    DestructElements(Buffer(), size_);
-                    delete[] buffer_;
+                    ConstructElements(Buffer(), tempBuffer.Buffer(), size_);
                 }
-                buffer_ = newBuffer;
             }
 
             // Initialize the new elements
@@ -516,6 +492,26 @@ private:
         size_ = newSize;
     }
 
+    /// Insert elements.
+    template <typename RandomIteratorT>
+    Iterator InsertElements(unsigned pos, RandomIteratorT start, RandomIteratorT end)
+    {
+        assert(start <= end);
+
+        if (pos > size_)
+            pos = size_;
+        unsigned length = (unsigned)(end - start);
+        Vector<T> tempBuffer;
+        Resize(size_ + length, 0, tempBuffer);
+        MoveRange(pos + length, pos, size_ - pos - length);
+
+        T* destPtr = Buffer() + pos;
+        for (RandomIteratorT it = start; it != end; ++it)
+            *destPtr++ = *it;
+
+        return Begin() + pos;
+    }
+
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {
@@ -584,11 +580,18 @@ public:
         Resize(size);
     }
 
+    /// Construct with initial size and default value.
+    PODVector(unsigned size, const T& value)
+    {
+        Resize(size);
+        for (unsigned i = 0; i < size; ++i)
+            At(i) = value;
+    }
+
     /// Construct with initial data.
     PODVector(const T* data, unsigned size)
     {
-        Resize(size);
-        CopyElements(Buffer(), data, size);
+        InsertElements(0, data, data + size);
     }
 
     /// Construct from another vector.
@@ -615,8 +618,12 @@ public:
     /// Assign from another vector.
     PODVector<T>& operator =(const PODVector<T>& rhs)
     {
-        Resize(rhs.size_);
-        CopyElements(Buffer(), rhs.Buffer(), rhs.size_);
+        // In case of self-assignment do nothing
+        if (&rhs != this)
+        {
+            Clear();
+            InsertElements(0, rhs.Begin(), rhs.End());
+        }
         return *this;
     }
 
@@ -715,19 +722,13 @@ public:
     /// Add an element at the end.
     void Push(const T& value)
     {
-        if (size_ < capacity_)
-            ++size_;
-        else
-            Resize(size_ + 1);
-        Back() = value;
+        InsertElements(size_, &value, &value + 1);
     }
 
     /// Add another vector at the end.
     void Push(const PODVector<T>& vector)
     {
-        unsigned oldSize = size_;
-        Resize(size_ + vector.size_);
-        CopyElements(Buffer() + oldSize, vector.Buffer(), vector.size_);
+        InsertElements(size_, vector.Begin(), vector.End());
     }
 
     /// Remove the last element.
@@ -740,78 +741,41 @@ public:
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-        Resize(size_ + 1);
-        MoveRange(pos + 1, pos, oldSize - pos);
-        Buffer()[pos] = value;
+        InsertElements(pos, &value, &value + 1);
     }
 
     /// Insert another vector at position.
     void Insert(unsigned pos, const PODVector<T>& vector)
     {
-        if (pos > size_)
-            pos = size_;
-
-        unsigned oldSize = size_;
-        Resize(size_ + vector.size_);
-        MoveRange(pos + vector.size_, pos, oldSize - pos);
-        CopyElements(Buffer() + pos, vector.Buffer(), vector.size_);
+        InsertElements(pos, vector.Begin(), vector.End());
     }
 
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, value);
-
-        return Begin() + pos;
+        return InsertElements(pos, &value, &value + 1);
     }
 
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        Insert(pos, vector);
-
-        return Begin() + pos;
+        return InsertElements(pos, vector.Begin(), vector.End());
     }
 
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length);
-        MoveRange(pos + length, pos, size_ - pos - length);
-        CopyElements(Buffer() + pos, &(*start), length);
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
 
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
         unsigned pos = (unsigned)(dest - Begin());
-        if (pos > size_)
-            pos = size_;
-        unsigned length = (unsigned)(end - start);
-        Resize(size_ + length);
-        MoveRange(pos + length, pos, size_ - pos - length);
-
-        T* destPtr = Buffer() + pos;
-        for (const T* i = start; i != end; ++i)
-            *destPtr++ = *i;
-
-        return Begin() + pos;
+        return InsertElements(pos, start, end);
     }
 
     /// Erase a range of elements.
@@ -903,27 +867,8 @@ public:
     /// Resize the vector.
     void Resize(unsigned newSize)
     {
-        if (newSize > capacity_)
-        {
-            if (!capacity_)
-                capacity_ = newSize;
-            else
-            {
-                while (capacity_ < newSize)
-                    capacity_ += (capacity_ + 1) >> 1;
-            }
-
-            unsigned char* newBuffer = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
-            // Move the data into the new buffer and delete the old
-            if (buffer_)
-            {
-                CopyElements(reinterpret_cast<T*>(newBuffer), Buffer(), size_);
-                delete[] buffer_;
-            }
-            buffer_ = newBuffer;
-        }
-
-        size_ = newSize;
+        PODVector<T> tempBuffer;
+        Resize(newSize, tempBuffer);
     }
 
     /// Set new capacity.
@@ -1019,6 +964,54 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 private:
+    /// Resize the vector. Current buffer will be stored in tempBuffer in case of reallocation.
+    void Resize(unsigned newSize, PODVector<T>& tempBuffer)
+    {
+        if (newSize > capacity_)
+        {
+            Swap(tempBuffer);
+            size_ = tempBuffer.size_;
+            capacity_ = tempBuffer.capacity_;
+
+            if (!capacity_)
+                capacity_ = newSize;
+            else
+            {
+                while (capacity_ < newSize)
+                    capacity_ += (capacity_ + 1) >> 1;
+            }
+
+            buffer_ = AllocateBuffer((unsigned)(capacity_ * sizeof(T)));
+            // Move the data into the new buffer
+            if (tempBuffer.Buffer())
+            {
+                CopyElements(Buffer(), tempBuffer.Buffer(), size_);
+            }
+        }
+
+        size_ = newSize;
+    }
+
+    /// Insert elements.
+    template <typename RandomIteratorT>
+    Iterator InsertElements(unsigned pos, RandomIteratorT start, RandomIteratorT end)
+    {
+        assert(start <= end);
+
+        if (pos > size_)
+            pos = size_;
+        unsigned length = (unsigned)(end - start);
+        PODVector<T> tempBuffer;
+        Resize(size_ + length, tempBuffer);
+        MoveRange(pos + length, pos, size_ - pos - length);
+
+        T* destPtr = Buffer() + pos;
+        for (RandomIteratorT i = start; i != end; ++i)
+            *destPtr++ = *i;
+
+        return Begin() + pos;
+    }
+
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {

+ 2 - 2
Source/Atomic/Core/Context.cpp

@@ -286,7 +286,7 @@ void Context::RemoveEventReceiver(Object* receiver, Object* sender, StringHash e
 
 void Context::BeginSendEvent(Object* sender, StringHash eventType)
 {
-#ifdef URHO3D_PROFILING
+#ifdef ATOMIC_PROFILING
     if (EventProfiler::IsActive())
     {
         EventProfiler* eventProfiler = GetSubsystem<EventProfiler>();
@@ -302,7 +302,7 @@ void Context::EndSendEvent()
 {
     eventSenders_.Pop();
 
-#ifdef URHO3D_PROFILING
+#ifdef ATOMIC_PROFILING
     if (EventProfiler::IsActive())
     {
         EventProfiler* eventProfiler = GetSubsystem<EventProfiler>();

+ 6 - 8
Source/Atomic/Graphics/AnimatedModel.cpp

@@ -111,14 +111,6 @@ void AnimatedModel::RegisterObject(Context* context)
         Variant::emptyVariantVector, AM_FILE);
     ATOMIC_ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
         AM_DEFAULT | AM_NOEDIT);
-
-    // ATOMIC BEGIN
-
-    ATOMIC_ACCESSOR_ATTRIBUTE("Geometry Enabled", GetGeometryEnabledAttr, SetGeometryEnabledAttr, VariantVector,
-        Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
-
-    // ATOMIC END
-
 }
 
 bool AnimatedModel::Load(Deserializer& source, bool setInstanceDefault)
@@ -396,6 +388,12 @@ void AnimatedModel::SetModel(Model* model, bool createBones)
     if (model == model_)
         return;
 
+    if (!node_)
+    {
+        ATOMIC_LOGERROR("Can not set model while model component is not attached to a scene node");
+        return;
+    }
+
     // Unsubscribe from the reload event of previous model (if any), then subscribe to the new
     if (model_)
         UnsubscribeFromEvent(model_, E_RELOADFINISHED);

+ 6 - 1
Source/Atomic/Graphics/AnimationController.cpp

@@ -28,6 +28,7 @@
 #include "../Graphics/Animation.h"
 #include "../Graphics/AnimationController.h"
 #include "../Graphics/AnimationState.h"
+#include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../IO/MemoryBuffer.h"
 #include "../Resource/ResourceCache.h"
@@ -412,6 +413,10 @@ bool AnimationController::SetWeight(const String& name, float weight)
     animations_[index].setWeight_ = (unsigned char)(weight * 255.0f);
     animations_[index].setWeightTtl_ = COMMAND_STAY_TIME;
     ++animations_[index].setWeightRev_;
+    // Cancel any ongoing weight fade
+    animations_[index].targetWeight_ = weight;
+    animations_[index].fadeTime_ = 0.0f;
+
     MarkNetworkUpdate();
     return true;
 }
@@ -912,7 +917,7 @@ void AnimationController::RemoveAnimationState(AnimationState* state)
 
 void AnimationController::FindAnimation(const String& name, unsigned& index, AnimationState*& state) const
 {
-    StringHash nameHash(name);
+    StringHash nameHash(GetInternalPath(name));
 
 // ATOMIC BEGIN
 

+ 4 - 6
Source/Atomic/Graphics/Batch.cpp

@@ -86,7 +86,7 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
     const IntRect& viewport = queue->shadowSplits_[split].shadowViewport_;
 
     Matrix3x4 shadowView(shadowCamera->GetView());
-    Matrix4 shadowProj(shadowCamera->GetProjection());
+    Matrix4 shadowProj(shadowCamera->GetGPUProjection());
     Matrix4 texAdjust(Matrix4::IDENTITY);
 
     Texture2D* shadowMap = queue->shadowMap_;
@@ -163,11 +163,9 @@ void Batch::CalculateSortKey()
 {
     unsigned shaderID = (unsigned)(
         ((*((unsigned*)&vertexShader_) / sizeof(ShaderVariation)) + (*((unsigned*)&pixelShader_) / sizeof(ShaderVariation))) &
-        0x3fff);
+        0x7fff);
     if (!isBase_)
         shaderID |= 0x8000;
-    if (pass_ && pass_->GetAlphaMask())
-        shaderID |= 0x4000;
 
     unsigned lightQueueID = (unsigned)((*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0xffff);
     unsigned materialID = (unsigned)((*((unsigned*)&material_) / sizeof(Material)) & 0xffff);
@@ -203,7 +201,7 @@ void Batch::Prepare(View* view, Camera* camera, bool setModelTransform, bool all
             else if (blend == BLEND_ADDALPHA)
                 blend = BLEND_SUBTRACTALPHA;
         }
-        graphics->SetBlendMode(blend);
+        graphics->SetBlendMode(blend, pass_->GetAlphaToCoverage() || material_->GetAlphaToCoverage());
 
         bool isShadowPass = pass_->GetIndex() == Technique::shadowPassIndex;
         CullMode effectiveCullMode = pass_->GetCullMode();
@@ -800,7 +798,7 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
             shaderID = j->second_;
         else
         {
-            shaderID = shaderRemapping_[shaderID] = freeShaderID | (shaderID & 0xc0000000);
+            shaderID = shaderRemapping_[shaderID] = freeShaderID | (shaderID & 0x80000000);
             ++freeShaderID;
         }
 

+ 12 - 3
Source/Atomic/Graphics/BillboardSet.cpp

@@ -52,6 +52,7 @@ const char* faceCameraModeNames[] =
     "Rotate Y",
     "LookAt XYZ",
     "LookAt Y",
+    "LookAt Mixed",
     "Direction",
     0
 };
@@ -80,6 +81,7 @@ BillboardSet::BillboardSet(Context* context) :
     sorted_(false),
     fixedScreenSize_(false),
     faceCameraMode_(FC_ROTATE_XYZ),
+    minAngle_(0.0f),
     geometry_(new Geometry(context)),
     vertexBuffer_(new VertexBuffer(context_)),
     indexBuffer_(new IndexBuffer(context_)),
@@ -119,6 +121,7 @@ void BillboardSet::RegisterObject(Context* context)
     ATOMIC_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Cast Shadows", bool, castShadows_, false, AM_DEFAULT);
     ATOMIC_ENUM_ACCESSOR_ATTRIBUTE("Face Camera Mode", GetFaceCameraMode, SetFaceCameraMode, FaceCameraMode, faceCameraModeNames, FC_ROTATE_XYZ, AM_DEFAULT);
+    ATOMIC_ACCESSOR_ATTRIBUTE("Min Angle", GetMinAngle, SetMinAngle, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
@@ -216,7 +219,7 @@ void BillboardSet::UpdateBatches(const FrameInfo& frame)
     transforms_[0] = relative_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
     // Billboard rotation
     transforms_[1] = Matrix3x4(Vector3::ZERO, faceCameraMode_ != FC_NONE ? frame.camera_->GetFaceCameraRotation(
-        node_->GetWorldPosition(), node_->GetWorldRotation(), faceCameraMode_) : node_->GetWorldRotation(), Vector3::ONE);
+        node_->GetWorldPosition(), node_->GetWorldRotation(), faceCameraMode_, minAngle_) : node_->GetWorldRotation(), Vector3::ONE);
 }
 
 void BillboardSet::UpdateGeometry(const FrameInfo& frame)
@@ -229,7 +232,7 @@ void BillboardSet::UpdateGeometry(const FrameInfo& frame)
     if (faceCameraMode_ != FC_NONE)
     {
         transforms_[1] = Matrix3x4(Vector3::ZERO, frame.camera_->GetFaceCameraRotation(node_->GetWorldPosition(),
-            node_->GetWorldRotation(), faceCameraMode_), Vector3::ONE);
+            node_->GetWorldRotation(), faceCameraMode_, minAngle_), Vector3::ONE);
     }
 
     if (bufferSizeDirty_ || indexBuffer_->IsDataLost())
@@ -332,6 +335,12 @@ void BillboardSet::SetFaceCameraMode(FaceCameraMode mode)
     }
 }
 
+void BillboardSet::SetMinAngle(float angle)
+{
+    minAngle_ = angle;
+    MarkNetworkUpdate();
+}
+
 void BillboardSet::SetAnimationLodBias(float bias)
 {
     animationLodBias_ = Max(bias, 0.0f);
@@ -753,7 +762,7 @@ void BillboardSet::CalculateFixedScreenSize(const FrameInfo& frame)
 
     if (!frame.camera_->IsOrthographic())
     {
-        Matrix4 viewProj(frame.camera_->GetProjection(false) * frame.camera_->GetView());
+        Matrix4 viewProj(frame.camera_->GetProjection() * frame.camera_->GetView());
         const Matrix3x4& worldTransform = node_->GetWorldTransform();
         Matrix3x4 billboardTransform = relative_ ? worldTransform : Matrix3x4::IDENTITY;
 

+ 7 - 0
Source/Atomic/Graphics/BillboardSet.h

@@ -129,6 +129,8 @@ public:
     void SetFixedScreenSize(bool enable);
     /// Set how the billboards should rotate in relation to the camera. Default is to follow camera rotation on all axes (FC_ROTATE_XYZ.)
     void SetFaceCameraMode(FaceCameraMode mode);
+    /// Set minimal angle between billboard normal and look-at direction.
+    void SetMinAngle(float angle);
     /// Set animation LOD bias.
     void SetAnimationLodBias(float bias);
     /// Mark for bounding box and vertex buffer update. Call after modifying the billboards.
@@ -161,6 +163,9 @@ public:
     /// Return how the billboards rotate in relation to the camera.
     FaceCameraMode GetFaceCameraMode() const { return faceCameraMode_; }
 
+    /// Return minimal angle between billboard normal and look-at direction.
+    float GetMinAngle() const { return minAngle_; }
+
     /// Return animation LOD bias.
     float GetAnimationLodBias() const { return animationLodBias_; }
 
@@ -201,6 +206,8 @@ protected:
     bool fixedScreenSize_;
     /// Billboard rotation mode in relation to the camera.
     FaceCameraMode faceCameraMode_;
+    /// Minimal angle between billboard normal and look-at direction.
+    float minAngle_;
 
 private:
     /// Resize billboard vertex and index buffers.

+ 183 - 141
Source/Atomic/Graphics/Camera.cpp

@@ -72,7 +72,8 @@ Camera::Camera(Context* context) :
     autoAspectRatio_(true),
     flipVertical_(false),
     useReflection_(false),
-    useClipping_(false)
+    useClipping_(false),
+    customProjection_(false)
 {
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
 }
@@ -241,71 +242,144 @@ void Camera::SetUseClipping(bool enable)
 void Camera::SetClipPlane(const Plane& plane)
 {
     clipPlane_ = plane;
-    projectionDirty_ = true;
     MarkNetworkUpdate();
 }
 
-
 void Camera::SetFlipVertical(bool enable)
 {
     flipVertical_ = enable;
-    projectionDirty_ = true;
+    MarkNetworkUpdate();
+}
+
+void Camera::SetProjection(const Matrix4& projection)
+{
+    projection_ = projection;
+    Matrix4 projInverse = projection_.Inverse();
+
+    // Calculate the actual near & far clip from the custom matrix
+    projNearClip_ = (projInverse * Vector3(0.0f, 0.0f, 0.0f)).z_;
+    projFarClip_ = (projInverse * Vector3(0.0f, 0.0f, 1.0f)).z_;
+    projectionDirty_ = false;
+    autoAspectRatio_ = false;
+    frustumDirty_ = true;
+    customProjection_ = true;
+    // Called due to autoAspectRatio changing state, the projection itself is not serialized
     MarkNetworkUpdate();
 }
 
 float Camera::GetNearClip() const
 {
-    // Orthographic camera has always near clip at 0 to avoid trouble with shader depth parameters,
-    // and unlike in perspective mode there should be no depth buffer precision issue
-    if (!orthographic_)
-        return nearClip_;
-    else
-        return 0.0f;
+    if (projectionDirty_)
+        UpdateProjection();
+
+    return projNearClip_;
+}
+
+float Camera::GetFarClip() const
+{
+    if (projectionDirty_)
+        UpdateProjection();
+
+    return projFarClip_;
+}
+
+const Frustum& Camera::GetFrustum() const
+{
+    // Use projection_ instead of GetProjection() so that Y-flip has no effect. Update first if necessary
+    if (projectionDirty_)
+        UpdateProjection();
+
+    if (frustumDirty_)
+    {
+        if (customProjection_)
+            frustum_.Define(projection_ * GetView());
+        else
+        {
+            // If not using a custom projection, prefer calculating frustum from projection parameters instead of matrix
+            // for better accuracy
+            if (!orthographic_)
+                frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), GetFarClip(), GetEffectiveWorldTransform());
+            else
+                frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), GetFarClip(), GetEffectiveWorldTransform());
+        }
+
+        frustumDirty_ = false;
+    }
+
+    return frustum_;
 }
 
 Frustum Camera::GetSplitFrustum(float nearClip, float farClip) const
 {
-    Frustum ret;
+    if (projectionDirty_)
+        UpdateProjection();
 
-    Matrix3x4 worldTransform = GetEffectiveWorldTransform();
-    nearClip = Max(nearClip, GetNearClip());
-    farClip = Min(farClip, farClip_);
+    nearClip = Max(nearClip, projNearClip_);
+    farClip = Min(farClip, projFarClip_);
     if (farClip < nearClip)
         farClip = nearClip;
 
-    if (!orthographic_)
-        ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, worldTransform);
+    Frustum ret;
+
+    if (customProjection_)
+    {
+        // DefineSplit() needs to project the near & far distances, so can not use a combined view-projection matrix.
+        // Transform to world space afterward instead
+        ret.DefineSplit(projection_, nearClip, farClip);
+        ret.Transform(GetEffectiveWorldTransform());
+    }
     else
-        ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, worldTransform);
+    {
+        if (!orthographic_)
+            ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip, GetEffectiveWorldTransform());
+        else
+            ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip, GetEffectiveWorldTransform());
+    }
 
     return ret;
 }
 
 Frustum Camera::GetViewSpaceFrustum() const
 {
+    if (projectionDirty_)
+        UpdateProjection();
+
     Frustum ret;
 
-    if (!orthographic_)
-        ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_);
+    if (customProjection_)
+        ret.Define(projection_);
     else
-        ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_);
+    {
+        if (!orthographic_)
+            ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), GetFarClip());
+        else
+            ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), GetFarClip());
+    }
 
     return ret;
 }
 
 Frustum Camera::GetViewSpaceSplitFrustum(float nearClip, float farClip) const
 {
-    Frustum ret;
+    if (projectionDirty_)
+        UpdateProjection();
 
-    nearClip = Max(nearClip, GetNearClip());
-    farClip = Min(farClip, farClip_);
+    nearClip = Max(nearClip, projNearClip_);
+    farClip = Min(farClip, projFarClip_);
     if (farClip < nearClip)
         farClip = nearClip;
 
-    if (!orthographic_)
-        ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip);
+    Frustum ret;
+
+    if (customProjection_)
+        ret.DefineSplit(projection_, nearClip, farClip);
     else
-        ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip);
+    {
+        if (!orthographic_)
+            ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip);
+        else
+            ret.DefineOrtho(orthoSize_, aspectRatio_, zoom_, nearClip, farClip);
+    }
 
     return ret;
 }
@@ -322,7 +396,7 @@ Ray Camera::GetScreenRay(float x, float y) const
         return ret;
     }
 
-    Matrix4 viewProjInverse = (GetProjection(false) * GetView()).Inverse();
+    Matrix4 viewProjInverse = (GetProjection() * GetView()).Inverse();
 
     // The parameters range from 0.0 to 1.0. Expand to normalized device coordinates (-1.0 to 1.0) & flip Y axis
     x = 2.0f * x - 1.0f;
@@ -342,7 +416,7 @@ Vector2 Camera::WorldToScreenPoint(const Vector3& worldPos) const
 
     if (eyeSpacePos.z_ > 0.0f)
     {
-        Vector3 screenSpacePos = GetProjection(false) * eyeSpacePos;
+        Vector3 screenSpacePos = GetProjection() * eyeSpacePos;
         ret.x_ = screenSpacePos.x_;
         ret.y_ = screenSpacePos.y_;
     }
@@ -365,124 +439,38 @@ Vector3 Camera::ScreenToWorldPoint(const Vector3& screenPos) const
     return ray.origin_ + ray.direction_ * rayDistance;
 }
 
-const Frustum& Camera::GetFrustum() const
-{
-    if (frustumDirty_)
-    {
-        Matrix3x4 worldTransform = GetEffectiveWorldTransform();
-
-        if (!orthographic_)
-            frustum_.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform);
-        else
-            frustum_.DefineOrtho(orthoSize_, aspectRatio_, zoom_, GetNearClip(), farClip_, worldTransform);
-
-        frustumDirty_ = false;
-    }
-
-    return frustum_;
-}
-
-const Matrix4& Camera::GetProjection() const
+Matrix4 Camera::GetProjection() const
 {
     if (projectionDirty_)
-    {
-        projection_ = GetProjection(true);
-        projectionDirty_ = false;
-    }
+        UpdateProjection();
 
-    return projection_;
+    return flipVertical_ ? flipMatrix * projection_ : projection_;
 }
 
-Matrix4 Camera::GetProjection(bool apiSpecific) const
+Matrix4 Camera::GetGPUProjection() const
 {
-    Matrix4 ret(Matrix4::ZERO);
-
-    // Whether to construct matrix using OpenGL or Direct3D clip space convention
-#ifdef ATOMIC_OPENGL
-    bool openGLFormat = apiSpecific;
+#ifndef ATOMIC_OPENGL
+    return GetProjection(); // Already matches API-specific format
 #else
-    bool openGLFormat = false;
-#endif
-
-    if (!orthographic_)
-    {
-        float nearClip = GetNearClip();
-        float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
-        float w = h / aspectRatio_;
-        float q, r;
+    // See formulation for depth range conversion at http://www.ogre3d.org/forums/viewtopic.php?f=4&t=13357
+    Matrix4 ret = GetProjection();
 
-        if (openGLFormat)
-        {
-            q = (farClip_ + nearClip) / (farClip_ - nearClip);
-            r = -2.0f * farClip_ * nearClip / (farClip_ - nearClip);
-        }
-        else
-        {
-            q = farClip_ / (farClip_ - nearClip);
-            r = -q * nearClip;
-        }
-
-        ret.m00_ = w;
-        ret.m02_ = projectionOffset_.x_ * 2.0f;
-        ret.m11_ = h;
-        ret.m12_ = projectionOffset_.y_ * 2.0f;
-        ret.m22_ = q;
-        ret.m23_ = r;
-        ret.m32_ = 1.0f;
-    }
-    else
-    {
-        // Disregard near clip, because it does not affect depth precision as with perspective projection
-        float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
-        float w = h / aspectRatio_;
-        float q, r;
-
-        if (openGLFormat)
-        {
-            q = 2.0f / farClip_;
-            r = -1.0f;
-        }
-        else
-        {
-            q = 1.0f / farClip_;
-            r = 0.0f;
-        }
-
-        ret.m00_ = w;
-        ret.m03_ = projectionOffset_.x_ * 2.0f;
-        ret.m11_ = h;
-        ret.m13_ = projectionOffset_.y_ * 2.0f;
-        ret.m22_ = q;
-        ret.m23_ = r;
-        ret.m33_ = 1.0f;
-    }
-
-    if (flipVertical_)
-        ret = flipMatrix * ret;
+    ret.m20_ = 2.0f * ret.m20_ - ret.m30_;
+    ret.m21_ = 2.0f * ret.m21_ - ret.m31_;
+    ret.m22_ = 2.0f * ret.m22_ - ret.m32_;
+    ret.m23_ = 2.0f * ret.m23_ - ret.m33_;
 
     return ret;
+#endif
 }
 
 void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
 {
-    near.z_ = GetNearClip();
-    far.z_ = farClip_;
-
-    if (!orthographic_)
-    {
-        float halfViewSize = tanf(fov_ * M_DEGTORAD * 0.5f) / zoom_;
-        near.y_ = near.z_ * halfViewSize;
-        near.x_ = near.y_ * aspectRatio_;
-        far.y_ = far.z_ * halfViewSize;
-        far.x_ = far.y_ * aspectRatio_;
-    }
-    else
-    {
-        float halfViewSize = orthoSize_ * 0.5f / zoom_;
-        near.y_ = far.y_ = halfViewSize;
-        near.x_ = far.x_ = near.y_ * aspectRatio_;
-    }
+    Frustum viewSpaceFrustum = GetViewSpaceFrustum();
+    near = viewSpaceFrustum.vertices_[0];
+    far = viewSpaceFrustum.vertices_[4];
 
+    /// \todo Necessary? Explain this
     if (flipVertical_)
     {
         near.y_ = -near.y_;
@@ -532,16 +520,13 @@ float Camera::GetLodDistance(float distance, float scale, float bias) const
         return orthoSize_ / d;
 }
 
-Quaternion Camera::GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode)
+Quaternion Camera::GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode, float minAngle)
 {
     if (!node_)
         return rotation;
 
     switch (mode)
     {
-    default:
-        return rotation;
-
     case FC_ROTATE_XYZ:
         return node_->GetWorldRotation();
 
@@ -560,19 +545,31 @@ Quaternion Camera::GetFaceCameraRotation(const Vector3& position, const Quaterni
         }
 
     case FC_LOOKAT_Y:
+    case FC_LOOKAT_MIXED:
         {
-            // Make the Y-only lookat happen on an XZ plane to make sure there are no unwanted transitions
-            // or singularities
-            Vector3 lookAtVec(position - node_->GetWorldPosition());
-            lookAtVec.y_ = 0.0f;
+            // Mixed mode needs true look-at vector
+            const Vector3 lookAtVec(position - node_->GetWorldPosition());
+            // While Y-only lookat happens on an XZ plane to make sure there are no unwanted transitions or singularities
+            const Vector3 lookAtVecXZ(lookAtVec.x_, 0.0f, lookAtVec.z_);
 
             Quaternion lookAt;
-            lookAt.FromLookRotation(lookAtVec);
+            lookAt.FromLookRotation(lookAtVecXZ);
 
             Vector3 euler = rotation.EulerAngles();
+            if (mode == FC_LOOKAT_MIXED)
+            {
+                const float angle = lookAtVec.Angle(rotation * Vector3::UP);
+                if (angle > 180 - minAngle)
+                    euler.x_ += minAngle - (180 - angle);
+                else if (angle < minAngle)
+                    euler.x_ -= minAngle - angle;
+            }
             euler.y_ = lookAt.EulerAngles().y_;
             return Quaternion(euler.x_, euler.y_, euler.z_);
         }
+
+    default:
+        return rotation;
     }
 }
 
@@ -584,7 +581,7 @@ Matrix3x4 Camera::GetEffectiveWorldTransform() const
 
 bool Camera::IsProjectionValid() const
 {
-    return farClip_ > GetNearClip();
+    return GetFarClip() > GetNearClip();
 }
 
 const Matrix3x4& Camera::GetView() const
@@ -650,4 +647,49 @@ void Camera::OnMarkedDirty(Node* node)
     viewDirty_ = true;
 }
 
+void Camera::UpdateProjection() const
+{
+    // Start from a zero matrix in case it was custom previously
+    projection_ = Matrix4::ZERO;
+
+    if (!orthographic_)
+    {
+        float h = (1.0f / tanf(fov_ * M_DEGTORAD * 0.5f)) * zoom_;
+        float w = h / aspectRatio_;
+        float q = farClip_ / (farClip_ - nearClip_);
+        float r = -q * nearClip_;
+
+        projection_.m00_ = w;
+        projection_.m02_ = projectionOffset_.x_ * 2.0f;
+        projection_.m11_ = h;
+        projection_.m12_ = projectionOffset_.y_ * 2.0f;
+        projection_.m22_ = q;
+        projection_.m23_ = r;
+        projection_.m32_ = 1.0f;
+        projNearClip_ = nearClip_;
+        projFarClip_ = farClip_;
+    }
+    else
+    {
+        float h = (1.0f / (orthoSize_ * 0.5f)) * zoom_;
+        float w = h / aspectRatio_;
+        float q = 1.0f / farClip_;
+        float r = 0.0f;
+
+        projection_.m00_ = w;
+        projection_.m03_ = projectionOffset_.x_ * 2.0f;
+        projection_.m11_ = h;
+        projection_.m13_ = projectionOffset_.y_ * 2.0f;
+        projection_.m22_ = q;
+        projection_.m23_ = r;
+        projection_.m33_ = 1.0f;
+        // Near clip does not affect depth accuracy in ortho projection, so let it stay 0 to avoid problems with shader depth parameters
+        projNearClip_ = 0.0f;
+        projFarClip_ = farClip_;
+    }
+
+    projectionDirty_ = false;
+    customProjection_ = false;
+}
+
 }

+ 26 - 12
Source/Atomic/Graphics/Camera.h

@@ -94,11 +94,16 @@ public:
     void SetClipPlane(const Plane& plane);
     /// Set vertical flipping mode. Called internally by View to resolve OpenGL / Direct3D9 rendertarget sampling differences.
     void SetFlipVertical(bool enable);
+    /// Set custom projection matrix, which should be specified in D3D convention with depth range 0 - 1. Disables auto aspect ratio.
+    /** Change any of the standard view parameters (FOV, far clip, zoom etc.) to revert to the standard projection. 
+        Note that the custom projection is not serialized or replicated through the network.
+     */
+    void SetProjection(const Matrix4& projection);
 
-    /// Return far clip distance.
-    float GetFarClip() const { return farClip_; }
+    /// Return far clip distance. If a custom projection matrix is in use, is calculated from it instead of the value assigned with SetFarClip().
+    float GetFarClip() const;
 
-    /// Return near clip distance.
+    /// Return near clip distance. If a custom projection matrix is in use, is calculated from it instead of the value assigned with SetNearClip().
     float GetNearClip() const;
 
     /// Return vertical field of view in degrees.
@@ -133,10 +138,10 @@ public:
 
     /// Return frustum in world space.
     const Frustum& GetFrustum() const;
-    /// Return API-specific projection matrix.
-    const Matrix4& GetProjection() const;
-    /// Return either API-specific or API-independent (D3D convention) projection matrix.
-    Matrix4 GetProjection(bool apiSpecific) const;
+    /// Return projection matrix. It's in D3D convention with depth range 0 - 1.
+    Matrix4 GetProjection() const;
+    /// Return projection matrix converted to API-specific format for use as a shader parameter.
+    Matrix4 GetGPUProjection() const;
     /// Return view matrix.
     const Matrix3x4& GetView() const;
     /// Return frustum near and far sizes.
@@ -149,11 +154,11 @@ public:
     Frustum GetViewSpaceFrustum() const;
     /// Return split frustum in view space.
     Frustum GetViewSpaceSplitFrustum(float nearClip, float farClip) const;
-    /// Return ray corresponding to normalized screen coordinates (0.0 - 1.0), with origin on the near clip plane.
+    /// Return ray corresponding to normalized screen coordinates (0 - 1), with origin on the near clip plane.
     Ray GetScreenRay(float x, float y) const;
-    /// Convert a world space point to normalized screen coordinates (0.0 - 1.0).
+    /// Convert a world space point to normalized screen coordinates (0 - 1).
     Vector2 WorldToScreenPoint(const Vector3& worldPos) const;
-    /// Convert normalized screen coordinates (0.0 - 1.0) and distance along view Z axis (in Z coordinate) to a world space point. The distance can not be closer than the near clip plane.
+    /// Convert normalized screen coordinates (0 - 1) and distance along view Z axis (in Z coordinate) to a world space point. The distance can not be closer than the near clip plane.
     /** Note that a HitDistance() from the camera screen ray is not the same as distance along the view Z axis, as under a perspective projection the ray is likely to not be Z-aligned.
      */
     Vector3 ScreenToWorldPoint(const Vector3& screenPos) const;
@@ -186,7 +191,7 @@ public:
     /// Return a scene node's LOD scaled distance.
     float GetLodDistance(float distance, float scale, float bias) const;
     /// Return a world rotation for facing a camera on certain axes based on the existing world rotation.
-    Quaternion GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode);
+    Quaternion GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode, float minAngle = 0.0f);
     /// Get effective world transform for matrix and frustum calculations including reflection but excluding node scaling.
     Matrix3x4 GetEffectiveWorldTransform() const;
     /// Return if projection parameters are valid for rendering and raycasting.
@@ -212,11 +217,14 @@ protected:
     virtual void OnMarkedDirty(Node* node);
 
 private:
+    /// Recalculate projection matrix.
+    void UpdateProjection() const;
+
     /// Cached view matrix.
     mutable Matrix3x4 view_;
     /// Cached projection matrix.
     mutable Matrix4 projection_;
-    /// Cached frustum.
+    /// Cached world space frustum.
     mutable Frustum frustum_;
     /// View matrix dirty flag.
     mutable bool viewDirty_;
@@ -226,6 +234,10 @@ private:
     mutable bool frustumDirty_;
     /// Orthographic mode flag.
     bool orthographic_;
+    /// Cached actual near clip distance.
+    mutable float projNearClip_;
+    /// Cached actual far clip distance.
+    mutable float projFarClip_;
     /// Near clip distance.
     float nearClip_;
     /// Far clip distance.
@@ -262,6 +274,8 @@ private:
     bool useReflection_;
     /// Use custom clip plane flag.
     bool useClipping_;
+    /// Use custom projection matrix flag. Used internally.
+    mutable bool customProjection_;
 };
 
 }

+ 2 - 1
Source/Atomic/Graphics/DebugRenderer.cpp

@@ -81,6 +81,7 @@ void DebugRenderer::SetView(Camera* camera)
 
     view_ = camera->GetView();
     projection_ = camera->GetProjection();
+    gpuProjection_ = camera->GetGPUProjection();
     frustum_ = camera->GetFrustum();
 }
 
@@ -510,7 +511,7 @@ void DebugRenderer::Render()
     graphics->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
     graphics->SetShaderParameter(VSP_VIEW, view_);
     graphics->SetShaderParameter(VSP_VIEWINV, view_.Inverse());
-    graphics->SetShaderParameter(VSP_VIEWPROJ, projection_ * view_);
+    graphics->SetShaderParameter(VSP_VIEWPROJ, gpuProjection_ * view_);
     graphics->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
     graphics->SetVertexBuffer(vertexBuffer_);
 

+ 2 - 0
Source/Atomic/Graphics/DebugRenderer.h

@@ -185,6 +185,8 @@ private:
     Matrix3x4 view_;
     /// Projection transform.
     Matrix4 projection_;
+    /// Projection transform in API-specific format.
+    Matrix4 gpuProjection_;
     /// View frustum.
     Frustum frustum_;
     /// Vertex buffer.

+ 13 - 9
Source/Atomic/Graphics/Direct3D11/D3D11Graphics.cpp

@@ -229,6 +229,7 @@ Graphics::Graphics(Context* context) :
     numBatches_(0),
     maxScratchBufferRequest_(0),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
+    defaultTextureAnisotropy_(4),
     shaderPath_("Shaders/HLSL/"),
     shaderExtension_(".hlsl"),
     orientations_("LandscapeLeft LandscapeRight"),
@@ -1323,11 +1324,13 @@ void Graphics::SetDefaultTextureFilterMode(TextureFilterMode mode)
     }
 }
 
-void Graphics::SetTextureAnisotropy(unsigned level)
+void Graphics::SetDefaultTextureAnisotropy(unsigned level)
 {
-    if (level != textureAnisotropy_)
+    level = Max(level, 1U);
+
+    if (level != defaultTextureAnisotropy_)
     {
-        textureAnisotropy_ = level;
+        defaultTextureAnisotropy_ = level;
         SetTextureParametersDirty();
     }
 }
@@ -1451,11 +1454,12 @@ void Graphics::SetViewport(const IntRect& rect)
     SetScissorTest(false);
 }
 
-void Graphics::SetBlendMode(BlendMode mode)
+void Graphics::SetBlendMode(BlendMode mode, bool alphaToCoverage)
 {
-    if (mode != blendMode_)
+    if (mode != blendMode_ || alphaToCoverage != alphaToCoverage_)
     {
         blendMode_ = mode;
+        alphaToCoverage_ = alphaToCoverage;
         impl_->blendStateDirty_ = true;
     }
 }
@@ -2321,7 +2325,7 @@ void Graphics::ResetCachedState()
     vertexShader_ = 0;
     pixelShader_ = 0;
     blendMode_ = BLEND_REPLACE;
-    textureAnisotropy_ = 1;
+    alphaToCoverage_ = false;
     colorWrite_ = true;
     cullMode_ = CULL_CCW;
     constantDepthBias_ = 0.0f;
@@ -2440,7 +2444,7 @@ void Graphics::PrepareDraw()
 
     if (impl_->blendStateDirty_)
     {
-        unsigned newBlendStateHash = (unsigned)((colorWrite_ ? 1 : 0) | (blendMode_ << 1));
+        unsigned newBlendStateHash = (unsigned)((colorWrite_ ? 1 : 0) | (alphaToCoverage_ ? 2 : 0) | (blendMode_ << 2));
         if (newBlendStateHash != impl_->blendStateHash_)
         {
             HashMap<unsigned, ID3D11BlendState*>::Iterator i = impl_->blendStates_.Find(newBlendStateHash);
@@ -2450,7 +2454,7 @@ void Graphics::PrepareDraw()
 
                 D3D11_BLEND_DESC stateDesc;
                 memset(&stateDesc, 0, sizeof stateDesc);
-                stateDesc.AlphaToCoverageEnable = false;
+                stateDesc.AlphaToCoverageEnable = alphaToCoverage_ ? TRUE : FALSE;
                 stateDesc.IndependentBlendEnable = false;
                 stateDesc.RenderTarget[0].BlendEnable = d3dBlendEnable[blendMode_];
                 stateDesc.RenderTarget[0].SrcBlend = d3dSrcBlend[blendMode_];
@@ -2537,7 +2541,7 @@ void Graphics::PrepareDraw()
 
         unsigned newRasterizerStateHash =
             (scissorTest_ ? 1 : 0) | (fillMode_ << 1) | (cullMode_ << 3) | ((scaledDepthBias & 0x1fff) << 5) |
-            ((*((unsigned*)&slopeScaledDepthBias_) & 0x1fff) << 18);
+            (((int)(slopeScaledDepthBias_ * 100.0f) & 0x1fff) << 18);
         if (newRasterizerStateHash != impl_->rasterizerStateHash_)
         {
             HashMap<unsigned, ID3D11RasterizerState*>::Iterator i = impl_->rasterizerStates_.Find(newRasterizerStateHash);

+ 1 - 1
Source/Atomic/Graphics/Direct3D11/D3D11Texture.cpp

@@ -138,7 +138,7 @@ void Texture::UpdateParameters()
     samplerDesc.AddressU = d3dAddressMode[addressMode_[0]];
     samplerDesc.AddressV = d3dAddressMode[addressMode_[1]];
     samplerDesc.AddressW = d3dAddressMode[addressMode_[2]];
-    samplerDesc.MaxAnisotropy = graphics_->GetTextureAnisotropy();
+    samplerDesc.MaxAnisotropy = anisotropy_ ? anisotropy_ : graphics_->GetDefaultTextureAnisotropy();
     samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
     samplerDesc.MinLOD = -M_INFINITY;
     samplerDesc.MaxLOD = M_INFINITY;

+ 18 - 17
Source/Atomic/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -272,6 +272,7 @@ Graphics::Graphics(Context* context) :
     numBatches_(0),
     maxScratchBufferRequest_(0),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
+    defaultTextureAnisotropy_(4),
     shaderPath_("Shaders/HLSL/"),
     shaderExtension_(".hlsl"),
     orientations_("LandscapeLeft LandscapeRight"),
@@ -1429,6 +1430,14 @@ void Graphics::SetTexture(unsigned index, Texture* texture)
                 impl_->wAddressModes_[index] = w;
             }
         }
+        unsigned maxAnisotropy = texture->GetAnisotropy();
+        if (!maxAnisotropy)
+            maxAnisotropy = defaultTextureAnisotropy_;
+        if (maxAnisotropy != impl_->maxAnisotropy_[index])
+        {
+            impl_->device_->SetSamplerState(index, D3DSAMP_MAXANISOTROPY, maxAnisotropy);
+            impl_->maxAnisotropy_[index] = maxAnisotropy;
+        }
         if (u == D3DTADDRESS_BORDER || v == D3DTADDRESS_BORDER)
         {
             const Color& borderColor = texture->GetBorderColor();
@@ -1455,6 +1464,11 @@ void Graphics::SetDefaultTextureFilterMode(TextureFilterMode mode)
     defaultTextureFilterMode_ = mode;
 }
 
+void Graphics::SetDefaultTextureAnisotropy(unsigned level)
+{
+    defaultTextureAnisotropy_ = Max(level, 1U);
+}
+
 void Graphics::ResetRenderTargets()
 {
     for (unsigned i = 0; i < MAX_RENDERTARGETS; ++i)
@@ -1598,21 +1612,7 @@ void Graphics::SetViewport(const IntRect& rect)
     SetScissorTest(false);
 }
 
-void Graphics::SetTextureAnisotropy(unsigned level)
-{
-    if (level < 1)
-        level = 1;
-
-    if (level != textureAnisotropy_)
-    {
-        for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
-            impl_->device_->SetSamplerState(i, D3DSAMP_MAXANISOTROPY, level);
-
-        textureAnisotropy_ = level;
-    }
-}
-
-void Graphics::SetBlendMode(BlendMode mode)
+void Graphics::SetBlendMode(BlendMode mode, bool /* alphaToCoverage */)
 {
     if (mode != blendMode_)
     {
@@ -2365,7 +2365,7 @@ void Graphics::CheckFeatureSupport()
 {
     anisotropySupport_ = true;
     dxtTextureSupport_ = true;
-
+    
     // Reset features first
     lightPrepassSupport_ = false;
     deferredSupport_ = false;
@@ -2525,6 +2525,7 @@ void Graphics::ResetCachedState()
         impl_->uAddressModes_[i] = D3DTADDRESS_WRAP;
         impl_->vAddressModes_[i] = D3DTADDRESS_WRAP;
         impl_->wAddressModes_[i] = D3DTADDRESS_WRAP;
+        impl_->maxAnisotropy_[i] = M_MAX_UNSIGNED;
         impl_->borderColors_[i] = Color(0.0f, 0.0f, 0.0f, 0.0f);
         impl_->sRGBModes_[i] = false;
     }
@@ -2547,7 +2548,7 @@ void Graphics::ResetCachedState()
     vertexShader_ = 0;
     pixelShader_ = 0;
     blendMode_ = BLEND_REPLACE;
-    textureAnisotropy_ = 1;
+    alphaToCoverage_ = false;
     colorWrite_ = true;
     cullMode_ = CULL_CCW;
     constantDepthBias_ = 0.0f;

+ 2 - 0
Source/Atomic/Graphics/Direct3D9/D3D9GraphicsImpl.h

@@ -90,6 +90,8 @@ private:
     D3DTEXTUREADDRESS vAddressModes_[MAX_TEXTURE_UNITS];
     /// Texture W coordinate addressing modes in use.
     D3DTEXTUREADDRESS wAddressModes_[MAX_TEXTURE_UNITS];
+    /// Texture anisotropy setting in use.
+    unsigned maxAnisotropy_[MAX_TEXTURE_UNITS];
     /// Texture border colors in use.
     Color borderColors_[MAX_TEXTURE_UNITS];
     /// Device lost flag.

+ 16 - 11
Source/Atomic/Graphics/Graphics.h

@@ -188,12 +188,12 @@ public:
     void SetTexture(unsigned index, Texture* texture);
     /// Bind texture unit 0 for update. Called by Texture. Used only on OpenGL.
     void SetTextureForUpdate(Texture* texture);
-    /// Set default texture filtering mode.
-    void SetDefaultTextureFilterMode(TextureFilterMode mode);
-    /// Set texture anisotropy.
-    void SetTextureAnisotropy(unsigned level);
     /// Dirty texture parameters of all textures (when global settings change.)
     void SetTextureParametersDirty();
+    /// Set default texture filtering mode. Called by Renderer before rendering.
+    void SetDefaultTextureFilterMode(TextureFilterMode mode);
+    /// Set default texture anisotropy level. Called by Renderer before rendering.
+    void SetDefaultTextureAnisotropy(unsigned level);
     /// Reset all rendertargets, depth-stencil surface and viewport.
     void ResetRenderTargets();
     /// Reset specific rendertarget.
@@ -210,8 +210,8 @@ public:
     void SetDepthStencil(Texture2D* texture);
     /// Set viewport.
     void SetViewport(const IntRect& rect);
-    /// Set blending mode.
-    void SetBlendMode(BlendMode mode);
+    /// Set blending and alpha-to-coverage modes. Alpha-to-coverage is not supported on Direct3D9.
+    void SetBlendMode(BlendMode mode, bool alphaToCoverage = false);
     /// Set color write on/off.
     void SetColorWrite(bool enable);
     /// Set hardware culling mode.
@@ -384,6 +384,9 @@ public:
     /// Return default texture filtering mode.
     TextureFilterMode GetDefaultTextureFilterMode() const { return defaultTextureFilterMode_; }
 
+    /// Return default texture max. anisotropy level.
+    unsigned GetDefaultTextureAnisotropy() const { return defaultTextureAnisotropy_; }
+
     /// Return current rendertarget by index.
     RenderSurface* GetRenderTarget(unsigned index) const;
 
@@ -393,12 +396,12 @@ public:
     /// Return the viewport coordinates.
     IntRect GetViewport() const { return viewport_; }
 
-    /// Return texture anisotropy.
-    unsigned GetTextureAnisotropy() const { return textureAnisotropy_; }
-
     /// Return blending mode.
     BlendMode GetBlendMode() const { return blendMode_; }
 
+    /// Return whether alpha-to-coverage is enabled.
+    bool GetAlphaToCoverage() const { return alphaToCoverage_; }
+
     /// Return whether color write is enabled.
     bool GetColorWrite() const { return colorWrite_; }
 
@@ -699,10 +702,12 @@ private:
     IntRect viewport_;
     /// Default texture filtering mode.
     TextureFilterMode defaultTextureFilterMode_;
-    /// Texture anisotropy level.
-    unsigned textureAnisotropy_;
+    /// Default texture max. anisotropy level.
+    unsigned defaultTextureAnisotropy_;
     /// Blending mode.
     BlendMode blendMode_;
+    /// Alpha-to-coverage enable.
+    bool alphaToCoverage_;
     /// Color write enable.
     bool colorWrite_;
     /// Hardware culling mode.

+ 3 - 2
Source/Atomic/Graphics/GraphicsDefs.h

@@ -352,10 +352,11 @@ enum FaceCameraMode
     FC_ROTATE_Y,
     FC_LOOKAT_XYZ,
     FC_LOOKAT_Y,
-    FC_DIRECTION
+    FC_LOOKAT_MIXED,
+    FC_DIRECTION,
 };
 
-/// Shadow type
+/// Shadow type.
 enum ShadowQuality
 {
     SHADOWQUALITY_SIMPLE_16BIT = 0,

+ 66 - 1
Source/Atomic/Graphics/Light.cpp

@@ -55,7 +55,9 @@ static const float DEFAULT_SHADOWFADESTART = 0.8f;
 static const float DEFAULT_SHADOWQUANTIZE = 0.5f;
 static const float DEFAULT_SHADOWMINVIEW = 3.0f;
 static const float DEFAULT_SHADOWNEARFARRATIO = 0.002f;
+static const float DEFAULT_SHADOWMAXEXTRUSION = 1000.0f;
 static const float DEFAULT_SHADOWSPLIT = 1000.0f;
+static const float DEFAULT_TEMPERATURE = 6590.0f;
 
 static const char* typeNames[] =
 {
@@ -92,6 +94,7 @@ Light::Light(Context* context) :
     shadowCascade_(CascadeParameters(DEFAULT_SHADOWSPLIT, 0.0f, 0.0f, 0.0f, DEFAULT_SHADOWFADESTART)),
     shadowFocus_(FocusParameters(true, true, true, DEFAULT_SHADOWQUANTIZE, DEFAULT_SHADOWMINVIEW)),
     lightQueue_(0),
+    temperature_(6590.0f),
     specularIntensity_(DEFAULT_SPECULARINTENSITY),
     brightness_(DEFAULT_BRIGHTNESS),
     range_(DEFAULT_RANGE),
@@ -102,7 +105,9 @@ Light::Light(Context* context) :
     shadowIntensity_(0.0f),
     shadowResolution_(1.0f),
     shadowNearFarRatio_(DEFAULT_SHADOWNEARFARRATIO),
-    perVertex_(false)
+    shadowMaxExtrusion_(DEFAULT_SHADOWMAXEXTRUSION),
+    perVertex_(false),
+    usePhysicalValues_(false)
 {
 }
 
@@ -120,6 +125,8 @@ void Light::RegisterObject(Context* context)
     ATOMIC_ACCESSOR_ATTRIBUTE("Specular Intensity", GetSpecularIntensity, SetSpecularIntensity, float, DEFAULT_SPECULARINTENSITY,
         AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Brightness Multiplier", GetBrightness, SetBrightness, float, DEFAULT_BRIGHTNESS, AM_DEFAULT);
+    ATOMIC_ACCESSOR_ATTRIBUTE("Temperature", GetTemperature, SetTemperature, float, DEFAULT_TEMPERATURE, AM_DEFAULT);
+    ATOMIC_ATTRIBUTE("Use Physical Values", bool, usePhysicalValues_, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Range", GetRange, SetRange, float, DEFAULT_RANGE, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Spot FOV", GetFov, SetFov, float, DEFAULT_LIGHT_FOV, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Spot Aspect Ratio", GetAspectRatio, SetAspectRatio, float, 1.0f, AM_DEFAULT);
@@ -148,6 +155,7 @@ void Light::RegisterObject(Context* context)
     ATOMIC_ATTRIBUTE("Depth Slope Bias", float, shadowBias_.slopeScaledBias_, DEFAULT_SLOPESCALEDBIAS, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Normal Offset", float, shadowBias_.normalOffset_, DEFAULT_NORMALOFFSET, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Near/Farclip Ratio", float, shadowNearFarRatio_, DEFAULT_SHADOWNEARFARRATIO, AM_DEFAULT);
+    ATOMIC_ACCESSOR_ATTRIBUTE("Max Extrusion", GetShadowMaxExtrusion, SetShadowMaxExtrusion, float, DEFAULT_SHADOWMAXEXTRUSION, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("View Mask", int, viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Light Mask", int, lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
 }
@@ -290,6 +298,18 @@ void Light::SetColor(const Color& color)
     MarkNetworkUpdate();
 }
 
+void Light::SetTemperature(float temperature)
+{
+    temperature_ = Clamp(temperature, 1000.0f, 10000.0f);
+    MarkNetworkUpdate();
+}
+
+void Light::SetUsePhysicalValues(bool enable)
+{
+    usePhysicalValues_ = enable;
+    MarkNetworkUpdate();
+}
+
 void Light::SetSpecularIntensity(float intensity)
 {
     specularIntensity_ = Max(intensity, 0.0f);
@@ -329,6 +349,12 @@ void Light::SetShadowNearFarRatio(float nearFarRatio)
     MarkNetworkUpdate();
 }
 
+void Light::SetShadowMaxExtrusion(float extrusion)
+{
+    shadowMaxExtrusion_ = Max(extrusion, 0.0f);
+    MarkNetworkUpdate();
+}
+
 void Light::SetFadeDistance(float distance)
 {
     fadeDistance_ = Max(distance, 0.0f);
@@ -386,6 +412,45 @@ void Light::SetShapeTexture(Texture* texture)
     MarkNetworkUpdate();
 }
 
+Color Light::GetColorFromTemperature() const
+{
+    // Approximate Planckian locus in CIE 1960 UCS
+    float u = (0.860117757f + 1.54118254e-4f * temperature_ + 1.28641212e-7f * temperature_ * temperature_) /
+        (1.0f + 8.42420235e-4f * temperature_ + 7.08145163e-7f * temperature_ * temperature_);
+    float v = (0.317398726f + 4.22806245e-5f * temperature_ + 4.20481691e-8f * temperature_ * temperature_) /
+        (1.0f - 2.89741816e-5f * temperature_ + 1.61456053e-7f * temperature_ * temperature_);
+
+    float x = 3.0f * u / (2.0f * u - 8.0f * v + 4.0f);
+    float y = 2.0f * v / (2.0f * u - 8.0f * v + 4.0f);
+    float z = 1.0f - x - y;
+
+    float y_ = 1.0f;
+    float x_ = y_ / y * x;
+    float z_ = y_ / y * z;
+
+    float red = 3.2404542f * x_ + -1.5371385f * y_ + -0.4985314f * z_;
+    float green = -0.9692660f * x_ + 1.8760108f * y_ + 0.0415560f * z_;
+    float blue = 0.0556434f * x_ + -0.2040259f * y_ + 1.0572252f * z_;
+
+    return Color(red, green, blue);
+}
+
+Color Light::GetEffectiveColor() const
+{
+    if (usePhysicalValues_)
+    {
+        // Light color in kelvin.
+        Color tempColor = GetColorFromTemperature();
+        // Light brightness in lumens
+        float energy = (brightness_ * 4.0f * M_PI) * 16.0f / (100.0f * 100.0f) / M_PI;
+        return Color(tempColor.r_ * color_.r_ * energy, tempColor.g_ * color_.g_ * energy, tempColor.b_ * color_.b_ * energy, 1.0f);
+    }
+    else
+    {
+        return Color(color_ * brightness_, 1.0f);
+    }
+}
+
 Frustum Light::GetFrustum() const
 {
     // Note: frustum is unaffected by node or parent scale

+ 30 - 6
Source/Atomic/Graphics/Light.h

@@ -50,7 +50,7 @@ static const unsigned MAX_CASCADE_SPLITS = 4;
 static const unsigned MAX_CASCADE_SPLITS = 1;
 #endif
 
-/// Shadow depth bias parameters.
+/// Depth bias parameters. Used both by lights (for shadow mapping) and materials.
 struct ATOMIC_API BiasParameters
 {
     /// Construct undefined.
@@ -178,9 +178,13 @@ public:
     void SetPerVertex(bool enable);
     /// Set color.
     void SetColor(const Color& color);
+    /// Set temperature of the light in Kelvin. Modulates the light color when "use physical values" is enabled.
+    void SetTemperature(float temperature);
+    /// Set use physical light values.
+    void SetUsePhysicalValues(bool enable);
     /// Set specular intensity. Zero disables specular calculations.
     void SetSpecularIntensity(float intensity);
-    /// Set light brightness multiplier. Both the color and specular intensity are multiplied with this to get final values for rendering.
+    /// Set light brightness multiplier. Both the color and specular intensity are multiplied with this. When "use physical values" is enabled, the value is specified in lumens.
     void SetBrightness(float brightness);
     /// Set range.
     void SetRange(float range);
@@ -202,8 +206,10 @@ public:
     void SetShadowIntensity(float intensity);
     /// Set shadow resolution between 0.25 - 1.0. Determines the shadow map to use.
     void SetShadowResolution(float resolution);
-    /// Set shadow camera near/far clip distance ratio.
+    /// Set shadow camera near/far clip distance ratio for spot and point lights. Does not affect directional lights, since they are orthographic and have near clip 0.
     void SetShadowNearFarRatio(float nearFarRatio);
+    /// Set maximum shadow extrusion for directional lights. The actual extrusion will be the smaller of this and camera far clip. Default 1000.
+    void SetShadowMaxExtrusion(float extrusion);
     /// Set range attenuation texture.
     void SetRampTexture(Texture* texture);
     /// Set spotlight attenuation texture.
@@ -218,14 +224,23 @@ public:
     /// Return color.
     const Color& GetColor() const { return color_; }
 
+    /// Return the temperature of the light in Kelvin.
+    float GetTemperature() const { return temperature_; }
+
+    /// Return if light uses temperature and brightness in lumens.
+    bool GetUsePhysicalValues() const { return usePhysicalValues_; }
+
+    /// Return the color value of the temperature in Kelvin.
+    Color GetColorFromTemperature() const;
+
     /// Return specular intensity.
     float GetSpecularIntensity() const { return specularIntensity_; }
 
-    /// Return brightness multiplier.
+    /// Return brightness multiplier. Specified in lumens when "use physical values" is enabled.
     float GetBrightness() const { return brightness_; }
 
-    /// Return effective color, multiplied by brightness. Do not multiply the alpha so that can compare against the default black color to detect a light with no effect.
-    Color GetEffectiveColor() const { return Color(color_ * brightness_, 1.0f); }
+    /// Return effective color, multiplied by brightness and affected by temperature when "use physical values" is enabled. Alpha is always 1 so that can compare against the default black color to detect a light with no effect.
+    Color GetEffectiveColor() const;
 
     /// Return effective specular intensity, multiplied by absolute value of brightness.
     float GetEffectiveSpecularIntensity() const { return specularIntensity_ * Abs(brightness_); }
@@ -263,6 +278,9 @@ public:
     /// Return shadow camera near/far clip distance ratio.
     float GetShadowNearFarRatio() const { return shadowNearFarRatio_; }
 
+    /// Return maximum shadow extrusion distance for directional lights.
+    float GetShadowMaxExtrusion() const { return shadowMaxExtrusion_; }
+
     /// Return range attenuation texture.
     Texture* GetRampTexture() const { return rampTexture_; }
 
@@ -319,6 +337,8 @@ private:
     LightType lightType_;
     /// Color.
     Color color_;
+    /// Light Temperature.
+    float temperature_;
     /// Shadow depth bias parameters.
     BiasParameters shadowBias_;
     /// Directional light cascaded shadow parameters.
@@ -353,8 +373,12 @@ private:
     float shadowResolution_;
     /// Shadow camera near/far clip distance ratio.
     float shadowNearFarRatio_;
+    /// Directional shadow max. extrusion distance.
+    float shadowMaxExtrusion_;
     /// Per-vertex lighting flag.
     bool perVertex_;
+    /// Use physical light values flag.
+    bool usePhysicalValues_;
 };
 
 inline bool CompareLights(Light* lhs, Light* rhs)

+ 135 - 23
Source/Atomic/Graphics/Material.cpp

@@ -173,6 +173,7 @@ TechniqueEntry::TechniqueEntry() :
 
 TechniqueEntry::TechniqueEntry(Technique* tech, unsigned qualityLevel, float lodDistance) :
     technique_(tech),
+    original_(tech),
     qualityLevel_(qualityLevel),
     lodDistance_(lodDistance)
 {
@@ -429,6 +430,13 @@ bool Material::Load(const XMLElement& source)
 
     ResourceCache* cache = GetSubsystem<ResourceCache>();
 
+    XMLElement shaderElem = source.GetChild("shader");
+    if (shaderElem)
+    {
+        vertexShaderDefines_ = shaderElem.GetAttribute("vsdefines");
+        pixelShaderDefines_ = shaderElem.GetAttribute("psdefines");
+    }
+
     XMLElement techniqueElem = source.GetChild("technique");
     techniques_.Clear();
 
@@ -438,7 +446,7 @@ bool Material::Load(const XMLElement& source)
         if (tech)
         {
             TechniqueEntry newTechnique;
-            newTechnique.technique_ = tech;
+            newTechnique.technique_ = newTechnique.original_ = tech;
             if (techniqueElem.HasAttribute("quality"))
                 newTechnique.qualityLevel_ = techniqueElem.GetInt("quality");
             if (techniqueElem.HasAttribute("loddistance"))
@@ -450,6 +458,7 @@ bool Material::Load(const XMLElement& source)
     }
 
     SortTechniques();
+    ApplyShaderDefines();
 
     XMLElement textureElem = source.GetChild("texture");
     while (textureElem)
@@ -539,13 +548,20 @@ bool Material::Load(const XMLElement& source)
     if (depthBiasElem)
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
 
+    XMLElement alphaToCoverageElem = source.GetChild("alphatocoverage");
+    if (alphaToCoverageElem)
+        SetAlphaToCoverage(alphaToCoverageElem.GetBool("enable"));
+
     XMLElement renderOrderElem = source.GetChild("renderorder");
     if (renderOrderElem)
         SetRenderOrder((unsigned char)renderOrderElem.GetUInt("value"));
 
+    XMLElement occlusionElem = source.GetChild("occlusion");
+    if (occlusionElem)
+        SetOcclusion(occlusionElem.GetBool("enable"));
+
     RefreshShaderParameterHash();
     RefreshMemoryUse();
-    CheckOcclusion();
     return true;
 }
 
@@ -561,6 +577,13 @@ bool Material::Load(const JSONValue& source)
 
     ResourceCache* cache = GetSubsystem<ResourceCache>();
 
+    const JSONValue& shaderVal = source.Get("shader");
+    if (!shaderVal.IsNull())
+    {
+        vertexShaderDefines_ = shaderVal.Get("vsdefines").GetString();
+        pixelShaderDefines_ = shaderVal.Get("psdefines").GetString();
+    }
+
     // Load techniques
     JSONArray techniquesArray = source.Get("techniques").GetArray();
     techniques_.Clear();
@@ -573,7 +596,7 @@ bool Material::Load(const JSONValue& source)
         if (tech)
         {
             TechniqueEntry newTechnique;
-            newTechnique.technique_ = tech;
+            newTechnique.technique_ = newTechnique.original_ = tech;
             JSONValue qualityVal = techVal.Get("quality");
             if (!qualityVal.IsNull())
                 newTechnique.qualityLevel_ = qualityVal.GetInt();
@@ -585,6 +608,7 @@ bool Material::Load(const JSONValue& source)
     }
 
     SortTechniques();
+    ApplyShaderDefines();
 
     // Load textures
     JSONObject textureObject = source.Get("textures").GetObject();
@@ -681,13 +705,20 @@ bool Material::Load(const JSONValue& source)
     if (!depthBiasVal.IsNull())
         SetDepthBias(BiasParameters(depthBiasVal.Get("constant").GetFloat(), depthBiasVal.Get("slopescaled").GetFloat()));
 
+    JSONValue alphaToCoverageVal = source.Get("alphatocoverage");
+    if (!alphaToCoverageVal.IsNull())
+        SetAlphaToCoverage(alphaToCoverageVal.GetBool());
+
     JSONValue renderOrderVal = source.Get("renderorder");
     if (!renderOrderVal.IsNull())
-        SetRenderOrder((unsigned char)renderOrderVal.Get("value").GetUInt());
+        SetRenderOrder((unsigned char)renderOrderVal.GetUInt());
+
+    JSONValue occlusionVal = source.Get("occlusion");
+    if (!occlusionVal.IsNull())
+        SetOcclusion(occlusionVal.GetBool());
 
     RefreshShaderParameterHash();
     RefreshMemoryUse();
-    CheckOcclusion();
     return true;
 }
 
@@ -724,6 +755,16 @@ bool Material::Save(XMLElement& dest) const
         }
     }
 
+    // Write shader compile defines
+    if (!vertexShaderDefines_.Empty() || !pixelShaderDefines_.Empty())
+    {
+        XMLElement shaderElem = dest.CreateChild("shader");
+        if (!vertexShaderDefines_.Empty())
+            shaderElem.SetString("vsdefines", vertexShaderDefines_);
+        if (!pixelShaderDefines_.Empty())
+            shaderElem.SetString("psdefines", pixelShaderDefines_);
+    }
+
     // Write shader parameters
     for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
          j != shaderParameters_.End(); ++j)
@@ -769,10 +810,18 @@ bool Material::Save(XMLElement& dest) const
     depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
     depthBiasElem.SetFloat("slopescaled", depthBias_.slopeScaledBias_);
 
+    // Write alpha-to-coverage
+    XMLElement alphaToCoverageElem = dest.CreateChild("alphatocoverage");
+    alphaToCoverageElem.SetBool("enable", alphaToCoverage_);
+
     // Write render order
     XMLElement renderOrderElem = dest.CreateChild("renderorder");
     renderOrderElem.SetUInt("value", renderOrder_);
 
+    // Write occlusion
+    XMLElement occlusionElem = dest.CreateChild("occlusion");
+    occlusionElem.SetBool("enable", occlusion_);
+
     return true;
 }
 
@@ -805,6 +854,17 @@ bool Material::Save(JSONValue& dest) const
     }
     dest.Set("textures", texturesValue);
 
+    // Write shader compile defines
+    if (!vertexShaderDefines_.Empty() || !pixelShaderDefines_.Empty())
+    {
+        JSONValue shaderVal;
+        if (!vertexShaderDefines_.Empty())
+            shaderVal.Set("vsdefines", vertexShaderDefines_);
+        if (!pixelShaderDefines_.Empty())
+            shaderVal.Set("psdefines", pixelShaderDefines_);
+        dest.Set("shader", shaderVal);
+    }
+
     // Write shader parameters
     JSONValue shaderParamsVal;
     for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
@@ -849,10 +909,17 @@ bool Material::Save(JSONValue& dest) const
     JSONValue depthBiasValue;
     depthBiasValue.Set("constant", depthBias_.constantBias_);
     depthBiasValue.Set("slopescaled", depthBias_.slopeScaledBias_);
+    dest.Set("depthbias", depthBiasValue);
+
+    // Write alpha-to-coverage
+    dest.Set("alphatocoverage", alphaToCoverage_);
 
     // Write render order
     dest.Set("renderorder", (unsigned) renderOrder_);
 
+    // Write occlusion
+    dest.Set("occlusion", occlusion_);
+
     return true;
 }
 
@@ -871,14 +938,39 @@ void Material::SetTechnique(unsigned index, Technique* tech, unsigned qualityLev
         return;
 
     techniques_[index] = TechniqueEntry(tech, qualityLevel, lodDistance);
-    CheckOcclusion();
+    ApplyShaderDefines(index);
+}
+
+void Material::SetVertexShaderDefines(const String& defines)
+{
+    if (defines != vertexShaderDefines_)
+    {
+        vertexShaderDefines_ = defines;
+        ApplyShaderDefines();
+    }
+}
+
+void Material::SetPixelShaderDefines(const String& defines)
+{
+    if (defines != pixelShaderDefines_)
+    {
+        pixelShaderDefines_ = defines;
+        ApplyShaderDefines();
+    }
 }
 
 void Material::SetShaderParameter(const String& name, const Variant& value)
 {
     MaterialShaderParameter newParam;
     newParam.name_ = name;
-    newParam.value_ = value;
+    if (value.GetType() != VAR_DOUBLE)
+        newParam.value_ = value;
+    else
+    {
+        // Lua scripts may end up creating Double variants, which are unsuitable for shader data. Convert if necessary.
+        newParam.value_ = value.GetFloat();
+    }
+
     StringHash nameHash(name);
     shaderParameters_[nameHash] = newParam;
 
@@ -1015,11 +1107,21 @@ void Material::SetDepthBias(const BiasParameters& parameters)
     depthBias_.Validate();
 }
 
+void Material::SetAlphaToCoverage(bool enable)
+{
+    alphaToCoverage_ = enable;
+}
+
 void Material::SetRenderOrder(unsigned char order)
 {
     renderOrder_ = order;
 }
 
+void Material::SetOcclusion(bool enable)
+{
+    occlusion_ = enable;
+}
+
 void Material::SetScene(Scene* scene)
 {
     UnsubscribeFromEvent(E_UPDATE);
@@ -1057,9 +1159,13 @@ SharedPtr<Material> Material::Clone(const String& cloneName) const
 
     ret->SetName(cloneName);
     ret->techniques_ = techniques_;
+    ret->vertexShaderDefines_ = vertexShaderDefines_;
+    ret->pixelShaderDefines_ = pixelShaderDefines_;
     ret->shaderParameters_ = shaderParameters_;
     ret->shaderParameterHash_ = shaderParameterHash_;
     ret->textures_ = textures_;
+    ret->depthBias_ = depthBias_;
+    ret->alphaToCoverage_ = alphaToCoverage_;
     ret->occlusion_ = occlusion_;
     ret->specular_ = specular_;
     ret->cullMode_ = cullMode_;
@@ -1146,28 +1252,15 @@ Variant Material::ParseShaderParameterValue(const String& value)
         return ToVectorVariant(valueTrimmed);
 }
 
-void Material::CheckOcclusion()
-{
-    // Determine occlusion by checking the base pass of each technique
-    occlusion_ = false;
-    for (unsigned i = 0; i < techniques_.Size(); ++i)
-    {
-        Technique* tech = techniques_[i].technique_;
-        if (tech)
-        {
-            Pass* pass = tech->GetPass("base");
-            if (pass && pass->GetDepthWrite() && !pass->GetAlphaMask())
-                occlusion_ = true;
-        }
-    }
-}
-
 void Material::ResetToDefaults()
 {
     // Needs to be a no-op when async loading, as this does a GetResource() which is not allowed from worker threads
     if (!Thread::IsMainThread())
         return;
 
+    vertexShaderDefines_.Clear();
+    pixelShaderDefines_.Clear();
+
     SetNumTechniques(1);
     Renderer* renderer = GetSubsystem<Renderer>();
     SetTechnique(0, renderer ? renderer->GetDefaultTechnique() :
@@ -1192,6 +1285,7 @@ void Material::ResetToDefaults()
     fillMode_ = FILL_SOLID;
     depthBias_ = BiasParameters(0.0f, 0.0f);
     renderOrder_ = DEFAULT_RENDER_ORDER;
+    occlusion_ = true;
 
     RefreshShaderParameterHash();
     RefreshMemoryUse();
@@ -1270,6 +1364,24 @@ void Material::HandleAttributeAnimationUpdate(StringHash eventType, VariantMap&
         SetShaderParameterAnimation(finishedNames[i], 0);
 }
 
+void Material::ApplyShaderDefines(unsigned index)
+{
+    if (index == M_MAX_UNSIGNED)
+    {
+        for (unsigned i = 0; i < techniques_.Size(); ++i)
+            ApplyShaderDefines(i);
+        return;
+    }
+
+    if (index >= techniques_.Size() || !techniques_[index].original_)
+        return;
+
+    if (vertexShaderDefines_.Empty() && pixelShaderDefines_.Empty())
+        techniques_[index].technique_ = techniques_[index].original_;
+    else
+        techniques_[index].technique_ = techniques_[index].original_->CloneWithDefines(vertexShaderDefines_, pixelShaderDefines_);
+}
+
 // ATOMIC BEGIN
 const char** Material::GetTextureUnitNames()
 {

+ 29 - 5
Source/Atomic/Graphics/Material.h

@@ -64,6 +64,8 @@ struct TechniqueEntry
 
     /// Technique.
     SharedPtr<Technique> technique_;
+    /// Original technique, in case the material adds shader compilation defines. The modified clones are requested from it.
+    SharedPtr<Technique> original_;
     /// Quality level.
     int qualityLevel_;
     /// LOD distance.
@@ -134,6 +136,10 @@ public:
     void SetNumTechniques(unsigned num);
     /// Set technique.
     void SetTechnique(unsigned index, Technique* tech, unsigned qualityLevel = 0, float lodDistance = 0.0f);
+    /// Set additional vertex shader defines. Separate multiple defines with spaces. Setting defines at the material level causes technique(s) to be cloned as necessary.
+    void SetVertexShaderDefines(const String& defines);
+    /// Set additional pixel shader defines. Separate multiple defines with spaces. Setting defines at the material level causes technique(s) to be cloned as necessary.
+    void SetPixelShaderDefines(const String& defines);
     /// Set shader parameter.
     void SetShaderParameter(const String& name, const Variant& value);
     /// Set shader parameter animation.
@@ -155,10 +161,14 @@ public:
     void SetShadowCullMode(CullMode mode);
     /// Set polygon fill mode. Interacts with the camera's fill mode setting so that the "least filled" mode will be used.
     void SetFillMode(FillMode mode);
-    /// Set depth bias.
+    /// Set depth bias parameters for depth write and compare. Note that the normal offset parameter is not used and will not be saved, as it affects only shadow map sampling during light rendering.
     void SetDepthBias(const BiasParameters& parameters);
+    /// Set alpha-to-coverage mode on all passes.
+    void SetAlphaToCoverage(bool enable);
     /// Set 8-bit render order within pass. Default 128. Lower values will render earlier and higher values later, taking precedence over e.g. state and distance sorting.
     void SetRenderOrder(unsigned char order);
+    /// Set whether to use in occlusion rendering. Default true.
+    void SetOcclusion(bool enable);
     /// Associate the material with a scene to ensure that shader parameter animation happens in sync with scene update, respecting the scene time scale. If no scene is set, the global update events will be used.
     void SetScene(Scene* scene);
     /// Remove shader parameter.
@@ -190,6 +200,11 @@ public:
     /// Return all textures.
     const HashMap<TextureUnit, SharedPtr<Texture> >& GetTextures() const { return textures_; }
 
+    /// Return additional vertex shader defines.
+    const String& GetVertexShaderDefines() const { return vertexShaderDefines_; }
+    /// Return additional pixel shader defines.
+    const String& GetPixelShaderDefines() const { return pixelShaderDefines_; }
+
     /// Return shader parameter.
     const Variant& GetShaderParameter(const String& name) const;
     /// Return shader parameter animation.
@@ -214,6 +229,9 @@ public:
     /// Return depth bias.
     const BiasParameters& GetDepthBias() const { return depthBias_; }
 
+    /// Return alpha-to-coverage mode.
+    bool GetAlphaToCoverage() const { return alphaToCoverage_; }
+
     /// Return render order.
     unsigned char GetRenderOrder() const { return renderOrder_; }
     
@@ -243,19 +261,19 @@ public:
     // ATOMIC END
 
 private:
-    /// Helper function for loading JSON files
+    /// Helper function for loading JSON files.
     bool BeginLoadJSON(Deserializer& source);
-    /// Helper function for loading XML files
+    /// Helper function for loading XML files.
     bool BeginLoadXML(Deserializer& source);
 
-    /// Re-evaluate occlusion rendering.
-    void CheckOcclusion();
     /// Reset to defaults.
     void ResetToDefaults();
     /// Recalculate shader parameter hash.
     void RefreshShaderParameterHash();
     /// Recalculate the memory used by the material.
     void RefreshMemoryUse();
+    /// Reapply shader defines to technique index. By default reapply all.
+    void ApplyShaderDefines(unsigned index = M_MAX_UNSIGNED);
     /// Return shader parameter animation info.
     ShaderParameterAnimationInfo* GetShaderParameterAnimationInfo(const String& name) const;
     /// Update whether should be subscribed to scene or global update events for shader parameter animation.
@@ -271,6 +289,10 @@ private:
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     /// %Shader parameters animation infos.
     HashMap<StringHash, SharedPtr<ShaderParameterAnimationInfo> > shaderParameterAnimationInfos_;
+    /// Vertex shader defines.
+    String vertexShaderDefines_;
+    /// Pixel shader defines.
+    String pixelShaderDefines_;
     /// Normal culling mode.
     CullMode cullMode_;
     /// Culling mode for shadow rendering.
@@ -285,6 +307,8 @@ private:
     unsigned auxViewFrameNumber_;
     /// Shader parameter hash value.
     unsigned shaderParameterHash_;
+    /// Alpha-to-coverage mode.
+    bool alphaToCoverage_;
     /// Render occlusion flag.
     bool occlusion_;
     /// Specular lighting flag.

+ 1 - 1
Source/Atomic/Graphics/OcclusionBuffer.cpp

@@ -125,7 +125,7 @@ void OcclusionBuffer::SetView(Camera* camera)
         return;
 
     view_ = camera->GetView();
-    projection_ = camera->GetProjection(false);
+    projection_ = camera->GetProjection();
     viewProj_ = projection_ * view_;
     nearClip_ = camera->GetNearClip();
     farClip_ = camera->GetFarClip();

Some files were not shown because too many files changed in this diff