Browse Source

Updating to Urho3D master (a5c5956103edeb98c7145b2b934371f078e74b9b)

1901271 Expose mouse position manipulation api in Input class
d4039d5 Add functions for mipmap manipulation to Image.
90efa3b Specify high precision for water shader varyings on GLES to fix shaky reflection/refraction texture sampling. Closes #1593.
5b67d28 Let Box2D world stay at default values for continuous (true) & substepping (false), since substepping enabled leads to erratic behavior under load. Closes #1592.
97eba58 Fix implicit conversion in normal offset shadow calculations. Closes #1586.
9c6e607 Fix memory leak in Dictionary.
00f0a87 Stop existing weight fade when AnimationController::SetWeight() is called, to ensure the set weight is not overridden one frame later. Closes #1583.
7c72c36 Fix LookAt Mixed rotation mode.
b227682 Possibility to enable alpha-to-coverage in either pass or material (all passes). Requires D3D11 or OpenGL and hardware multisampling enabled. Seems to look slightly different on D3D / OpenGL. Fixed depth bias not being copied in Material::Clone(). Closes #1578.
90d7d22 Do not make a value copy of the VariantVector inside the attribute in SceneResolver. Closes #1576.
32ef767 Make a value copy of the node IDs when resolving. Potential solution for #1576.
9114141 Add missing enum string name for serialization.
83acf5b Optional per-texture specifiable max. anisotropy level. Closes #1563.
6323aed Add NavigationPushiness::NAVIGATIONPUSHINESS_NONE
5f7ef27 fix skydome glsl error
19300a3 Add note that ResetTarget() doesn't stop automatically. Do not debug draw a "velocity" target for CrowdAgent. Closes #1572.
6895a51 Pass-level mechanism for eliminating unnecessary shader compilation defines. Closes #1567. Use this mechanism to eliminate PACKEDNORMAL define from depth & shadow pass in normalmapped techniques.
4e5f83a Make it safe to remove CrowdAgent during the reposition event. Closes #1570.
6be0d71 Fix keeping track of RigidBody2D constraints. Closes #1569.
02fae13 Update face camera mode name and add script bindings.
d344cae Add new face camera mode to BillboardSet and Text3D.
2b2f12f Added porting note related to light max extrusion parameter.
2fe4cb0 Add max extrusion parameter for directional lights. Default to 1000. This prevents large far clip causing poor shadow map depth resolution and too strong effect of depth bias parameters, but can be increased if very tall shadows are needed.
623639c Add note of example use of render order.
695f750 Remove specific AlphaMask & NormalPacked techniques, in favor of adding the necessary shader defines in the material instead.
dc90a2d Remove ambiguous weak ptr constructor call.
48f779e Add possibility for materials to define vertex & pixel shader compilation defines, like techniques & passes. Related to #1566. As a consequence, removed the "alphamask" hint from techniques (render order can be used instead) and automatic determination if material should occlude. Fixed bugs in Material JSON save. Allow JSONValue::Size() to also work in object mode. Added porting notes as necessary.
3dfb4a4 Find navigation mesh from the scene in a delayed manner. Plus other codepath consistency fixes for CrowdManager. Closes #1565.
1dbb990 Convert double to float when assigning a shader parameter (possible danger when setting material parameters from Lua)
0201718 Add missing assert to PODVector.
2d59e72 Guard against self-assignment clearing the containers.
7a600be Refactor Vector and PODVector implementation.
000b1af Check for obstacle node moving and update navigation mesh appropriately. Needs a hack to skip this during scene deletion to avoid crash. Closes #1558.
b7c7568 Add to/from string conversions for JSONValueType & JSONNumberType. Minor code cleanup and missing JSONValue script bindings. Closes #1546.
ab40958 Detect Push / Insert to Vector or PODVector from inside itself and make a value copy in that case. Closes #1556.
8bef941 Fix slowed down navigation crowd agent when node dirtied in E_CROWD_AGENT_NODE_REPOSITION. Send the event only after position has been updated. Check for only rotation changing when node dirtied, and do not update position / reset state in that case. Closes #1548.
d72de15 Add note that GetNextLevel() will keep returning 1x1x1 image if necessary. Closes #1554.
5b70c5d Restore earlier method of defining camera frustum when a custom projection matrix is not in use, to improve deferred depth reconstruction accuracy. Related to #1551.
b3964e2 Demonstrate Z fighting elimination by depth bias in 10_RenderToTexture sample. Closes #1543.
79f1a1b added a check for invalid boneIndex caused by geometry key animation
a1aa049 fixed geometry having animation key problem
489f759 Fix slope-scale depth bias potentially not creating new rasterizer state on D3D11 due to poor hashing. Remove mistaken adjustment of slope-scale bias on OpenGL. Now behavior should be uniform between D3D9/D3D11/OpenGL. Closes #1547.
9d5380b Remove extraneous f from GLSL code to satisfy the compiler.
6a72b70 Fix copypaste error in attribute accessor.
273a3ac Add support of free functions as attribute accessors.
6c4a112 Add note on camera projection matrix API change.
d9c0ce7 Send also node-specific 2D collision events. Closes #1535.
341f2d9 Normalize slash / backslash when AnimationController queries for existence of an animation state. Closes #1537.
bc8074a Added SetProjection() to camera, which sets custom projection matrix. This is reset by modifying any of the standard projection parameters (farClip, FOV etc.) Make sure camera's actual far & near clip are based on the projection matrix.
871e52f Base frustum calculation on the projection matrix.
3af3c2b fixed channelIndices[] indexing in ExpandAnimatedChannelKeys() func.
48cd15b Store camera projection matrix as API-independent and convert as necessary (preparation for allowing the user to define a custom projection matrix.) Camera GetProjection() API changed; GetGPUProjection() is now used to get the API-specific projection for use as a shader parameter.
bef8df2 Support defining neighbor terrains to avoid LOD level discontinuities at the edges.
d3cc011 Handle flipping of normals in collision event sending if body pointers were swapped. Do not discard contact results from the "other" manifold, rather concatenate them into the same collision event. Thanks to Enhex for highlighting the issue.
ecfa732 Workaround GCC issue producing shared lib containing undefined symbol. Close #1519.
9bbec4b Explain why normal offset is not saved for materials. Closes #1518.
7b5da66 Skip adding a deferred light volume batch when the light has low 8 bits of lightmask cleared; it would not have effect due to the stencil test. Skip shadow map render when there are no forward & deferred batches using it.
2c8ed38 Capitalize CrowdAgent enum attributes for consistency with other components. Loading is case-insensitive so this does not break existing scenes.
3fe5024 Remove deprecated autoRemove bool from SoundSource. Replace with a more generic AutoRemoveMode enum which is now used by both SoundSource & ParticleEmitter.
a2d86f1 Get screenshot as RGBA on OpenGL ES to fix Android black screenshot.
a76fc0a Undefine GetObject in TileMapLayer2D.h to prevent it getting confused with Win32 API function define. To help, the header should be included after Windows.h is included. Related to #1512.
0991c8e Ensure node's components are properly marked for network update in case node is late added to the scene. Make it impossible for a NetworkState to exist without properly allocated currentValues & previousValues. Fix erroneous comment in C++ version of SceneReplication sample. Code cleanup & minor optimization. Closes #1511.
2f25c3b Add note to discourage use of AddComponent(). Prevent attempting to assign model resource on StaticModel / AnimatedModel when no node set. Closes #1510.
Josh Engebretson 9 years ago
parent
commit
d2e23f99aa
100 changed files with 919 additions and 823 deletions
  1. 2 2
      Resources/CoreData/Shaders/GLSL/BRDF.glsl
  2. 2 2
      Resources/CoreData/Shaders/GLSL/Lighting.glsl
  3. 2 5
      Resources/CoreData/Shaders/GLSL/Skydome.glsl
  4. 8 1
      Resources/CoreData/Shaders/GLSL/Water.glsl
  5. 3 3
      Resources/CoreData/Shaders/HLSL/Lighting.hlsl
  6. 0 9
      Resources/CoreData/Techniques/DiffAOAlphaMask.xml
  7. 0 10
      Resources/CoreData/Techniques/DiffAlphaMask.xml
  8. 0 10
      Resources/CoreData/Techniques/DiffAlphaMaskTranslucent.xml
  9. 0 9
      Resources/CoreData/Techniques/DiffLightMapEnvCube.xml
  10. 2 2
      Resources/CoreData/Techniques/DiffNormal.xml
  11. 2 2
      Resources/CoreData/Techniques/DiffNormalAO.xml
  12. 1 1
      Resources/CoreData/Techniques/DiffNormalAOAlpha.xml
  13. 0 9
      Resources/CoreData/Techniques/DiffNormalAOAlphaMask.xml
  14. 1 1
      Resources/CoreData/Techniques/DiffNormalAlpha.xml
  15. 0 10
      Resources/CoreData/Techniques/DiffNormalAlphaMask.xml
  16. 0 10
      Resources/CoreData/Techniques/DiffNormalAlphaMaskTranslucent.xml
  17. 1 1
      Resources/CoreData/Techniques/DiffNormalAlphaTranslucent.xml
  18. 2 2
      Resources/CoreData/Techniques/DiffNormalEmissive.xml
  19. 1 1
      Resources/CoreData/Techniques/DiffNormalEmissiveAlpha.xml
  20. 2 2
      Resources/CoreData/Techniques/DiffNormalEnvCube.xml
  21. 1 1
      Resources/CoreData/Techniques/DiffNormalEnvCubeAlpha.xml
  22. 0 10
      Resources/CoreData/Techniques/DiffNormalPacked.xml
  23. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedAO.xml
  24. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedAOAlpha.xml
  25. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedAOAlphaMask.xml
  26. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedAlpha.xml
  27. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedAlphaMask.xml
  28. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedAlphaMaskTranslucent.xml
  29. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedAlphaTranslucent.xml
  30. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedEmissive.xml
  31. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedEmissiveAlpha.xml
  32. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedEnvCube.xml
  33. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedEnvCubeAlpha.xml
  34. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedSpec.xml
  35. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedSpecAO.xml
  36. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedSpecAOAlpha.xml
  37. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedSpecAOAlphaMask.xml
  38. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedSpecAlpha.xml
  39. 0 10
      Resources/CoreData/Techniques/DiffNormalPackedSpecAlphaMask.xml
  40. 0 9
      Resources/CoreData/Techniques/DiffNormalPackedSpecEmissive.xml
  41. 0 5
      Resources/CoreData/Techniques/DiffNormalPackedSpecEmissiveAlpha.xml
  42. 2 2
      Resources/CoreData/Techniques/DiffNormalSpec.xml
  43. 2 2
      Resources/CoreData/Techniques/DiffNormalSpecAO.xml
  44. 1 1
      Resources/CoreData/Techniques/DiffNormalSpecAOAlpha.xml
  45. 0 9
      Resources/CoreData/Techniques/DiffNormalSpecAOAlphaMask.xml
  46. 1 1
      Resources/CoreData/Techniques/DiffNormalSpecAlpha.xml
  47. 0 10
      Resources/CoreData/Techniques/DiffNormalSpecAlphaMask.xml
  48. 2 2
      Resources/CoreData/Techniques/DiffNormalSpecEmissive.xml
  49. 1 1
      Resources/CoreData/Techniques/DiffNormalSpecEmissiveAlpha.xml
  50. 0 10
      Resources/CoreData/Techniques/DiffSpecAlphaMask.xml
  51. 0 6
      Resources/CoreData/Techniques/DiffUnlitAlphaMask.xml
  52. 2 2
      Resources/CoreData/Techniques/NoTextureNormal.xml
  53. 1 1
      Resources/CoreData/Techniques/NoTextureNormalAlpha.xml
  54. 0 10
      Resources/CoreData/Techniques/NoTextureNormalPacked.xml
  55. 0 5
      Resources/CoreData/Techniques/NoTextureNormalPackedAlpha.xml
  56. 2 2
      Resources/CoreData/Techniques/PBR/DiffNormalSpecEmissive.xml
  57. 1 1
      Resources/CoreData/Techniques/PBR/DiffNormalSpecEmissiveAlpha.xml
  58. 2 2
      Resources/CoreData/Techniques/PBR/PBRDiffNormal.xml
  59. 1 1
      Resources/CoreData/Techniques/PBR/PBRDiffNormalAlpha.xml
  60. 2 2
      Resources/CoreData/Techniques/PBR/PBRDiffNormalEmissive.xml
  61. 1 1
      Resources/CoreData/Techniques/PBR/PBRDiffNormalEmissiveAlpha.xml
  62. 2 2
      Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpec.xml
  63. 2 2
      Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissive.xml
  64. 1 1
      Resources/CoreData/Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissiveAlpha.xml
  65. 0 10
      Resources/CoreData/Techniques/VegetationDiffAlphaMask.xml
  66. 0 8
      Resources/CoreData/Techniques/VegetationDiffUnlitAlphaMask.xml
  67. 12 6
      Source/Atomic/Atomic2D/Constraint2D.cpp
  68. 2 2
      Source/Atomic/Atomic2D/Constraint2D.h
  69. 21 29
      Source/Atomic/Atomic2D/PhysicsEvents2D.h
  70. 51 11
      Source/Atomic/Atomic2D/PhysicsWorld2D.cpp
  71. 5 3
      Source/Atomic/Atomic2D/RigidBody2D.cpp
  72. 4 0
      Source/Atomic/Atomic2D/TileMapLayer2D.h
  73. 7 26
      Source/Atomic/Audio/SoundSource.cpp
  74. 6 8
      Source/Atomic/Audio/SoundSource.h
  75. 6 2
      Source/Atomic/Container/HashMap.h
  76. 6 2
      Source/Atomic/Container/HashSet.h
  77. 6 3
      Source/Atomic/Container/List.h
  78. 135 142
      Source/Atomic/Container/Vector.h
  79. 2 2
      Source/Atomic/Core/Context.cpp
  80. 6 8
      Source/Atomic/Graphics/AnimatedModel.cpp
  81. 6 1
      Source/Atomic/Graphics/AnimationController.cpp
  82. 4 6
      Source/Atomic/Graphics/Batch.cpp
  83. 12 3
      Source/Atomic/Graphics/BillboardSet.cpp
  84. 7 0
      Source/Atomic/Graphics/BillboardSet.h
  85. 183 141
      Source/Atomic/Graphics/Camera.cpp
  86. 26 12
      Source/Atomic/Graphics/Camera.h
  87. 2 1
      Source/Atomic/Graphics/DebugRenderer.cpp
  88. 2 0
      Source/Atomic/Graphics/DebugRenderer.h
  89. 16 11
      Source/Atomic/Graphics/Graphics.h
  90. 3 2
      Source/Atomic/Graphics/GraphicsDefs.h
  91. 66 1
      Source/Atomic/Graphics/Light.cpp
  92. 30 6
      Source/Atomic/Graphics/Light.h
  93. 135 23
      Source/Atomic/Graphics/Material.cpp
  94. 29 5
      Source/Atomic/Graphics/Material.h
  95. 1 1
      Source/Atomic/Graphics/OcclusionBuffer.cpp
  96. 28 11
      Source/Atomic/Graphics/OpenGL/OGLGraphics.cpp
  97. 2 1
      Source/Atomic/Graphics/OpenGL/OGLTexture.cpp
  98. 23 5
      Source/Atomic/Graphics/ParticleEmitter.cpp
  99. 8 1
      Source/Atomic/Graphics/ParticleEmitter.h
  100. 11 8
      Source/Atomic/Graphics/Renderer.cpp

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

@@ -113,8 +113,8 @@
         float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
         float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
         float fd90 = energyBias + 2.0 * VdotH * VdotH * roughness;
         float fd90 = energyBias + 2.0 * VdotH * VdotH * roughness;
         float f0 = 1.0;
         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;
         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
         #ifdef DIRLIGHT
             float cosAngle = clamp(1.0 - dot(normal, cLightDir), 0.0, 1.0);
             float cosAngle = clamp(1.0 - dot(normal, cLightDir), 0.0, 1.0);
         #else
         #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
         #endif
         projWorldPos.xyz += cosAngle * normalOffsetScale[index] * normal;
         projWorldPos.xyz += cosAngle * normalOffsetScale[index] * normal;
     #endif
     #endif
@@ -353,7 +353,7 @@ float GetShadowDeferred(vec4 projWorldPos, vec3 normal, float depth)
         return GetDirShadowDeferred(projWorldPos, normal, depth);
         return GetDirShadowDeferred(projWorldPos, normal, depth);
     #else
     #else
         #ifdef NORMALOFFSET
         #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;
             projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
         #endif
         #endif
 
 

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

@@ -4,9 +4,6 @@
 
 
 varying vec2 vTexCoord;
 varying vec2 vTexCoord;
 
 
-uniform mat4 gl_ModelViewMatrix;
-uniform mat4 gl_ProjectionMatrix;
-
 void VS()
 void VS()
 {
 {
     mat4 modelMatrix = iModelMatrix;
     mat4 modelMatrix = iModelMatrix;
@@ -17,6 +14,6 @@ void VS()
 }
 }
 
 
 void PS()
 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 "ScreenPos.glsl"
 #include "Fog.glsl"
 #include "Fog.glsl"
 
 
+#ifndef GL_ES
 varying vec4 vScreenPos;
 varying vec4 vScreenPos;
 varying vec2 vReflectUV;
 varying vec2 vReflectUV;
 varying vec2 vWaterUV;
 varying vec2 vWaterUV;
-varying vec3 vNormal;
 varying vec4 vEyeVec;
 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
 #ifdef COMPILEVS
 uniform vec2 cNoiseSpeed;
 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
         #ifdef DIRLIGHT
             float cosAngle = saturate(1.0 - dot(normal, cLightDir));
             float cosAngle = saturate(1.0 - dot(normal, cLightDir));
         #else
         #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
         #endif
 
 
         #if defined(DIRLIGHT)
         #if defined(DIRLIGHT)
@@ -191,7 +191,7 @@ float Chebyshev(float2 Moments, float depth)
 {  
 {  
     //One-tailed inequality valid if depth > Moments.x  
     //One-tailed inequality valid if depth > Moments.x  
     float p = float(depth <= Moments.x);  
     float p = float(depth <= Moments.x);  
-    //Compute variance.  
+    //Compute variance.
     float Variance = Moments.y - (Moments.x * Moments.x); 
     float Variance = Moments.y - (Moments.x * Moments.x); 
 
 
     float minVariance = cVSMShadowParams.x;
     float minVariance = cVSMShadowParams.x;
@@ -351,7 +351,7 @@ float GetShadowDeferred(float4 projWorldPos, float3 normal, float depth)
         return GetDirShadowDeferred(projWorldPos, normal, depth);
         return GetDirShadowDeferred(projWorldPos, normal, depth);
     #else
     #else
         #ifdef NORMALOFFSET
         #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;
             projWorldPos.xyz += cosAngle * cNormalOffsetScalePS.x * normal;
         #endif
         #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="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP" />
     <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>
 </technique>

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

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
     <pass name="material" vsdefines="AO" psdefines="MATERIAL AO" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP AO" psdefines="DEFERRED NORMALMAP AO" />
     <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>
 </technique>

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

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
     <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
     <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>
 </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">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
     <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>
 </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">
 <technique vs="LitSolid" ps="LitSolid" vsdefines="TRANSLUCENT" psdefines="DIFFMAP TRANSLUCENT">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
     <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>
 </technique>

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

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL EMISSIVEMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL EMISSIVEMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP EMISSIVEMAP" />
     <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>
 </technique>

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

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
     <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
     <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>
 </technique>

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

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="MATERIAL NORMALMAP ENVCUBEMAP" depthtest="equal" depthwrite="false" />
     <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="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>
 </technique>

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

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" vsdefines="NORMALMAP ENVCUBEMAP" psdefines="NORMALMAP ENVCUBEMAP" depthwrite="false" blend="alpha" />
     <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="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>
 </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="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL SPECMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP SPECMAP" />
     <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>
 </technique>

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

@@ -4,6 +4,6 @@
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" vsdefines="AO" psdefines="MATERIAL SPECMAP AO" depthtest="equal" depthwrite="false" />
     <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="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>
 </technique>

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

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" vsdefines="AO" psdefines="AO" depthwrite="false" blend="alpha" />
     <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="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>
 </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">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthwrite="false" blend="addalpha" />
     <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>
 </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="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP SPECMAP" />
     <pass name="material" psdefines="MATERIAL SPECMAP EMISSIVEMAP" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL SPECMAP EMISSIVEMAP" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP SPECMAP EMISSIVEMAP" />
     <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>
 </technique>

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

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
 <technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
     <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
     <pass name="alpha" psdefines="EMISSIVEMAP" depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP SPECMAP" depthwrite="false" blend="addalpha" />
     <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>
 </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="prepass" vsdefines="NORMALMAP" psdefines="PREPASS NORMALMAP" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" vsdefines="NORMALMAP" psdefines="DEFERRED NORMALMAP" />
     <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>
 </technique>

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

@@ -1,5 +1,5 @@
 <technique vs="LitSolid" ps="LitSolid">
 <technique vs="LitSolid" ps="LitSolid">
     <pass name="alpha"  depthwrite="false" blend="alpha" />
     <pass name="alpha"  depthwrite="false" blend="alpha" />
     <pass name="litalpha" vsdefines="NORMALMAP" psdefines="NORMALMAP" depthwrite="false" blend="addalpha" />
     <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>
 </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="light" depthtest="equal" depthwrite="false" blend="add" />>
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" />
     <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>
 </technique>

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

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

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

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add" />
     <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>
 </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">
 <technique vs="PBRLitSolid" ps="PBRLitSolid" vsdefines="IBL" psdefines="DIFFMAP NORMALMAP PBR IBL">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>
 </technique>

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

@@ -2,6 +2,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add" />
     <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>
 </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">
 <technique vs="PBRLitSolid" ps="PBRLitSolid"  vsdefines="IBL" psdefines="DIFFMAP NORMALMAP EMISSIVEMAP PBR IBL">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>
 </technique>

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

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add"/>
     <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>
 </technique>

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

@@ -3,6 +3,6 @@
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
     <pass name="deferred" psdefines="DEFERRED" blend="add"/>
     <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>
 </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">
 <technique vs="PBRLitSolid" ps="PBRLitSolid" vsdefines="IBL" psdefines="DIFFMAP NORMALMAP EMISSIVEMAP PBR IBL METALLIC ROUGHNESS">
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="alpha" depthwrite="false" blend="alpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
     <pass name="litalpha" depthwrite="false" blend="addalpha" />
-    <pass name="shadow" vs="Shadow" ps="Shadow" />
+    <pass name="shadow" vs="Shadow" ps="Shadow" psexcludes="PACKEDNORMAL" />
 </technique>
 </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()
 Constraint2D::~Constraint2D()
 {
 {
-    if (ownerBody_)
-        ownerBody_->RemoveConstraint2D(this);
-
-    if (otherBody_)
-        otherBody_->RemoveConstraint2D(this);
-
     ReleaseJoint();
     ReleaseJoint();
 }
 }
 
 
@@ -80,6 +74,12 @@ void Constraint2D::CreateJoint()
     {
     {
         joint_ = physicsWorld_->GetWorld()->CreateJoint(jointDef);
         joint_ = physicsWorld_->GetWorld()->CreateJoint(jointDef);
         joint_->SetUserData(this);
         joint_->SetUserData(this);
+
+        if (ownerBody_)
+            ownerBody_->AddConstraint2D(this);
+
+        if (otherBody_)
+            otherBody_->AddConstraint2D(this);
     }
     }
 }
 }
 
 
@@ -88,6 +88,12 @@ void Constraint2D::ReleaseJoint()
     if (!joint_)
     if (!joint_)
         return;
         return;
 
 
+    if (ownerBody_)
+        ownerBody_->RemoveConstraint2D(this);
+
+    if (otherBody_)
+        otherBody_->RemoveConstraint2D(this);
+
     if (physicsWorld_)
     if (physicsWorld_)
         physicsWorld_->GetWorld()->DestroyJoint(joint_);
         physicsWorld_->GetWorld()->DestroyJoint(joint_);
 
 

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

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

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

@@ -24,40 +24,14 @@
 
 
 #include "../Core/Object.h"
 #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
 // 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.
 // on whether 3D physics support or Bullet has been compiled in.
-// #include "../Physics/PhysicsEvents.h"
-
-// ATOMIC END
+#include "../Physics/PhysicsEvents.h"
 
 
 namespace Atomic
 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_EVENT(E_PHYSICSBEGINCONTACT2D, PhysicsBeginContact2D)
 {
 {
     ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
     ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
@@ -68,7 +42,7 @@ ATOMIC_EVENT(E_PHYSICSBEGINCONTACT2D, PhysicsBeginContact2D)
     ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
     ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
 }
 }
 
 
-/// Physics end contact.
+/// Physics end contact. Global event sent by PhysicsWorld2D.
 ATOMIC_EVENT(E_PHYSICSENDCONTACT2D, PhysicsEndContact2D)
 ATOMIC_EVENT(E_PHYSICSENDCONTACT2D, PhysicsEndContact2D)
 {
 {
     ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
     ATOMIC_PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
@@ -79,4 +53,22 @@ ATOMIC_EVENT(E_PHYSICSENDCONTACT2D, PhysicsEndContact2D)
     ATOMIC_PARAM(P_CONTACT, Contact);              // b2Contact pointer
     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("Draw CenterOfMass", GetDrawCenterOfMass, SetDrawCenterOfMass, bool, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Allow Sleeping", GetAllowSleeping, SetAllowSleeping, 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_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_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("Sub Stepping", GetSubStepping, SetSubStepping, bool, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Gravity", GetGravity, SetGravity, Vector2, DEFAULT_GRAVITY, 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);
     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_PROFILE(UpdatePhysics2D);
 
 
-// ATOMIC BEGIN
-
-    using namespace PhysicsPreStep2D;
-
+    using namespace PhysicsPreStep;
 
 
     VariantMap& eventData = GetEventDataMap();
     VariantMap& eventData = GetEventDataMap();
     eventData[P_WORLD] = this;
     eventData[P_WORLD] = this;
     eventData[P_TIMESTEP] = timeStep;
     eventData[P_TIMESTEP] = timeStep;
-    SendEvent(E_PHYSICSPRESTEP2D, eventData);
-
-// ATOMIC END
+    SendEvent(E_PHYSICSPRESTEP, eventData);
 
 
     physicsStepping_ = true;
     physicsStepping_ = true;
     world_->Step(timeStep, velocityIterations_, positionIterations_);
     world_->Step(timeStep, velocityIterations_, positionIterations_);
@@ -285,10 +285,8 @@ void PhysicsWorld2D::Update(float timeStep)
     SendBeginContactEvents();
     SendBeginContactEvents();
     SendEndContactEvents();
     SendEndContactEvents();
 
 
-// ATOMIC BEGIN
-    using namespace PhysicsPostStep2D;
-    SendEvent(E_PHYSICSPOSTSTEP2D, eventData);
-// ATOMIC END
+    using namespace PhysicsPostStep;
+    SendEvent(E_PHYSICSPOSTSTEP, eventData);
 }
 }
 
 
 void PhysicsWorld2D::DrawDebugGeometry()
 void PhysicsWorld2D::DrawDebugGeometry()
@@ -686,6 +684,7 @@ void PhysicsWorld2D::SendBeginContactEvents()
 
 
     using namespace PhysicsBeginContact2D;
     using namespace PhysicsBeginContact2D;
     VariantMap& eventData = GetEventDataMap();
     VariantMap& eventData = GetEventDataMap();
+    VariantMap nodeEventData;
     eventData[P_WORLD] = this;
     eventData[P_WORLD] = this;
 
 
     for (unsigned i = 0; i < beginContactInfos_.Size(); ++i)
     for (unsigned i = 0; i < beginContactInfos_.Size(); ++i)
@@ -698,6 +697,26 @@ void PhysicsWorld2D::SendBeginContactEvents()
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
 
 
         SendEvent(E_PHYSICSBEGINCONTACT2D, eventData);
         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();
     beginContactInfos_.Clear();
@@ -710,6 +729,7 @@ void PhysicsWorld2D::SendEndContactEvents()
 
 
     using namespace PhysicsEndContact2D;
     using namespace PhysicsEndContact2D;
     VariantMap& eventData = GetEventDataMap();
     VariantMap& eventData = GetEventDataMap();
+    VariantMap nodeEventData;
     eventData[P_WORLD] = this;
     eventData[P_WORLD] = this;
 
 
     for (unsigned i = 0; i < endContactInfos_.Size(); ++i)
     for (unsigned i = 0; i < endContactInfos_.Size(); ++i)
@@ -722,6 +742,26 @@ void PhysicsWorld2D::SendEndContactEvents()
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
         eventData[P_CONTACT] = (void*)contactInfo.contact_;
 
 
         SendEvent(E_PHYSICSENDCONTACT2D, eventData);
         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();
     endContactInfos_.Clear();

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

@@ -402,10 +402,12 @@ void RigidBody2D::ReleaseBody()
     if (!physicsWorld_ || !physicsWorld_->GetWorld())
     if (!physicsWorld_ || !physicsWorld_->GetWorld())
         return;
         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)
     for (unsigned i = 0; i < collisionShapes_.Size(); ++i)

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

@@ -25,6 +25,10 @@
 #include "../Scene/Component.h"
 #include "../Scene/Component.h"
 #include "../Atomic2D/TileMapDefs2D.h"
 #include "../Atomic2D/TileMapDefs2D.h"
 
 
+#ifdef GetObject
+#undef GetObject
+#endif
+
 namespace Atomic
 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])
 #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;
 static const int STREAM_SAFETY_SAMPLES = 4;
 
 
 extern const char* AUDIO_CATEGORY;
 extern const char* AUDIO_CATEGORY;
 
 
+extern const char* autoRemoveModeNames[];
 
 
 SoundSource::SoundSource(Context* context) :
 SoundSource::SoundSource(Context* context) :
     Component(context),
     Component(context),
@@ -108,9 +107,8 @@ SoundSource::SoundSource(Context* context) :
     gain_(1.0f),
     gain_(1.0f),
     attenuation_(1.0f),
     attenuation_(1.0f),
     panning_(0.0f),
     panning_(0.0f),
-    autoRemoveTimer_(0.0f),
-    autoRemove_(false),
     sendFinishedEvent_(false),
     sendFinishedEvent_(false),
+    autoRemove_(REMOVE_DISABLED),
     position_(0),
     position_(0),
     fractPosition_(0),
     fractPosition_(0),
     timePosition_(0.0f),
     timePosition_(0.0f),
@@ -142,7 +140,7 @@ void SoundSource::RegisterObject(Context* context)
     ATOMIC_ATTRIBUTE("Attenuation", float, attenuation_, 1.0f, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Attenuation", float, attenuation_, 1.0f, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Panning", float, panning_, 0.0f, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Panning", float, panning_, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Is Playing", IsPlaying, SetPlayingAttr, bool, false, 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);
     ATOMIC_ACCESSOR_ATTRIBUTE("Play Position", GetPositionAttr, SetPositionAttr, int, 0, AM_FILE);
 }
 }
 
 
@@ -283,12 +281,10 @@ void SoundSource::SetPanning(float panning)
     MarkNetworkUpdate();
     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
 bool SoundSource::IsPlaying() const
@@ -338,23 +334,8 @@ void SoundSource::Update(float timeStep)
 
 
         if (self.Expired())
         if (self.Expired())
             return;
             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);
     void SetAttenuation(float attenuation);
     /// Set stereo panning. -1.0 is full left and 1.0 is full right.
     /// Set stereo panning. -1.0 is full left and 1.0 is full right.
     void SetPanning(float panning);
     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.
     /// Set new playback position.
     void SetPlayPosition(signed char* pos);
     void SetPlayPosition(signed char* pos);
 
 
@@ -99,8 +99,8 @@ public:
     /// Return stereo panning.
     /// Return stereo panning.
     float GetPanning() const { return 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.
     /// Return whether is playing.
     bool IsPlaying() const;
     bool IsPlaying() const;
@@ -138,14 +138,12 @@ protected:
     float attenuation_;
     float attenuation_;
     /// Stereo panning.
     /// Stereo panning.
     float panning_;
     float panning_;
-    /// Autoremove timer.
-    float autoRemoveTimer_;
     /// Effective master gain.
     /// Effective master gain.
     float masterGain_;
     float masterGain_;
-    /// Autoremove flag.
-    bool autoRemove_;
     /// Whether finished event should be sent on playback stop.
     /// Whether finished event should be sent on playback stop.
     bool sendFinishedEvent_;
     bool sendFinishedEvent_;
+    /// Automatic removal mode.
+    AutoRemoveMode autoRemove_;
 
 
 private:
 private:
     /// Play a sound without locking the audio mutex. Called internally.
     /// 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.
     /// Assign a hash map.
     HashMap& operator =(const HashMap<T, U>& rhs)
     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;
         return *this;
     }
     }
 
 

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

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

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

@@ -209,9 +209,12 @@ public:
     /// Assign from another list.
     /// Assign from another list.
     List& operator =(const List<T>& rhs)
     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;
         return *this;
     }
     }
 
 

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

@@ -55,13 +55,21 @@ public:
     /// Construct with initial size.
     /// Construct with initial size.
     explicit Vector(unsigned 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.
     /// Construct with initial data.
     Vector(const T* data, unsigned size)
     Vector(const T* data, unsigned size)
     {
     {
-        Resize(size, data);
+        InsertElements(0, data, data + size);
     }
     }
 
 
     /// Construct from another vector.
     /// Construct from another vector.
@@ -82,15 +90,19 @@ public:
     /// Destruct.
     /// Destruct.
     ~Vector()
     ~Vector()
     {
     {
-        Clear();
+        DestructElements(Buffer(), size_);
         delete[] buffer_;
         delete[] buffer_;
     }
     }
 
 
     /// Assign from another vector.
     /// Assign from another vector.
     Vector<T>& operator =(const Vector<T>& rhs)
     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;
         return *this;
     }
     }
 
 
@@ -188,105 +200,68 @@ public:
 
 
     /// Add an element at the end.
     /// Add an element at the end.
 #ifndef COVERITY_SCAN_MODEL
 #ifndef COVERITY_SCAN_MODEL
-    void Push(const T& value) { Resize(size_ + 1, &value); }
+    void Push(const T& value)
+    {
+        InsertElements(size_, &value, &value + 1);
+    }
 #else
 #else
     // FIXME: Attempt had been made to use this model in the Coverity-Scan model file without any success
     // 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
     // Probably because the model had generated a different mangled name than the one used by static analyzer
     void Push(const T& value)
     void Push(const T& value)
     {
     {
         T array[] = {value};
         T array[] = {value};
-        Resize(size_ + 1, array);
+        InsertElements(size_, array, array + 1);
     }
     }
 #endif
 #endif
 
 
     /// Add another vector at the end.
     /// 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.
     /// Remove the last element.
     void Pop()
     void Pop()
     {
     {
         if (size_)
         if (size_)
-            Resize(size_ - 1, 0);
+            Resize(size_ - 1);
     }
     }
 
 
     /// Insert an element at position.
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     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.
     /// Insert another vector at position.
     void Insert(unsigned pos, const Vector<T>& vector)
     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.
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     Iterator Insert(const Iterator& dest, const T& value)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const Vector<T>& vector)
     Iterator Insert(const Iterator& dest, const Vector<T>& vector)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Erase a range of elements.
@@ -297,7 +272,7 @@ public:
             return;
             return;
 
 
         MoveRange(pos, pos + length, size_ - pos - length);
         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.
     /// 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
             // Swap elements from the end of the array into the empty space
             CopyElements(Buffer() + pos, Buffer() + newSize, length);
             CopyElements(Buffer() + pos, Buffer() + newSize, length);
         }
         }
-        Resize(newSize, 0);
+        Resize(newSize);
     }
     }
 
 
     /// Erase an element by iterator. Return iterator to the next element.
     /// Erase an element by iterator. Return iterator to the next element.
@@ -376,7 +351,7 @@ public:
     void Clear() { Resize(0); }
     void Clear() { Resize(0); }
 
 
     /// Resize the vector.
     /// Resize the vector.
-    void Resize(unsigned newSize) { Resize(newSize, 0); }
+    void Resize(unsigned newSize) { Vector<T> tempBuffer; Resize(newSize, 0, tempBuffer); }
 
 
     /// Set new capacity.
     /// Set new capacity.
     void Reserve(unsigned newCapacity)
     void Reserve(unsigned newCapacity)
@@ -480,8 +455,8 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 
 private:
 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 size shrinks, destruct the removed elements
         if (newSize < size_)
         if (newSize < size_)
@@ -491,6 +466,10 @@ private:
             // Allocate new buffer if necessary and copy the current elements
             // Allocate new buffer if necessary and copy the current elements
             if (newSize > capacity_)
             if (newSize > capacity_)
             {
             {
+                Swap(tempBuffer);
+                size_ = tempBuffer.size_;
+                capacity_ = tempBuffer.capacity_;
+
                 if (!capacity_)
                 if (!capacity_)
                     capacity_ = newSize;
                     capacity_ = newSize;
                 else
                 else
@@ -499,14 +478,11 @@ private:
                         capacity_ += (capacity_ + 1) >> 1;
                         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
             // Initialize the new elements
@@ -516,6 +492,26 @@ private:
         size_ = newSize;
         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.
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     {
     {
@@ -584,11 +580,18 @@ public:
         Resize(size);
         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.
     /// Construct with initial data.
     PODVector(const T* data, unsigned size)
     PODVector(const T* data, unsigned size)
     {
     {
-        Resize(size);
-        CopyElements(Buffer(), data, size);
+        InsertElements(0, data, data + size);
     }
     }
 
 
     /// Construct from another vector.
     /// Construct from another vector.
@@ -615,8 +618,12 @@ public:
     /// Assign from another vector.
     /// Assign from another vector.
     PODVector<T>& operator =(const PODVector<T>& rhs)
     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;
         return *this;
     }
     }
 
 
@@ -715,19 +722,13 @@ public:
     /// Add an element at the end.
     /// Add an element at the end.
     void Push(const T& value)
     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.
     /// Add another vector at the end.
     void Push(const PODVector<T>& vector)
     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.
     /// Remove the last element.
@@ -740,78 +741,41 @@ public:
     /// Insert an element at position.
     /// Insert an element at position.
     void Insert(unsigned pos, const T& value)
     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.
     /// Insert another vector at position.
     void Insert(unsigned pos, const PODVector<T>& vector)
     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.
     /// Insert an element by iterator.
     Iterator Insert(const Iterator& dest, const T& value)
     Iterator Insert(const Iterator& dest, const T& value)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Insert a vector by iterator.
     Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
     Iterator Insert(const Iterator& dest, const PODVector<T>& vector)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Insert a vector partially by iterators.
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     Iterator Insert(const Iterator& dest, const ConstIterator& start, const ConstIterator& end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Insert elements.
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     Iterator Insert(const Iterator& dest, const T* start, const T* end)
     {
     {
         unsigned pos = (unsigned)(dest - Begin());
         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.
     /// Erase a range of elements.
@@ -903,27 +867,8 @@ public:
     /// Resize the vector.
     /// Resize the vector.
     void Resize(unsigned newSize)
     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.
     /// Set new capacity.
@@ -1019,6 +964,54 @@ public:
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
     T* Buffer() const { return reinterpret_cast<T*>(buffer_); }
 
 
 private:
 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.
     /// Move a range of elements within the vector.
     void MoveRange(unsigned dest, unsigned src, unsigned count)
     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)
 void Context::BeginSendEvent(Object* sender, StringHash eventType)
 {
 {
-#ifdef URHO3D_PROFILING
+#ifdef ATOMIC_PROFILING
     if (EventProfiler::IsActive())
     if (EventProfiler::IsActive())
     {
     {
         EventProfiler* eventProfiler = GetSubsystem<EventProfiler>();
         EventProfiler* eventProfiler = GetSubsystem<EventProfiler>();
@@ -302,7 +302,7 @@ void Context::EndSendEvent()
 {
 {
     eventSenders_.Pop();
     eventSenders_.Pop();
 
 
-#ifdef URHO3D_PROFILING
+#ifdef ATOMIC_PROFILING
     if (EventProfiler::IsActive())
     if (EventProfiler::IsActive())
     {
     {
         EventProfiler* eventProfiler = GetSubsystem<EventProfiler>();
         EventProfiler* eventProfiler = GetSubsystem<EventProfiler>();

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

@@ -111,14 +111,6 @@ void AnimatedModel::RegisterObject(Context* context)
         Variant::emptyVariantVector, AM_FILE);
         Variant::emptyVariantVector, AM_FILE);
     ATOMIC_ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
     ATOMIC_ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
         AM_DEFAULT | AM_NOEDIT);
         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)
 bool AnimatedModel::Load(Deserializer& source, bool setInstanceDefault)
@@ -396,6 +388,12 @@ void AnimatedModel::SetModel(Model* model, bool createBones)
     if (model == model_)
     if (model == model_)
         return;
         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
     // Unsubscribe from the reload event of previous model (if any), then subscribe to the new
     if (model_)
     if (model_)
         UnsubscribeFromEvent(model_, E_RELOADFINISHED);
         UnsubscribeFromEvent(model_, E_RELOADFINISHED);

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

@@ -28,6 +28,7 @@
 #include "../Graphics/Animation.h"
 #include "../Graphics/Animation.h"
 #include "../Graphics/AnimationController.h"
 #include "../Graphics/AnimationController.h"
 #include "../Graphics/AnimationState.h"
 #include "../Graphics/AnimationState.h"
+#include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../IO/Log.h"
 #include "../IO/MemoryBuffer.h"
 #include "../IO/MemoryBuffer.h"
 #include "../Resource/ResourceCache.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].setWeight_ = (unsigned char)(weight * 255.0f);
     animations_[index].setWeightTtl_ = COMMAND_STAY_TIME;
     animations_[index].setWeightTtl_ = COMMAND_STAY_TIME;
     ++animations_[index].setWeightRev_;
     ++animations_[index].setWeightRev_;
+    // Cancel any ongoing weight fade
+    animations_[index].targetWeight_ = weight;
+    animations_[index].fadeTime_ = 0.0f;
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
     return true;
     return true;
 }
 }
@@ -912,7 +917,7 @@ void AnimationController::RemoveAnimationState(AnimationState* state)
 
 
 void AnimationController::FindAnimation(const String& name, unsigned& index, AnimationState*& state) const
 void AnimationController::FindAnimation(const String& name, unsigned& index, AnimationState*& state) const
 {
 {
-    StringHash nameHash(name);
+    StringHash nameHash(GetInternalPath(name));
 
 
 // ATOMIC BEGIN
 // 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_;
     const IntRect& viewport = queue->shadowSplits_[split].shadowViewport_;
 
 
     Matrix3x4 shadowView(shadowCamera->GetView());
     Matrix3x4 shadowView(shadowCamera->GetView());
-    Matrix4 shadowProj(shadowCamera->GetProjection());
+    Matrix4 shadowProj(shadowCamera->GetGPUProjection());
     Matrix4 texAdjust(Matrix4::IDENTITY);
     Matrix4 texAdjust(Matrix4::IDENTITY);
 
 
     Texture2D* shadowMap = queue->shadowMap_;
     Texture2D* shadowMap = queue->shadowMap_;
@@ -163,11 +163,9 @@ void Batch::CalculateSortKey()
 {
 {
     unsigned shaderID = (unsigned)(
     unsigned shaderID = (unsigned)(
         ((*((unsigned*)&vertexShader_) / sizeof(ShaderVariation)) + (*((unsigned*)&pixelShader_) / sizeof(ShaderVariation))) &
         ((*((unsigned*)&vertexShader_) / sizeof(ShaderVariation)) + (*((unsigned*)&pixelShader_) / sizeof(ShaderVariation))) &
-        0x3fff);
+        0x7fff);
     if (!isBase_)
     if (!isBase_)
         shaderID |= 0x8000;
         shaderID |= 0x8000;
-    if (pass_ && pass_->GetAlphaMask())
-        shaderID |= 0x4000;
 
 
     unsigned lightQueueID = (unsigned)((*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0xffff);
     unsigned lightQueueID = (unsigned)((*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0xffff);
     unsigned materialID = (unsigned)((*((unsigned*)&material_) / sizeof(Material)) & 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)
             else if (blend == BLEND_ADDALPHA)
                 blend = BLEND_SUBTRACTALPHA;
                 blend = BLEND_SUBTRACTALPHA;
         }
         }
-        graphics->SetBlendMode(blend);
+        graphics->SetBlendMode(blend, pass_->GetAlphaToCoverage() || material_->GetAlphaToCoverage());
 
 
         bool isShadowPass = pass_->GetIndex() == Technique::shadowPassIndex;
         bool isShadowPass = pass_->GetIndex() == Technique::shadowPassIndex;
         CullMode effectiveCullMode = pass_->GetCullMode();
         CullMode effectiveCullMode = pass_->GetCullMode();
@@ -800,7 +798,7 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
             shaderID = j->second_;
             shaderID = j->second_;
         else
         else
         {
         {
-            shaderID = shaderRemapping_[shaderID] = freeShaderID | (shaderID & 0xc0000000);
+            shaderID = shaderRemapping_[shaderID] = freeShaderID | (shaderID & 0x80000000);
             ++freeShaderID;
             ++freeShaderID;
         }
         }
 
 

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

@@ -52,6 +52,7 @@ const char* faceCameraModeNames[] =
     "Rotate Y",
     "Rotate Y",
     "LookAt XYZ",
     "LookAt XYZ",
     "LookAt Y",
     "LookAt Y",
+    "LookAt Mixed",
     "Direction",
     "Direction",
     0
     0
 };
 };
@@ -80,6 +81,7 @@ BillboardSet::BillboardSet(Context* context) :
     sorted_(false),
     sorted_(false),
     fixedScreenSize_(false),
     fixedScreenSize_(false),
     faceCameraMode_(FC_ROTATE_XYZ),
     faceCameraMode_(FC_ROTATE_XYZ),
+    minAngle_(0.0f),
     geometry_(new Geometry(context)),
     geometry_(new Geometry(context)),
     vertexBuffer_(new VertexBuffer(context_)),
     vertexBuffer_(new VertexBuffer(context_)),
     indexBuffer_(new IndexBuffer(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_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Cast Shadows", bool, castShadows_, false, 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_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("Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Shadow Distance", GetShadowDistance, SetShadowDistance, 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);
     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;
     transforms_[0] = relative_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
     // Billboard rotation
     // Billboard rotation
     transforms_[1] = Matrix3x4(Vector3::ZERO, faceCameraMode_ != FC_NONE ? frame.camera_->GetFaceCameraRotation(
     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)
 void BillboardSet::UpdateGeometry(const FrameInfo& frame)
@@ -229,7 +232,7 @@ void BillboardSet::UpdateGeometry(const FrameInfo& frame)
     if (faceCameraMode_ != FC_NONE)
     if (faceCameraMode_ != FC_NONE)
     {
     {
         transforms_[1] = Matrix3x4(Vector3::ZERO, frame.camera_->GetFaceCameraRotation(node_->GetWorldPosition(),
         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())
     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)
 void BillboardSet::SetAnimationLodBias(float bias)
 {
 {
     animationLodBias_ = Max(bias, 0.0f);
     animationLodBias_ = Max(bias, 0.0f);
@@ -753,7 +762,7 @@ void BillboardSet::CalculateFixedScreenSize(const FrameInfo& frame)
 
 
     if (!frame.camera_->IsOrthographic())
     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();
         const Matrix3x4& worldTransform = node_->GetWorldTransform();
         Matrix3x4 billboardTransform = relative_ ? worldTransform : Matrix3x4::IDENTITY;
         Matrix3x4 billboardTransform = relative_ ? worldTransform : Matrix3x4::IDENTITY;
 
 

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

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

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

@@ -72,7 +72,8 @@ Camera::Camera(Context* context) :
     autoAspectRatio_(true),
     autoAspectRatio_(true),
     flipVertical_(false),
     flipVertical_(false),
     useReflection_(false),
     useReflection_(false),
-    useClipping_(false)
+    useClipping_(false),
+    customProjection_(false)
 {
 {
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
     reflectionMatrix_ = reflectionPlane_.ReflectionMatrix();
 }
 }
@@ -241,71 +242,144 @@ void Camera::SetUseClipping(bool enable)
 void Camera::SetClipPlane(const Plane& plane)
 void Camera::SetClipPlane(const Plane& plane)
 {
 {
     clipPlane_ = plane;
     clipPlane_ = plane;
-    projectionDirty_ = true;
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
-
 void Camera::SetFlipVertical(bool enable)
 void Camera::SetFlipVertical(bool enable)
 {
 {
     flipVertical_ = 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();
     MarkNetworkUpdate();
 }
 }
 
 
 float Camera::GetNearClip() const
 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 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)
     if (farClip < nearClip)
         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
     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;
     return ret;
 }
 }
 
 
 Frustum Camera::GetViewSpaceFrustum() const
 Frustum Camera::GetViewSpaceFrustum() const
 {
 {
+    if (projectionDirty_)
+        UpdateProjection();
+
     Frustum ret;
     Frustum ret;
 
 
-    if (!orthographic_)
-        ret.Define(fov_, aspectRatio_, zoom_, GetNearClip(), farClip_);
+    if (customProjection_)
+        ret.Define(projection_);
     else
     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;
     return ret;
 }
 }
 
 
 Frustum Camera::GetViewSpaceSplitFrustum(float nearClip, float farClip) const
 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)
     if (farClip < nearClip)
         farClip = nearClip;
         farClip = nearClip;
 
 
-    if (!orthographic_)
-        ret.Define(fov_, aspectRatio_, zoom_, nearClip, farClip);
+    Frustum ret;
+
+    if (customProjection_)
+        ret.DefineSplit(projection_, nearClip, farClip);
     else
     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;
     return ret;
 }
 }
@@ -322,7 +396,7 @@ Ray Camera::GetScreenRay(float x, float y) const
         return ret;
         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
     // 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;
     x = 2.0f * x - 1.0f;
@@ -342,7 +416,7 @@ Vector2 Camera::WorldToScreenPoint(const Vector3& worldPos) const
 
 
     if (eyeSpacePos.z_ > 0.0f)
     if (eyeSpacePos.z_ > 0.0f)
     {
     {
-        Vector3 screenSpacePos = GetProjection(false) * eyeSpacePos;
+        Vector3 screenSpacePos = GetProjection() * eyeSpacePos;
         ret.x_ = screenSpacePos.x_;
         ret.x_ = screenSpacePos.x_;
         ret.y_ = screenSpacePos.y_;
         ret.y_ = screenSpacePos.y_;
     }
     }
@@ -365,124 +439,38 @@ Vector3 Camera::ScreenToWorldPoint(const Vector3& screenPos) const
     return ray.origin_ + ray.direction_ * rayDistance;
     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_)
     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
 #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;
     return ret;
+#endif
 }
 }
 
 
 void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
 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_)
     if (flipVertical_)
     {
     {
         near.y_ = -near.y_;
         near.y_ = -near.y_;
@@ -532,16 +520,13 @@ float Camera::GetLodDistance(float distance, float scale, float bias) const
         return orthoSize_ / d;
         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_)
     if (!node_)
         return rotation;
         return rotation;
 
 
     switch (mode)
     switch (mode)
     {
     {
-    default:
-        return rotation;
-
     case FC_ROTATE_XYZ:
     case FC_ROTATE_XYZ:
         return node_->GetWorldRotation();
         return node_->GetWorldRotation();
 
 
@@ -560,19 +545,31 @@ Quaternion Camera::GetFaceCameraRotation(const Vector3& position, const Quaterni
         }
         }
 
 
     case FC_LOOKAT_Y:
     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;
             Quaternion lookAt;
-            lookAt.FromLookRotation(lookAtVec);
+            lookAt.FromLookRotation(lookAtVecXZ);
 
 
             Vector3 euler = rotation.EulerAngles();
             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_;
             euler.y_ = lookAt.EulerAngles().y_;
             return Quaternion(euler.x_, euler.y_, euler.z_);
             return Quaternion(euler.x_, euler.y_, euler.z_);
         }
         }
+
+    default:
+        return rotation;
     }
     }
 }
 }
 
 
@@ -584,7 +581,7 @@ Matrix3x4 Camera::GetEffectiveWorldTransform() const
 
 
 bool Camera::IsProjectionValid() const
 bool Camera::IsProjectionValid() const
 {
 {
-    return farClip_ > GetNearClip();
+    return GetFarClip() > GetNearClip();
 }
 }
 
 
 const Matrix3x4& Camera::GetView() const
 const Matrix3x4& Camera::GetView() const
@@ -650,4 +647,49 @@ void Camera::OnMarkedDirty(Node* node)
     viewDirty_ = true;
     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);
     void SetClipPlane(const Plane& plane);
     /// Set vertical flipping mode. Called internally by View to resolve OpenGL / Direct3D9 rendertarget sampling differences.
     /// Set vertical flipping mode. Called internally by View to resolve OpenGL / Direct3D9 rendertarget sampling differences.
     void SetFlipVertical(bool enable);
     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;
     float GetNearClip() const;
 
 
     /// Return vertical field of view in degrees.
     /// Return vertical field of view in degrees.
@@ -133,10 +138,10 @@ public:
 
 
     /// Return frustum in world space.
     /// Return frustum in world space.
     const Frustum& GetFrustum() const;
     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.
     /// Return view matrix.
     const Matrix3x4& GetView() const;
     const Matrix3x4& GetView() const;
     /// Return frustum near and far sizes.
     /// Return frustum near and far sizes.
@@ -149,11 +154,11 @@ public:
     Frustum GetViewSpaceFrustum() const;
     Frustum GetViewSpaceFrustum() const;
     /// Return split frustum in view space.
     /// Return split frustum in view space.
     Frustum GetViewSpaceSplitFrustum(float nearClip, float farClip) const;
     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;
     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;
     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.
     /** 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;
     Vector3 ScreenToWorldPoint(const Vector3& screenPos) const;
@@ -186,7 +191,7 @@ public:
     /// Return a scene node's LOD scaled distance.
     /// Return a scene node's LOD scaled distance.
     float GetLodDistance(float distance, float scale, float bias) const;
     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.
     /// 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.
     /// Get effective world transform for matrix and frustum calculations including reflection but excluding node scaling.
     Matrix3x4 GetEffectiveWorldTransform() const;
     Matrix3x4 GetEffectiveWorldTransform() const;
     /// Return if projection parameters are valid for rendering and raycasting.
     /// Return if projection parameters are valid for rendering and raycasting.
@@ -212,11 +217,14 @@ protected:
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
 
 
 private:
 private:
+    /// Recalculate projection matrix.
+    void UpdateProjection() const;
+
     /// Cached view matrix.
     /// Cached view matrix.
     mutable Matrix3x4 view_;
     mutable Matrix3x4 view_;
     /// Cached projection matrix.
     /// Cached projection matrix.
     mutable Matrix4 projection_;
     mutable Matrix4 projection_;
-    /// Cached frustum.
+    /// Cached world space frustum.
     mutable Frustum frustum_;
     mutable Frustum frustum_;
     /// View matrix dirty flag.
     /// View matrix dirty flag.
     mutable bool viewDirty_;
     mutable bool viewDirty_;
@@ -226,6 +234,10 @@ private:
     mutable bool frustumDirty_;
     mutable bool frustumDirty_;
     /// Orthographic mode flag.
     /// Orthographic mode flag.
     bool orthographic_;
     bool orthographic_;
+    /// Cached actual near clip distance.
+    mutable float projNearClip_;
+    /// Cached actual far clip distance.
+    mutable float projFarClip_;
     /// Near clip distance.
     /// Near clip distance.
     float nearClip_;
     float nearClip_;
     /// Far clip distance.
     /// Far clip distance.
@@ -262,6 +274,8 @@ private:
     bool useReflection_;
     bool useReflection_;
     /// Use custom clip plane flag.
     /// Use custom clip plane flag.
     bool useClipping_;
     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();
     view_ = camera->GetView();
     projection_ = camera->GetProjection();
     projection_ = camera->GetProjection();
+    gpuProjection_ = camera->GetGPUProjection();
     frustum_ = camera->GetFrustum();
     frustum_ = camera->GetFrustum();
 }
 }
 
 
@@ -510,7 +511,7 @@ void DebugRenderer::Render()
     graphics->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
     graphics->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
     graphics->SetShaderParameter(VSP_VIEW, view_);
     graphics->SetShaderParameter(VSP_VIEW, view_);
     graphics->SetShaderParameter(VSP_VIEWINV, view_.Inverse());
     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->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
     graphics->SetVertexBuffer(vertexBuffer_);
     graphics->SetVertexBuffer(vertexBuffer_);
 
 

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

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

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

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

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

@@ -352,10 +352,11 @@ enum FaceCameraMode
     FC_ROTATE_Y,
     FC_ROTATE_Y,
     FC_LOOKAT_XYZ,
     FC_LOOKAT_XYZ,
     FC_LOOKAT_Y,
     FC_LOOKAT_Y,
-    FC_DIRECTION
+    FC_LOOKAT_MIXED,
+    FC_DIRECTION,
 };
 };
 
 
-/// Shadow type
+/// Shadow type.
 enum ShadowQuality
 enum ShadowQuality
 {
 {
     SHADOWQUALITY_SIMPLE_16BIT = 0,
     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_SHADOWQUANTIZE = 0.5f;
 static const float DEFAULT_SHADOWMINVIEW = 3.0f;
 static const float DEFAULT_SHADOWMINVIEW = 3.0f;
 static const float DEFAULT_SHADOWNEARFARRATIO = 0.002f;
 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_SHADOWSPLIT = 1000.0f;
+static const float DEFAULT_TEMPERATURE = 6590.0f;
 
 
 static const char* typeNames[] =
 static const char* typeNames[] =
 {
 {
@@ -92,6 +94,7 @@ Light::Light(Context* context) :
     shadowCascade_(CascadeParameters(DEFAULT_SHADOWSPLIT, 0.0f, 0.0f, 0.0f, DEFAULT_SHADOWFADESTART)),
     shadowCascade_(CascadeParameters(DEFAULT_SHADOWSPLIT, 0.0f, 0.0f, 0.0f, DEFAULT_SHADOWFADESTART)),
     shadowFocus_(FocusParameters(true, true, true, DEFAULT_SHADOWQUANTIZE, DEFAULT_SHADOWMINVIEW)),
     shadowFocus_(FocusParameters(true, true, true, DEFAULT_SHADOWQUANTIZE, DEFAULT_SHADOWMINVIEW)),
     lightQueue_(0),
     lightQueue_(0),
+    temperature_(6590.0f),
     specularIntensity_(DEFAULT_SPECULARINTENSITY),
     specularIntensity_(DEFAULT_SPECULARINTENSITY),
     brightness_(DEFAULT_BRIGHTNESS),
     brightness_(DEFAULT_BRIGHTNESS),
     range_(DEFAULT_RANGE),
     range_(DEFAULT_RANGE),
@@ -102,7 +105,9 @@ Light::Light(Context* context) :
     shadowIntensity_(0.0f),
     shadowIntensity_(0.0f),
     shadowResolution_(1.0f),
     shadowResolution_(1.0f),
     shadowNearFarRatio_(DEFAULT_SHADOWNEARFARRATIO),
     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,
     ATOMIC_ACCESSOR_ATTRIBUTE("Specular Intensity", GetSpecularIntensity, SetSpecularIntensity, float, DEFAULT_SPECULARINTENSITY,
         AM_DEFAULT);
         AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Brightness Multiplier", GetBrightness, SetBrightness, float, DEFAULT_BRIGHTNESS, 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("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 FOV", GetFov, SetFov, float, DEFAULT_LIGHT_FOV, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Spot Aspect Ratio", GetAspectRatio, SetAspectRatio, float, 1.0f, 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("Depth Slope Bias", float, shadowBias_.slopeScaledBias_, DEFAULT_SLOPESCALEDBIAS, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Normal Offset", float, shadowBias_.normalOffset_, DEFAULT_NORMALOFFSET, 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_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("View Mask", int, viewMask_, DEFAULT_VIEWMASK, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Light Mask", int, lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
     ATOMIC_ATTRIBUTE("Light Mask", int, lightMask_, DEFAULT_LIGHTMASK, AM_DEFAULT);
 }
 }
@@ -290,6 +298,18 @@ void Light::SetColor(const Color& color)
     MarkNetworkUpdate();
     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)
 void Light::SetSpecularIntensity(float intensity)
 {
 {
     specularIntensity_ = Max(intensity, 0.0f);
     specularIntensity_ = Max(intensity, 0.0f);
@@ -329,6 +349,12 @@ void Light::SetShadowNearFarRatio(float nearFarRatio)
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
+void Light::SetShadowMaxExtrusion(float extrusion)
+{
+    shadowMaxExtrusion_ = Max(extrusion, 0.0f);
+    MarkNetworkUpdate();
+}
+
 void Light::SetFadeDistance(float distance)
 void Light::SetFadeDistance(float distance)
 {
 {
     fadeDistance_ = Max(distance, 0.0f);
     fadeDistance_ = Max(distance, 0.0f);
@@ -386,6 +412,45 @@ void Light::SetShapeTexture(Texture* texture)
     MarkNetworkUpdate();
     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
 Frustum Light::GetFrustum() const
 {
 {
     // Note: frustum is unaffected by node or parent scale
     // 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;
 static const unsigned MAX_CASCADE_SPLITS = 1;
 #endif
 #endif
 
 
-/// Shadow depth bias parameters.
+/// Depth bias parameters. Used both by lights (for shadow mapping) and materials.
 struct ATOMIC_API BiasParameters
 struct ATOMIC_API BiasParameters
 {
 {
     /// Construct undefined.
     /// Construct undefined.
@@ -178,9 +178,13 @@ public:
     void SetPerVertex(bool enable);
     void SetPerVertex(bool enable);
     /// Set color.
     /// Set color.
     void SetColor(const Color& 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.
     /// Set specular intensity. Zero disables specular calculations.
     void SetSpecularIntensity(float intensity);
     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);
     void SetBrightness(float brightness);
     /// Set range.
     /// Set range.
     void SetRange(float range);
     void SetRange(float range);
@@ -202,8 +206,10 @@ public:
     void SetShadowIntensity(float intensity);
     void SetShadowIntensity(float intensity);
     /// Set shadow resolution between 0.25 - 1.0. Determines the shadow map to use.
     /// Set shadow resolution between 0.25 - 1.0. Determines the shadow map to use.
     void SetShadowResolution(float resolution);
     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);
     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.
     /// Set range attenuation texture.
     void SetRampTexture(Texture* texture);
     void SetRampTexture(Texture* texture);
     /// Set spotlight attenuation texture.
     /// Set spotlight attenuation texture.
@@ -218,14 +224,23 @@ public:
     /// Return color.
     /// Return color.
     const Color& GetColor() const { 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.
     /// Return specular intensity.
     float GetSpecularIntensity() const { return specularIntensity_; }
     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_; }
     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.
     /// Return effective specular intensity, multiplied by absolute value of brightness.
     float GetEffectiveSpecularIntensity() const { return specularIntensity_ * Abs(brightness_); }
     float GetEffectiveSpecularIntensity() const { return specularIntensity_ * Abs(brightness_); }
@@ -263,6 +278,9 @@ public:
     /// Return shadow camera near/far clip distance ratio.
     /// Return shadow camera near/far clip distance ratio.
     float GetShadowNearFarRatio() const { return shadowNearFarRatio_; }
     float GetShadowNearFarRatio() const { return shadowNearFarRatio_; }
 
 
+    /// Return maximum shadow extrusion distance for directional lights.
+    float GetShadowMaxExtrusion() const { return shadowMaxExtrusion_; }
+
     /// Return range attenuation texture.
     /// Return range attenuation texture.
     Texture* GetRampTexture() const { return rampTexture_; }
     Texture* GetRampTexture() const { return rampTexture_; }
 
 
@@ -319,6 +337,8 @@ private:
     LightType lightType_;
     LightType lightType_;
     /// Color.
     /// Color.
     Color color_;
     Color color_;
+    /// Light Temperature.
+    float temperature_;
     /// Shadow depth bias parameters.
     /// Shadow depth bias parameters.
     BiasParameters shadowBias_;
     BiasParameters shadowBias_;
     /// Directional light cascaded shadow parameters.
     /// Directional light cascaded shadow parameters.
@@ -353,8 +373,12 @@ private:
     float shadowResolution_;
     float shadowResolution_;
     /// Shadow camera near/far clip distance ratio.
     /// Shadow camera near/far clip distance ratio.
     float shadowNearFarRatio_;
     float shadowNearFarRatio_;
+    /// Directional shadow max. extrusion distance.
+    float shadowMaxExtrusion_;
     /// Per-vertex lighting flag.
     /// Per-vertex lighting flag.
     bool perVertex_;
     bool perVertex_;
+    /// Use physical light values flag.
+    bool usePhysicalValues_;
 };
 };
 
 
 inline bool CompareLights(Light* lhs, Light* rhs)
 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) :
 TechniqueEntry::TechniqueEntry(Technique* tech, unsigned qualityLevel, float lodDistance) :
     technique_(tech),
     technique_(tech),
+    original_(tech),
     qualityLevel_(qualityLevel),
     qualityLevel_(qualityLevel),
     lodDistance_(lodDistance)
     lodDistance_(lodDistance)
 {
 {
@@ -429,6 +430,13 @@ bool Material::Load(const XMLElement& source)
 
 
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     ResourceCache* cache = GetSubsystem<ResourceCache>();
 
 
+    XMLElement shaderElem = source.GetChild("shader");
+    if (shaderElem)
+    {
+        vertexShaderDefines_ = shaderElem.GetAttribute("vsdefines");
+        pixelShaderDefines_ = shaderElem.GetAttribute("psdefines");
+    }
+
     XMLElement techniqueElem = source.GetChild("technique");
     XMLElement techniqueElem = source.GetChild("technique");
     techniques_.Clear();
     techniques_.Clear();
 
 
@@ -438,7 +446,7 @@ bool Material::Load(const XMLElement& source)
         if (tech)
         if (tech)
         {
         {
             TechniqueEntry newTechnique;
             TechniqueEntry newTechnique;
-            newTechnique.technique_ = tech;
+            newTechnique.technique_ = newTechnique.original_ = tech;
             if (techniqueElem.HasAttribute("quality"))
             if (techniqueElem.HasAttribute("quality"))
                 newTechnique.qualityLevel_ = techniqueElem.GetInt("quality");
                 newTechnique.qualityLevel_ = techniqueElem.GetInt("quality");
             if (techniqueElem.HasAttribute("loddistance"))
             if (techniqueElem.HasAttribute("loddistance"))
@@ -450,6 +458,7 @@ bool Material::Load(const XMLElement& source)
     }
     }
 
 
     SortTechniques();
     SortTechniques();
+    ApplyShaderDefines();
 
 
     XMLElement textureElem = source.GetChild("texture");
     XMLElement textureElem = source.GetChild("texture");
     while (textureElem)
     while (textureElem)
@@ -539,13 +548,20 @@ bool Material::Load(const XMLElement& source)
     if (depthBiasElem)
     if (depthBiasElem)
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
 
 
+    XMLElement alphaToCoverageElem = source.GetChild("alphatocoverage");
+    if (alphaToCoverageElem)
+        SetAlphaToCoverage(alphaToCoverageElem.GetBool("enable"));
+
     XMLElement renderOrderElem = source.GetChild("renderorder");
     XMLElement renderOrderElem = source.GetChild("renderorder");
     if (renderOrderElem)
     if (renderOrderElem)
         SetRenderOrder((unsigned char)renderOrderElem.GetUInt("value"));
         SetRenderOrder((unsigned char)renderOrderElem.GetUInt("value"));
 
 
+    XMLElement occlusionElem = source.GetChild("occlusion");
+    if (occlusionElem)
+        SetOcclusion(occlusionElem.GetBool("enable"));
+
     RefreshShaderParameterHash();
     RefreshShaderParameterHash();
     RefreshMemoryUse();
     RefreshMemoryUse();
-    CheckOcclusion();
     return true;
     return true;
 }
 }
 
 
@@ -561,6 +577,13 @@ bool Material::Load(const JSONValue& source)
 
 
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     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
     // Load techniques
     JSONArray techniquesArray = source.Get("techniques").GetArray();
     JSONArray techniquesArray = source.Get("techniques").GetArray();
     techniques_.Clear();
     techniques_.Clear();
@@ -573,7 +596,7 @@ bool Material::Load(const JSONValue& source)
         if (tech)
         if (tech)
         {
         {
             TechniqueEntry newTechnique;
             TechniqueEntry newTechnique;
-            newTechnique.technique_ = tech;
+            newTechnique.technique_ = newTechnique.original_ = tech;
             JSONValue qualityVal = techVal.Get("quality");
             JSONValue qualityVal = techVal.Get("quality");
             if (!qualityVal.IsNull())
             if (!qualityVal.IsNull())
                 newTechnique.qualityLevel_ = qualityVal.GetInt();
                 newTechnique.qualityLevel_ = qualityVal.GetInt();
@@ -585,6 +608,7 @@ bool Material::Load(const JSONValue& source)
     }
     }
 
 
     SortTechniques();
     SortTechniques();
+    ApplyShaderDefines();
 
 
     // Load textures
     // Load textures
     JSONObject textureObject = source.Get("textures").GetObject();
     JSONObject textureObject = source.Get("textures").GetObject();
@@ -681,13 +705,20 @@ bool Material::Load(const JSONValue& source)
     if (!depthBiasVal.IsNull())
     if (!depthBiasVal.IsNull())
         SetDepthBias(BiasParameters(depthBiasVal.Get("constant").GetFloat(), depthBiasVal.Get("slopescaled").GetFloat()));
         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");
     JSONValue renderOrderVal = source.Get("renderorder");
     if (!renderOrderVal.IsNull())
     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();
     RefreshShaderParameterHash();
     RefreshMemoryUse();
     RefreshMemoryUse();
-    CheckOcclusion();
     return true;
     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
     // Write shader parameters
     for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
     for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
          j != shaderParameters_.End(); ++j)
          j != shaderParameters_.End(); ++j)
@@ -769,10 +810,18 @@ bool Material::Save(XMLElement& dest) const
     depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
     depthBiasElem.SetFloat("constant", depthBias_.constantBias_);
     depthBiasElem.SetFloat("slopescaled", depthBias_.slopeScaledBias_);
     depthBiasElem.SetFloat("slopescaled", depthBias_.slopeScaledBias_);
 
 
+    // Write alpha-to-coverage
+    XMLElement alphaToCoverageElem = dest.CreateChild("alphatocoverage");
+    alphaToCoverageElem.SetBool("enable", alphaToCoverage_);
+
     // Write render order
     // Write render order
     XMLElement renderOrderElem = dest.CreateChild("renderorder");
     XMLElement renderOrderElem = dest.CreateChild("renderorder");
     renderOrderElem.SetUInt("value", renderOrder_);
     renderOrderElem.SetUInt("value", renderOrder_);
 
 
+    // Write occlusion
+    XMLElement occlusionElem = dest.CreateChild("occlusion");
+    occlusionElem.SetBool("enable", occlusion_);
+
     return true;
     return true;
 }
 }
 
 
@@ -805,6 +854,17 @@ bool Material::Save(JSONValue& dest) const
     }
     }
     dest.Set("textures", texturesValue);
     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
     // Write shader parameters
     JSONValue shaderParamsVal;
     JSONValue shaderParamsVal;
     for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
     for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator j = shaderParameters_.Begin();
@@ -849,10 +909,17 @@ bool Material::Save(JSONValue& dest) const
     JSONValue depthBiasValue;
     JSONValue depthBiasValue;
     depthBiasValue.Set("constant", depthBias_.constantBias_);
     depthBiasValue.Set("constant", depthBias_.constantBias_);
     depthBiasValue.Set("slopescaled", depthBias_.slopeScaledBias_);
     depthBiasValue.Set("slopescaled", depthBias_.slopeScaledBias_);
+    dest.Set("depthbias", depthBiasValue);
+
+    // Write alpha-to-coverage
+    dest.Set("alphatocoverage", alphaToCoverage_);
 
 
     // Write render order
     // Write render order
     dest.Set("renderorder", (unsigned) renderOrder_);
     dest.Set("renderorder", (unsigned) renderOrder_);
 
 
+    // Write occlusion
+    dest.Set("occlusion", occlusion_);
+
     return true;
     return true;
 }
 }
 
 
@@ -871,14 +938,39 @@ void Material::SetTechnique(unsigned index, Technique* tech, unsigned qualityLev
         return;
         return;
 
 
     techniques_[index] = TechniqueEntry(tech, qualityLevel, lodDistance);
     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)
 void Material::SetShaderParameter(const String& name, const Variant& value)
 {
 {
     MaterialShaderParameter newParam;
     MaterialShaderParameter newParam;
     newParam.name_ = name;
     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);
     StringHash nameHash(name);
     shaderParameters_[nameHash] = newParam;
     shaderParameters_[nameHash] = newParam;
 
 
@@ -1015,11 +1107,21 @@ void Material::SetDepthBias(const BiasParameters& parameters)
     depthBias_.Validate();
     depthBias_.Validate();
 }
 }
 
 
+void Material::SetAlphaToCoverage(bool enable)
+{
+    alphaToCoverage_ = enable;
+}
+
 void Material::SetRenderOrder(unsigned char order)
 void Material::SetRenderOrder(unsigned char order)
 {
 {
     renderOrder_ = order;
     renderOrder_ = order;
 }
 }
 
 
+void Material::SetOcclusion(bool enable)
+{
+    occlusion_ = enable;
+}
+
 void Material::SetScene(Scene* scene)
 void Material::SetScene(Scene* scene)
 {
 {
     UnsubscribeFromEvent(E_UPDATE);
     UnsubscribeFromEvent(E_UPDATE);
@@ -1057,9 +1159,13 @@ SharedPtr<Material> Material::Clone(const String& cloneName) const
 
 
     ret->SetName(cloneName);
     ret->SetName(cloneName);
     ret->techniques_ = techniques_;
     ret->techniques_ = techniques_;
+    ret->vertexShaderDefines_ = vertexShaderDefines_;
+    ret->pixelShaderDefines_ = pixelShaderDefines_;
     ret->shaderParameters_ = shaderParameters_;
     ret->shaderParameters_ = shaderParameters_;
     ret->shaderParameterHash_ = shaderParameterHash_;
     ret->shaderParameterHash_ = shaderParameterHash_;
     ret->textures_ = textures_;
     ret->textures_ = textures_;
+    ret->depthBias_ = depthBias_;
+    ret->alphaToCoverage_ = alphaToCoverage_;
     ret->occlusion_ = occlusion_;
     ret->occlusion_ = occlusion_;
     ret->specular_ = specular_;
     ret->specular_ = specular_;
     ret->cullMode_ = cullMode_;
     ret->cullMode_ = cullMode_;
@@ -1146,28 +1252,15 @@ Variant Material::ParseShaderParameterValue(const String& value)
         return ToVectorVariant(valueTrimmed);
         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()
 void Material::ResetToDefaults()
 {
 {
     // Needs to be a no-op when async loading, as this does a GetResource() which is not allowed from worker threads
     // Needs to be a no-op when async loading, as this does a GetResource() which is not allowed from worker threads
     if (!Thread::IsMainThread())
     if (!Thread::IsMainThread())
         return;
         return;
 
 
+    vertexShaderDefines_.Clear();
+    pixelShaderDefines_.Clear();
+
     SetNumTechniques(1);
     SetNumTechniques(1);
     Renderer* renderer = GetSubsystem<Renderer>();
     Renderer* renderer = GetSubsystem<Renderer>();
     SetTechnique(0, renderer ? renderer->GetDefaultTechnique() :
     SetTechnique(0, renderer ? renderer->GetDefaultTechnique() :
@@ -1192,6 +1285,7 @@ void Material::ResetToDefaults()
     fillMode_ = FILL_SOLID;
     fillMode_ = FILL_SOLID;
     depthBias_ = BiasParameters(0.0f, 0.0f);
     depthBias_ = BiasParameters(0.0f, 0.0f);
     renderOrder_ = DEFAULT_RENDER_ORDER;
     renderOrder_ = DEFAULT_RENDER_ORDER;
+    occlusion_ = true;
 
 
     RefreshShaderParameterHash();
     RefreshShaderParameterHash();
     RefreshMemoryUse();
     RefreshMemoryUse();
@@ -1270,6 +1364,24 @@ void Material::HandleAttributeAnimationUpdate(StringHash eventType, VariantMap&
         SetShaderParameterAnimation(finishedNames[i], 0);
         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
 // ATOMIC BEGIN
 const char** Material::GetTextureUnitNames()
 const char** Material::GetTextureUnitNames()
 {
 {

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

@@ -64,6 +64,8 @@ struct TechniqueEntry
 
 
     /// Technique.
     /// Technique.
     SharedPtr<Technique> 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.
     /// Quality level.
     int qualityLevel_;
     int qualityLevel_;
     /// LOD distance.
     /// LOD distance.
@@ -134,6 +136,10 @@ public:
     void SetNumTechniques(unsigned num);
     void SetNumTechniques(unsigned num);
     /// Set technique.
     /// Set technique.
     void SetTechnique(unsigned index, Technique* tech, unsigned qualityLevel = 0, float lodDistance = 0.0f);
     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.
     /// Set shader parameter.
     void SetShaderParameter(const String& name, const Variant& value);
     void SetShaderParameter(const String& name, const Variant& value);
     /// Set shader parameter animation.
     /// Set shader parameter animation.
@@ -155,10 +161,14 @@ public:
     void SetShadowCullMode(CullMode mode);
     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.
     /// 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);
     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);
     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.
     /// 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);
     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.
     /// 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);
     void SetScene(Scene* scene);
     /// Remove shader parameter.
     /// Remove shader parameter.
@@ -190,6 +200,11 @@ public:
     /// Return all textures.
     /// Return all textures.
     const HashMap<TextureUnit, SharedPtr<Texture> >& GetTextures() const { return 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.
     /// Return shader parameter.
     const Variant& GetShaderParameter(const String& name) const;
     const Variant& GetShaderParameter(const String& name) const;
     /// Return shader parameter animation.
     /// Return shader parameter animation.
@@ -214,6 +229,9 @@ public:
     /// Return depth bias.
     /// Return depth bias.
     const BiasParameters& GetDepthBias() const { return depthBias_; }
     const BiasParameters& GetDepthBias() const { return depthBias_; }
 
 
+    /// Return alpha-to-coverage mode.
+    bool GetAlphaToCoverage() const { return alphaToCoverage_; }
+
     /// Return render order.
     /// Return render order.
     unsigned char GetRenderOrder() const { return renderOrder_; }
     unsigned char GetRenderOrder() const { return renderOrder_; }
     
     
@@ -243,19 +261,19 @@ public:
     // ATOMIC END
     // ATOMIC END
 
 
 private:
 private:
-    /// Helper function for loading JSON files
+    /// Helper function for loading JSON files.
     bool BeginLoadJSON(Deserializer& source);
     bool BeginLoadJSON(Deserializer& source);
-    /// Helper function for loading XML files
+    /// Helper function for loading XML files.
     bool BeginLoadXML(Deserializer& source);
     bool BeginLoadXML(Deserializer& source);
 
 
-    /// Re-evaluate occlusion rendering.
-    void CheckOcclusion();
     /// Reset to defaults.
     /// Reset to defaults.
     void ResetToDefaults();
     void ResetToDefaults();
     /// Recalculate shader parameter hash.
     /// Recalculate shader parameter hash.
     void RefreshShaderParameterHash();
     void RefreshShaderParameterHash();
     /// Recalculate the memory used by the material.
     /// Recalculate the memory used by the material.
     void RefreshMemoryUse();
     void RefreshMemoryUse();
+    /// Reapply shader defines to technique index. By default reapply all.
+    void ApplyShaderDefines(unsigned index = M_MAX_UNSIGNED);
     /// Return shader parameter animation info.
     /// Return shader parameter animation info.
     ShaderParameterAnimationInfo* GetShaderParameterAnimationInfo(const String& name) const;
     ShaderParameterAnimationInfo* GetShaderParameterAnimationInfo(const String& name) const;
     /// Update whether should be subscribed to scene or global update events for shader parameter animation.
     /// Update whether should be subscribed to scene or global update events for shader parameter animation.
@@ -271,6 +289,10 @@ private:
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     /// %Shader parameters animation infos.
     /// %Shader parameters animation infos.
     HashMap<StringHash, SharedPtr<ShaderParameterAnimationInfo> > shaderParameterAnimationInfos_;
     HashMap<StringHash, SharedPtr<ShaderParameterAnimationInfo> > shaderParameterAnimationInfos_;
+    /// Vertex shader defines.
+    String vertexShaderDefines_;
+    /// Pixel shader defines.
+    String pixelShaderDefines_;
     /// Normal culling mode.
     /// Normal culling mode.
     CullMode cullMode_;
     CullMode cullMode_;
     /// Culling mode for shadow rendering.
     /// Culling mode for shadow rendering.
@@ -285,6 +307,8 @@ private:
     unsigned auxViewFrameNumber_;
     unsigned auxViewFrameNumber_;
     /// Shader parameter hash value.
     /// Shader parameter hash value.
     unsigned shaderParameterHash_;
     unsigned shaderParameterHash_;
+    /// Alpha-to-coverage mode.
+    bool alphaToCoverage_;
     /// Render occlusion flag.
     /// Render occlusion flag.
     bool occlusion_;
     bool occlusion_;
     /// Specular lighting flag.
     /// Specular lighting flag.

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

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

+ 28 - 11
Source/Atomic/Graphics/OpenGL/OGLGraphics.cpp

@@ -255,6 +255,7 @@ Graphics::Graphics(Context* context_) :
     shadowMapFormat_(GL_DEPTH_COMPONENT16),
     shadowMapFormat_(GL_DEPTH_COMPONENT16),
     hiresShadowMapFormat_(GL_DEPTH_COMPONENT24),
     hiresShadowMapFormat_(GL_DEPTH_COMPONENT24),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
+    defaultTextureAnisotropy_(4),
     shaderPath_("Shaders/GLSL/"),
     shaderPath_("Shaders/GLSL/"),
     shaderExtension_(".glsl"),
     shaderExtension_(".glsl"),
     orientations_("LandscapeLeft LandscapeRight"),
     orientations_("LandscapeLeft LandscapeRight"),
@@ -602,8 +603,15 @@ bool Graphics::TakeScreenShot(Image* destImage)
 
 
     ResetRenderTargets();
     ResetRenderTargets();
 
 
+#ifndef GL_ES_VERSION_2_0
     destImage->SetSize(width_, height_, 3);
     destImage->SetSize(width_, height_, 3);
     glReadPixels(0, 0, width_, height_, GL_RGB, GL_UNSIGNED_BYTE, destImage->GetData());
     glReadPixels(0, 0, width_, height_, GL_RGB, GL_UNSIGNED_BYTE, destImage->GetData());
+#else
+    // Use RGBA format on OpenGL ES, as otherwise (at least on Android) the produced image is all black
+    destImage->SetSize(width_, height_, 4);
+    glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, destImage->GetData());
+#endif
+
     // On OpenGL we need to flip the image vertically after reading
     // On OpenGL we need to flip the image vertically after reading
     destImage->FlipVertical();
     destImage->FlipVertical();
 
 
@@ -1507,11 +1515,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();
         SetTextureParametersDirty();
     }
     }
 }
 }
@@ -1648,7 +1658,7 @@ void Graphics::SetViewport(const IntRect& rect)
     SetScissorTest(false);
     SetScissorTest(false);
 }
 }
 
 
-void Graphics::SetBlendMode(BlendMode mode)
+void Graphics::SetBlendMode(BlendMode mode, bool alphaToCoverage)
 {
 {
     if (mode != blendMode_)
     if (mode != blendMode_)
     {
     {
@@ -1663,6 +1673,16 @@ void Graphics::SetBlendMode(BlendMode mode)
 
 
         blendMode_ = mode;
         blendMode_ = mode;
     }
     }
+
+    if (alphaToCoverage != alphaToCoverage_)
+    {
+        if (alphaToCoverage)
+            glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+        else
+            glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+
+        alphaToCoverage_ = alphaToCoverage;
+    }
 }
 }
 
 
 void Graphics::SetColorWrite(bool enable)
 void Graphics::SetColorWrite(bool enable)
@@ -1703,9 +1723,8 @@ void Graphics::SetDepthBias(float constantBias, float slopeScaledBias)
         if (slopeScaledBias != 0.0f)
         if (slopeScaledBias != 0.0f)
         {
         {
             // OpenGL constant bias is unreliable and dependant on depth buffer bitdepth, apply in the projection matrix instead
             // OpenGL constant bias is unreliable and dependant on depth buffer bitdepth, apply in the projection matrix instead
-            float adjustedSlopeScaledBias = slopeScaledBias + 1.0f;
             glEnable(GL_POLYGON_OFFSET_FILL);
             glEnable(GL_POLYGON_OFFSET_FILL);
-            glPolygonOffset(adjustedSlopeScaledBias, 0.0f);
+            glPolygonOffset(slopeScaledBias, 0.0f);
         }
         }
         else
         else
             glDisable(GL_POLYGON_OFFSET_FILL);
             glDisable(GL_POLYGON_OFFSET_FILL);
@@ -2430,7 +2449,6 @@ void Graphics::Restore()
 void Graphics::MarkFBODirty()
 void Graphics::MarkFBODirty()
 {
 {
     impl_->fboDirty_ = true;
     impl_->fboDirty_ = true;
-
 }
 }
 
 
 void Graphics::SetVBO(unsigned object)
 void Graphics::SetVBO(unsigned object)
@@ -2727,9 +2745,8 @@ void Graphics::CheckFeatureSupport()
     }
     }
 #endif
 #endif
 
 
-// Consider OpenGL shadows always hardware sampled, if supported at all
-hardwareShadowSupport_ = shadowMapFormat_ != 0;
-
+    // Consider OpenGL shadows always hardware sampled, if supported at all
+    hardwareShadowSupport_ = shadowMapFormat_ != 0;
 }
 }
 
 
 void Graphics::PrepareDraw()
 void Graphics::PrepareDraw()
@@ -3070,7 +3087,7 @@ void Graphics::ResetCachedState()
     vertexShader_ = 0;
     vertexShader_ = 0;
     pixelShader_ = 0;
     pixelShader_ = 0;
     blendMode_ = BLEND_REPLACE;
     blendMode_ = BLEND_REPLACE;
-    textureAnisotropy_ = 1;
+    alphaToCoverage_ = false;
     colorWrite_ = true;
     colorWrite_ = true;
     cullMode_ = CULL_NONE;
     cullMode_ = CULL_NONE;
     constantDepthBias_ = 0.0f;
     constantDepthBias_ = 0.0f;

+ 2 - 1
Source/Atomic/Graphics/OpenGL/OGLTexture.cpp

@@ -133,8 +133,9 @@ void Texture::UpdateParameters()
     // Anisotropy
     // Anisotropy
     if (graphics_->GetAnisotropySupport())
     if (graphics_->GetAnisotropySupport())
     {
     {
+        unsigned maxAnisotropy = anisotropy_ ? anisotropy_ : graphics_->GetDefaultTextureAnisotropy();
         glTexParameterf(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT,
         glTexParameterf(target_, GL_TEXTURE_MAX_ANISOTROPY_EXT,
-            filterMode == FILTER_ANISOTROPIC ? (float)graphics_->GetTextureAnisotropy() : 1.0f);
+            filterMode == FILTER_ANISOTROPIC ? (float)maxAnisotropy : 1.0f);
     }
     }
 
 
     // Shadow compare
     // Shadow compare

+ 23 - 5
Source/Atomic/Graphics/ParticleEmitter.cpp

@@ -41,6 +41,8 @@ extern const char* GEOMETRY_CATEGORY;
 extern const char* faceCameraModeNames[];
 extern const char* faceCameraModeNames[];
 static const unsigned MAX_PARTICLES_IN_FRAME = 100;
 static const unsigned MAX_PARTICLES_IN_FRAME = 100;
 
 
+extern const char* autoRemoveModeNames[];
+
 ParticleEmitter::ParticleEmitter(Context* context) :
 ParticleEmitter::ParticleEmitter(Context* context) :
     BillboardSet(context),
     BillboardSet(context),
     periodTimer_(0.0f),
     periodTimer_(0.0f),
@@ -50,7 +52,8 @@ ParticleEmitter::ParticleEmitter(Context* context) :
     emitting_(true),
     emitting_(true),
     needUpdate_(false),
     needUpdate_(false),
     serializeParticles_(true),
     serializeParticles_(true),
-    sendFinishEvent_(true)
+    sendFinishedEvent_(true),
+    autoRemove_(REMOVE_DISABLED)
 {
 {
     SetNumParticles(DEFAULT_NUM_PARTICLES);
     SetNumParticles(DEFAULT_NUM_PARTICLES);
 }
 }
@@ -74,6 +77,7 @@ void ParticleEmitter::RegisterObject(Context* context)
     ATOMIC_ATTRIBUTE("Is Emitting", bool, emitting_, true, AM_FILE);
     ATOMIC_ATTRIBUTE("Is Emitting", bool, emitting_, true, AM_FILE);
     ATOMIC_ATTRIBUTE("Period Timer", float, periodTimer_, 0.0f, AM_FILE | AM_NOEDIT);
     ATOMIC_ATTRIBUTE("Period Timer", float, periodTimer_, 0.0f, AM_FILE | AM_NOEDIT);
     ATOMIC_ATTRIBUTE("Emission Timer", float, emissionTimer_, 0.0f, AM_FILE | AM_NOEDIT);
     ATOMIC_ATTRIBUTE("Emission Timer", float, emissionTimer_, 0.0f, AM_FILE | AM_NOEDIT);
+    ATOMIC_ENUM_ATTRIBUTE("Autoremove Mode", autoRemove_, autoRemoveModeNames, REMOVE_DISABLED, AM_DEFAULT);
     ATOMIC_COPY_BASE_ATTRIBUTES(Drawable);
     ATOMIC_COPY_BASE_ATTRIBUTES(Drawable);
     ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Particles", GetParticlesAttr, SetParticlesAttr, VariantVector, Variant::emptyVariantVector,
     ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Particles", GetParticlesAttr, SetParticlesAttr, VariantVector, Variant::emptyVariantVector,
         AM_FILE | AM_NOEDIT);
         AM_FILE | AM_NOEDIT);
@@ -128,7 +132,7 @@ void ParticleEmitter::Update(const FrameInfo& frame)
         if (inactiveTime && periodTimer_ >= inactiveTime)
         if (inactiveTime && periodTimer_ >= inactiveTime)
         {
         {
             emitting_ = true;
             emitting_ = true;
-            sendFinishEvent_ = true;
+            sendFinishedEvent_ = true;
             periodTimer_ -= inactiveTime;
             periodTimer_ -= inactiveTime;
         }
         }
         // If emitter has an indefinite stop interval, keep period timer reset to allow restarting emission in the editor
         // If emitter has an indefinite stop interval, keep period timer reset to allow restarting emission in the editor
@@ -295,7 +299,7 @@ void ParticleEmitter::SetEmitting(bool enable)
     if (enable != emitting_)
     if (enable != emitting_)
     {
     {
         emitting_ = enable;
         emitting_ = enable;
-        sendFinishEvent_ = enable;
+        sendFinishedEvent_ = enable;
         periodTimer_ = 0.0f;
         periodTimer_ = 0.0f;
         // Note: network update does not need to be marked as this is a file only attribute
         // Note: network update does not need to be marked as this is a file only attribute
     }
     }
@@ -307,6 +311,12 @@ void ParticleEmitter::SetSerializeParticles(bool enable)
     // Note: network update does not need to be marked as this is a file only attribute
     // Note: network update does not need to be marked as this is a file only attribute
 }
 }
 
 
+void ParticleEmitter::SetAutoRemoveMode(AutoRemoveMode mode)
+{
+    autoRemove_ = mode;
+    MarkNetworkUpdate();
+}
+
 void ParticleEmitter::ResetEmissionTimer()
 void ParticleEmitter::ResetEmissionTimer()
 {
 {
     emissionTimer_ = 0.0f;
     emissionTimer_ = 0.0f;
@@ -538,7 +548,7 @@ void ParticleEmitter::HandleScenePostUpdate(StringHash eventType, VariantMap& ev
         MarkForUpdate();
         MarkForUpdate();
     }
     }
 
 
-    if (node_ && !emitting_ && sendFinishEvent_)
+    if (node_ && !emitting_ && sendFinishedEvent_)
     {
     {
         // Send finished event only once all billboards are gone
         // Send finished event only once all billboards are gone
         bool hasEnabledBillboards = false;
         bool hasEnabledBillboards = false;
@@ -554,7 +564,10 @@ void ParticleEmitter::HandleScenePostUpdate(StringHash eventType, VariantMap& ev
 
 
         if (!hasEnabledBillboards)
         if (!hasEnabledBillboards)
         {
         {
-            sendFinishEvent_ = false;
+            sendFinishedEvent_ = false;
+
+            // Make a weak pointer to self to check for destruction during event handling
+            WeakPtr<ParticleEmitter> self(this);
 
 
             using namespace ParticleEffectFinished;
             using namespace ParticleEffectFinished;
 
 
@@ -563,6 +576,11 @@ void ParticleEmitter::HandleScenePostUpdate(StringHash eventType, VariantMap& ev
             eventData[P_EFFECT] = effect_;
             eventData[P_EFFECT] = effect_;
 
 
             node_->SendEvent(E_PARTICLEEFFECTFINISHED, eventData);
             node_->SendEvent(E_PARTICLEEFFECTFINISHED, eventData);
+
+            if (self.Expired())
+                return;
+
+            DoAutoRemove(autoRemove_);
         }
         }
     }
     }
 }
 }

+ 8 - 1
Source/Atomic/Graphics/ParticleEmitter.h

@@ -76,6 +76,8 @@ public:
     void SetEmitting(bool enable);
     void SetEmitting(bool enable);
     /// Set whether particles should be serialized. Default true, set false to reduce scene file size.
     /// Set whether particles should be serialized. Default true, set false to reduce scene file size.
     void SetSerializeParticles(bool enable);
     void SetSerializeParticles(bool enable);
+    //// Set to remove either the emitter component or its owner node from the scene automatically on particle effect completion. Disabled by default.
+    void SetAutoRemoveMode(AutoRemoveMode mode);
     /// Reset the emission period timer.
     /// Reset the emission period timer.
     void ResetEmissionTimer();
     void ResetEmissionTimer();
     /// Remove all current particles.
     /// Remove all current particles.
@@ -97,6 +99,9 @@ public:
     /// Return whether particles are to be serialized.
     /// Return whether particles are to be serialized.
     bool GetSerializeParticles() const { return serializeParticles_; }
     bool GetSerializeParticles() const { return serializeParticles_; }
 
 
+    /// Return automatic removal mode on particle effect completion.
+    AutoRemoveMode GetAutoRemoveMode() const { return autoRemove_; }
+
     /// Set particles effect attribute.
     /// Set particles effect attribute.
     void SetEffectAttr(const ResourceRef& value);
     void SetEffectAttr(const ResourceRef& value);
     /// Set particles effect attribute.
     /// Set particles effect attribute.
@@ -142,7 +147,9 @@ private:
     /// Serialize particles flag.
     /// Serialize particles flag.
     bool serializeParticles_;
     bool serializeParticles_;
     /// Ready to send effect finish event flag.
     /// Ready to send effect finish event flag.
-    bool sendFinishEvent_;
+    bool sendFinishedEvent_;
+    /// Automatic removal mode.
+    AutoRemoveMode autoRemove_;
 };
 };
 
 
 }
 }

+ 11 - 8
Source/Atomic/Graphics/Renderer.cpp

@@ -708,7 +708,7 @@ void Renderer::Render()
         SetIndirectionTextureData();
         SetIndirectionTextureData();
 
 
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
-    graphics_->SetTextureAnisotropy((unsigned)textureAnisotropy_);
+    graphics_->SetDefaultTextureAnisotropy((unsigned)textureAnisotropy_);
 
 
     // If no views that render to the backbuffer, clear the screen so that e.g. the UI is not rendered on top of previous frame
     // If no views that render to the backbuffer, clear the screen so that e.g. the UI is not rendered on top of previous frame
     bool hasBackbufferViews = false;
     bool hasBackbufferViews = false;
@@ -1400,7 +1400,7 @@ void Renderer::OptimizeLightByStencil(Light* light, Camera* camera)
 
 
         Geometry* geometry = GetLightGeometry(light);
         Geometry* geometry = GetLightGeometry(light);
         const Matrix3x4& view = camera->GetView();
         const Matrix3x4& view = camera->GetView();
-        const Matrix4& projection = camera->GetProjection();
+        const Matrix4& projection = camera->GetGPUProjection();
         Vector3 cameraPos = camera->GetNode()->GetWorldPosition();
         Vector3 cameraPos = camera->GetNode()->GetWorldPosition();
         float lightDist;
         float lightDist;
 
 
@@ -1665,6 +1665,9 @@ void Renderer::LoadPassShaders(Pass* pass)
         extraShaderDefines = " VSM_SHADOW ";
         extraShaderDefines = " VSM_SHADOW ";
     }
     }
 
 
+    String vsDefines = pass->GetEffectiveVertexShaderDefines();
+    String psDefines = pass->GetEffectivePixelShaderDefines();
+
     if (pass->GetLightingMode() == LIGHTING_PERPIXEL)
     if (pass->GetLightingMode() == LIGHTING_PERPIXEL)
     {
     {
         // Load forward pixel lit variations
         // Load forward pixel lit variations
@@ -1677,7 +1680,7 @@ void Renderer::LoadPassShaders(Pass* pass)
             unsigned l = j % MAX_LIGHT_VS_VARIATIONS;
             unsigned l = j % MAX_LIGHT_VS_VARIATIONS;
 
 
             vertexShaders[j] = graphics_->GetShader(VS, pass->GetVertexShader(),
             vertexShaders[j] = graphics_->GetShader(VS, pass->GetVertexShader(),
-                pass->GetVertexShaderDefines() + extraShaderDefines + lightVSVariations[l] + geometryVSVariations[g]);
+                vsDefines + extraShaderDefines + lightVSVariations[l] + geometryVSVariations[g]);
         }
         }
         for (unsigned j = 0; j < MAX_LIGHT_PS_VARIATIONS * 2; ++j)
         for (unsigned j = 0; j < MAX_LIGHT_PS_VARIATIONS * 2; ++j)
         {
         {
@@ -1687,12 +1690,12 @@ void Renderer::LoadPassShaders(Pass* pass)
             if (l & LPS_SHADOW)
             if (l & LPS_SHADOW)
             {
             {
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(),
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(),
-                    pass->GetPixelShaderDefines() + extraShaderDefines + lightPSVariations[l] + GetShadowVariations() +
+                    psDefines + extraShaderDefines + lightPSVariations[l] + GetShadowVariations() +
                     heightFogVariations[h]);
                     heightFogVariations[h]);
             }
             }
             else
             else
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(),
                 pixelShaders[j] = graphics_->GetShader(PS, pass->GetPixelShader(),
-                    pass->GetPixelShaderDefines() + extraShaderDefines + lightPSVariations[l] + heightFogVariations[h]);
+                    psDefines + extraShaderDefines + lightPSVariations[l] + heightFogVariations[h]);
         }
         }
     }
     }
     else
     else
@@ -1706,7 +1709,7 @@ void Renderer::LoadPassShaders(Pass* pass)
                 unsigned g = j / MAX_VERTEXLIGHT_VS_VARIATIONS;
                 unsigned g = j / MAX_VERTEXLIGHT_VS_VARIATIONS;
                 unsigned l = j % MAX_VERTEXLIGHT_VS_VARIATIONS;
                 unsigned l = j % MAX_VERTEXLIGHT_VS_VARIATIONS;
                 vertexShaders[j] = graphics_->GetShader(VS, pass->GetVertexShader(),
                 vertexShaders[j] = graphics_->GetShader(VS, pass->GetVertexShader(),
-                    pass->GetVertexShaderDefines() + extraShaderDefines + vertexLightVSVariations[l] + geometryVSVariations[g]);
+                    vsDefines + extraShaderDefines + vertexLightVSVariations[l] + geometryVSVariations[g]);
             }
             }
         }
         }
         else
         else
@@ -1715,7 +1718,7 @@ void Renderer::LoadPassShaders(Pass* pass)
             for (unsigned j = 0; j < MAX_GEOMETRYTYPES; ++j)
             for (unsigned j = 0; j < MAX_GEOMETRYTYPES; ++j)
             {
             {
                 vertexShaders[j] = graphics_->GetShader(VS, pass->GetVertexShader(),
                 vertexShaders[j] = graphics_->GetShader(VS, pass->GetVertexShader(),
-                    pass->GetVertexShaderDefines() + extraShaderDefines + geometryVSVariations[j]);
+                    vsDefines + extraShaderDefines + geometryVSVariations[j]);
             }
             }
         }
         }
 
 
@@ -1723,7 +1726,7 @@ void Renderer::LoadPassShaders(Pass* pass)
         for (unsigned j = 0; j < 2; ++j)
         for (unsigned j = 0; j < 2; ++j)
         {
         {
             pixelShaders[j] =
             pixelShaders[j] =
-                graphics_->GetShader(PS, pass->GetPixelShader(), pass->GetPixelShaderDefines() + extraShaderDefines + heightFogVariations[j]);
+                graphics_->GetShader(PS, pass->GetPixelShader(), psDefines + extraShaderDefines + heightFogVariations[j]);
         }
         }
     }
     }
 
 

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