Browse Source

Added more default materials.
Re-added fast square root & fast inverse square root, and fast variations of normalizing vectors & quaternions.
Skinning & instancing vertex shaders are now chosen automatically without the material having to specify them.
Refactored Button logic.

Lasse Öörni 15 years ago
parent
commit
347fe0815d
48 changed files with 417 additions and 291 deletions
  1. 1 4
      Bin/Data/Materials/Default.xml
  2. 8 0
      Bin/Data/Materials/DefaultAlpha.xml
  3. 1 4
      Bin/Data/Materials/DefaultDiff.xml
  4. 8 0
      Bin/Data/Materials/DefaultDiffAlpha.xml
  5. 12 0
      Bin/Data/Materials/DefaultDiffAlphaMask.xml
  6. 0 15
      Bin/Data/Materials/DefaultDiffInstanced.xml
  7. 12 0
      Bin/Data/Materials/DefaultDiffNormal.xml
  8. 12 0
      Bin/Data/Materials/DefaultDiffNormalAlphaMask.xml
  9. 0 14
      Bin/Data/Materials/DefaultDiffSkinned.xml
  10. 0 15
      Bin/Data/Materials/DefaultInstanced.xml
  11. 0 15
      Bin/Data/Materials/DefaultSkinned.xml
  12. 1 1
      Bin/Data/Materials/Jack.xml
  13. 0 3
      Bin/Data/Materials/JackStatic.xml
  14. 1 1
      Bin/Data/Materials/Mushroom.xml
  15. 0 7
      Bin/Data/Materials/MushroomInstanced.xml
  16. 0 7
      Bin/Data/Materials/MushroomStatic.xml
  17. 1 1
      Bin/Data/Materials/Ninja.xml
  18. 1 13
      Bin/Data/Materials/Test.xml
  19. 2 1
      Bin/Data/UI/UI.xml
  20. 1 1
      Engine/Engine/RegisterEngine.cpp
  21. 4 5
      Engine/Engine/RegisterUI.cpp
  22. 33 1
      Engine/Math/MathDefs.h
  23. 23 0
      Engine/Math/Quaternion.h
  24. 21 0
      Engine/Math/Vector2.h
  25. 22 0
      Engine/Math/Vector3.h
  26. 2 2
      Engine/Physics/RigidBody.cpp
  27. 2 0
      Engine/Renderer/AnimatedModel.h
  28. 102 72
      Engine/Renderer/AnimationState.cpp
  29. 2 2
      Engine/Renderer/AnimationState.h
  30. 1 1
      Engine/Renderer/Batch.cpp
  31. 1 1
      Engine/Renderer/Camera.cpp
  32. 1 1
      Engine/Renderer/DeferredView.cpp
  33. 1 1
      Engine/Renderer/ForwardView.cpp
  34. 2 0
      Engine/Renderer/GeometryNode.h
  35. 2 0
      Engine/Renderer/InstancedModel.h
  36. 57 34
      Engine/Renderer/Pipeline.cpp
  37. 9 0
      Engine/Renderer/RendererDefs.h
  38. 2 2
      Engine/Renderer/View.cpp
  39. 1 1
      Engine/Renderer/VolumeNode.cpp
  40. 42 39
      Engine/UI/Button.cpp
  41. 14 15
      Engine/UI/Button.h
  42. 1 1
      Engine/UI/UI.cpp
  43. 1 1
      Engine/UI/UIElement.cpp
  44. 1 1
      Engine/UI/UIElement.h
  45. 3 3
      Examples/Test/Application.cpp
  46. 2 2
      SourceAssets/Shaders/Deferred/GBuffer.xml
  47. 3 3
      SourceAssets/Shaders/Forward.xml
  48. 1 1
      SourceAssets/Shaders/Prepass/GBuffer.xml

+ 1 - 4
Bin/Data/Materials/Default.xml

@@ -2,14 +2,11 @@
     <technique>
     <technique>
         <parameter name="MatSpecProperties" value="0.5 16" />
         <parameter name="MatSpecProperties" value="0.5 16" />
         <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer" />
         <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer" />
-
         <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer" />
         <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer" />
         <pass name="material" vs="Prepass/Material" ps="Prepass/Material" depthwrite="false" depthtest="equal" />
         <pass name="material" vs="Prepass/Material" ps="Prepass/Material" depthwrite="false" depthtest="equal" />
-        
         <pass name="ambient" vs="Forward" ps="Forward_Ambient" />
         <pass name="ambient" vs="Forward" ps="Forward_Ambient" />
         <pass name="light" vs="Forward" ps="Forward" depthwrite="false" depthtest="equal" blend="add" />
         <pass name="light" vs="Forward" ps="Forward" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward" ps="Forward" depthwrite="false" depthtest="equal" blend="multiply" />
-        
+        <pass name="negative" vs="Forward" ps="Forward" depthwrite="false" depthtest="equal" blend="multiply" />       
         <pass name="shadow" vs="Shadow" ps="Shadow" />
         <pass name="shadow" vs="Shadow" ps="Shadow" />
     </technique>
     </technique>
 </material>
 </material>

+ 8 - 0
Bin/Data/Materials/DefaultAlpha.xml

@@ -0,0 +1,8 @@
+<material>
+    <technique>
+        <parameter name="MatSpecProperties" value="0.5 16" />
+        <pass name="ambient" vs="Forward" ps="Forward_Ambient" depthwrite="false" blend="alpha" />
+        <pass name="light" vs="Forward" ps="Forward" depthwrite="false" blend="addalpha" />
+        <pass name="negative" vs="Forward" ps="Forward" depthwrite="false" blend="multiply" />
+    </technique>
+</material>

+ 1 - 4
Bin/Data/Materials/DefaultDiff.xml

@@ -2,14 +2,11 @@
     <technique>
     <technique>
         <parameter name="MatSpecProperties" value="0.5 16" />
         <parameter name="MatSpecProperties" value="0.5 16" />
         <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer_Diff" />
         <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer_Diff" />
-
         <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer" />
         <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer" />
         <pass name="material" vs="Prepass/Material" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
         <pass name="material" vs="Prepass/Material" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
-        
         <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" />
         <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" />
         <pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="add" />
         <pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />
-        
+        <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />     
         <pass name="shadow" vs="Shadow" ps="Shadow" />
         <pass name="shadow" vs="Shadow" ps="Shadow" />
     </technique>
     </technique>
 </material>
 </material>

+ 8 - 0
Bin/Data/Materials/DefaultDiffAlpha.xml

@@ -0,0 +1,8 @@
+<material>
+    <technique>
+        <parameter name="MatSpecProperties" value="0.5 16" />
+        <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" depthwrite="false" blend="alpha" />
+        <pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" blend="addalpha" />
+        <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" blend="multiply" />
+    </technique>
+</material>

+ 12 - 0
Bin/Data/Materials/DefaultDiffAlphaMask.xml

@@ -0,0 +1,12 @@
+<material>
+    <technique>
+        <parameter name="MatSpecProperties" value="0.5 16" />
+        <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer_DiffMask" alphamask="true" />
+        <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer_Mask" alphamask="true" />
+        <pass name="material" vs="Prepass/Material" ps="Prepass/Material_DiffMask" alphamask="true" depthwrite="false" depthtest="equal" />
+        <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
+        <pass name="light" vs="Forward" ps="Forward_Diff" alphatest="true" depthwrite="false" depthtest="equal" blend="add" />
+        <pass name="negative" vs="Forward" ps="Forward_Diff" alphatest="true" depthwrite="false" depthtest="equal" blend="multiply" />  
+        <pass name="shadow" vs="Shadow" ps="Shadow_Mask" alphamask="true" />
+    </technique>
+</material>

+ 0 - 15
Bin/Data/Materials/DefaultDiffInstanced.xml

@@ -1,15 +0,0 @@
-<material>
-    <technique>
-        <parameter name="MatSpecProperties" value="0.5 16" />
-        <pass name="deferred" vs="Deferred/GBuffer_Instanced" ps="Deferred/GBuffer_Diff" />
-
-        <pass name="prepass" vs="Prepass/GBuffer_Instanced" ps="Prepass/GBuffer" />
-        <pass name="material" vs="Prepass/Material_Instanced" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
-        
-        <pass name="ambient" vs="Forward_Instanced" ps="Forward_DiffAmbient" />
-        <pass name="light" vs="Forward_Instanced" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward_Instanced" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />
-        
-        <pass name="shadow" vs="Shadow_Instanced" ps="Shadow" />
-    </technique>
-</material>

+ 12 - 0
Bin/Data/Materials/DefaultDiffNormal.xml

@@ -0,0 +1,12 @@
+<material>
+    <technique>
+        <parameter name="MatSpecProperties" value="0.5 16" />
+        <pass name="deferred" vs="Deferred/GBuffer_Normal" ps="Deferred/GBuffer_DiffNormal" />
+        <pass name="prepass" vs="Prepass/GBuffer_Normal" ps="Prepass/GBuffer_Normal" />
+        <pass name="material" vs="Prepass/Material" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
+        <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" />
+        <pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" depthwrite="false" depthtest="equal" blend="add" />
+        <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />       
+        <pass name="shadow" vs="Shadow" ps="Shadow" />
+    </technique>
+</material>

+ 12 - 0
Bin/Data/Materials/DefaultDiffNormalAlphaMask.xml

@@ -0,0 +1,12 @@
+<material>
+    <technique>
+        <parameter name="MatSpecProperties" value="0.5 16" />
+        <pass name="deferred" vs="Deferred/GBuffer_Normal" ps="Deferred/GBuffer_DiffNormalMask" alphamask="true" />
+        <pass name="prepass" vs="Prepass/GBuffer_Normal" ps="Prepass/GBuffer_NormalMask" alphamask="true" />
+        <pass name="material" vs="Prepass/Material" ps="Prepass/Material_DiffMask" alphamask="true" depthwrite="false" depthtest="equal" />
+        <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
+        <pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" alphatest="true" depthwrite="false" depthtest="equal" blend="add" />
+        <pass name="negative" vs="Forward" ps="Forward_Diff" alphatest="true" depthwrite="false" depthtest="equal" blend="multiply" />
+        <pass name="shadow" vs="Shadow" ps="Shadow_Mask" alphamask="true" />
+    </technique>
+</material>

+ 0 - 14
Bin/Data/Materials/DefaultDiffSkinned.xml

@@ -1,14 +0,0 @@
-<material>
-    <technique>
-        <parameter name="MatSpecProperties" value="0.5 16" />
-        <pass name="deferred" vs="Deferred/GBuffer_Skinned" ps="Deferred/GBuffer_Diff" />
-
-        <pass name="prepass" vs="Prepass/GBuffer_Skinned" ps="Prepass/GBuffer" />
-        <pass name="material" vs="Prepass/Material_Skinned" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
-
-        <pass name="ambient" vs="Forward_Skinned" ps="Forward_DiffAmbient" />
-        <pass name="light" vs="Forward_Skinned" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward_Skinned" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />
-        <pass name="shadow" vs="Shadow_Skinned" ps="Shadow" />
-    </technique>
-</material>

+ 0 - 15
Bin/Data/Materials/DefaultInstanced.xml

@@ -1,15 +0,0 @@
-<material>
-    <technique>
-        <parameter name="MatSpecProperties" value="0.5 16" />
-        <pass name="deferred" vs="Deferred/GBuffer_Instanced" ps="Deferred/GBuffer" />
-
-        <pass name="prepass" vs="Prepass/GBuffer_Instanced" ps="Prepass/GBuffer" />
-        <pass name="material" vs="Prepass/Material_Instanced" ps="Prepass/Material" depthwrite="false" depthtest="equal" />
-
-        <pass name="ambient" vs="Forward_Instanced" ps="Forward_Ambient" />
-        <pass name="light" vs="Forward_Instanced" ps="Forward" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward_Instanced" ps="Forward" depthwrite="false" depthtest="equal" blend="multiply" />
-        
-        <pass name="shadow" vs="Shadow_Instanced" ps="Shadow" />
-    </technique>
-</material>

+ 0 - 15
Bin/Data/Materials/DefaultSkinned.xml

@@ -1,15 +0,0 @@
-<material>
-    <technique>
-        <parameter name="MatSpecProperties" value="0.5 16" />
-        <pass name="deferred" vs="Deferred/GBuffer_Skinned" ps="Deferred/GBuffer" />
-
-        <pass name="prepass" vs="Prepass/GBuffer_Skinned" ps="Prepass/GBuffer" />
-        <pass name="material" vs="Prepass/Material_Skinned" ps="Prepass/Material" depthwrite="false" depthtest="equal" />
-
-        <pass name="ambient" vs="Forward_Skinned" ps="Forward_Ambient" />
-        <pass name="light" vs="Forward_Skinned" ps="Forward" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward_Skinned" ps="Forward" depthwrite="false" depthtest="equal" blend="multiply" />
-
-        <pass name="shadow" vs="Shadow_Skinned" ps="Shadow" />
-    </technique>
-</material>

+ 1 - 1
Bin/Data/Materials/Jack.xml

@@ -1,3 +1,3 @@
 <material>
 <material>
-    <base name="Materials/DefaultSkinned.xml" />
+    <base name="Materials/Default.xml" />
 </material>
 </material>

+ 0 - 3
Bin/Data/Materials/JackStatic.xml

@@ -1,3 +0,0 @@
-<material>
-    <base name="Materials/Default.xml" />
-</material>

+ 1 - 1
Bin/Data/Materials/Mushroom.xml

@@ -1,5 +1,5 @@
 <material>
 <material>
-    <base name="Materials/DefaultDiffSkinned.xml" />
+    <base name="Materials/DefaultDiff.xml" />
     <technique>
     <technique>
         <texture unit="diffuse" name="Textures/Mushroom.dds" />
         <texture unit="diffuse" name="Textures/Mushroom.dds" />
         <parameter name="MatSpecProperties" value="0.1 16" />
         <parameter name="MatSpecProperties" value="0.1 16" />

+ 0 - 7
Bin/Data/Materials/MushroomInstanced.xml

@@ -1,7 +0,0 @@
-<material>
-    <base name="Materials/DefaultDiffInstanced.xml" />
-    <technique>
-        <texture unit="diffuse" name="Textures/Mushroom.dds" />
-        <parameter name="MatSpecProperties" value="0.1 16" />
-    </technique>
-</material>

+ 0 - 7
Bin/Data/Materials/MushroomStatic.xml

@@ -1,7 +0,0 @@
-<material>
-    <base name="Materials/DefaultDiff.xml" />
-    <technique>
-        <texture unit="diffuse" name="Textures/Mushroom.dds" />
-        <parameter name="MatSpecProperties" value="0.1 16" />
-    </technique>
-</material>

+ 1 - 1
Bin/Data/Materials/Ninja.xml

@@ -1,5 +1,5 @@
 <material>
 <material>
-    <base name="Materials/DefaultDiffSkinned.xml" />
+    <base name="Materials/DefaultDiff.xml" />
     <technique>
     <technique>
         <texture unit="diffuse" name="Textures/Ninja.dds" />
         <texture unit="diffuse" name="Textures/Ninja.dds" />
         <parameter name="MatSpecProperties" value="0 0" />
         <parameter name="MatSpecProperties" value="0 0" />

+ 1 - 13
Bin/Data/Materials/Test.xml

@@ -1,31 +1,19 @@
 <material>
 <material>
+    <base name="Materials/DefaultDiffNormal.xml" />
     <technique quality="1">
     <technique quality="1">
         <texture unit="diffuse" name="Textures/Diffuse.dds" />
         <texture unit="diffuse" name="Textures/Diffuse.dds" />
         <texture unit="normal" name="Textures/Normal.dds" />
         <texture unit="normal" name="Textures/Normal.dds" />
         <parameter name="MatSpecProperties" value="0.5 16" />
         <parameter name="MatSpecProperties" value="0.5 16" />
-        <pass name="deferred" vs="Deferred/GBuffer_Normal" ps="Deferred/GBuffer_DiffNormal" />
-
-        <pass name="prepass" vs="Prepass/GBuffer_Normal" ps="Prepass/GBuffer_Normal" />
-        <pass name="material" vs="Prepass/Material" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
-
-        <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" />
-        <pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" depthwrite="false" depthtest="equal" blend="add" />
-        <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />
-
-        <pass name="shadow" vs="Shadow" ps="Shadow" />
     </technique>
     </technique>
     <technique quality="0">
     <technique quality="0">
         <texture unit="diffuse" name="Textures/Diffuse.dds" />
         <texture unit="diffuse" name="Textures/Diffuse.dds" />
         <parameter name="MatSpecProperties" value="0.5 16" />
         <parameter name="MatSpecProperties" value="0.5 16" />
         <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer_Diff" />
         <pass name="deferred" vs="Deferred/GBuffer" ps="Deferred/GBuffer_Diff" />
-
         <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer" />
         <pass name="prepass" vs="Prepass/GBuffer" ps="Prepass/GBuffer" />
         <pass name="material" vs="Prepass/Material" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
         <pass name="material" vs="Prepass/Material" ps="Prepass/Material_Diff" depthwrite="false" depthtest="equal" />
-
         <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" />
         <pass name="ambient" vs="Forward" ps="Forward_DiffAmbient" />
         <pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="add" />
         <pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="add" />
         <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />
         <pass name="negative" vs="Forward" ps="Forward_Diff" depthwrite="false" depthtest="equal" blend="multiply" />
-
         <pass name="shadow" vs="Shadow" ps="Shadow" />
         <pass name="shadow" vs="Shadow" ps="Shadow" />
     </technique>
     </technique>
 </material>
 </material>

+ 2 - 1
Bin/Data/UI/UI.xml

@@ -11,6 +11,7 @@
         <hoverrect value="32 0 48 16" />
         <hoverrect value="32 0 48 16" />
         <pressedrect value="48 0 64 16" />
         <pressedrect value="48 0 64 16" />
         <border value="5 5 5 5" />
         <border value="5 5 5 5" />
+        <labeloffset value="0 0" />
     </element>
     </element>
     <element name="Window">
     <element name="Window">
         <texture name="Textures/UI.png" />
         <texture name="Textures/UI.png" />
@@ -21,6 +22,6 @@
         <resizable enable="true" />
         <resizable enable="true" />
     </element>
     </element>
     <element name="Text">
     <element name="Text">
-        <font name="Fonts/Cour.ttf" size="10" />
+        <font name="Cour.ttf" size="10" />
     </element>
     </element>
 </elements>
 </elements>

+ 1 - 1
Engine/Engine/RegisterEngine.cpp

@@ -115,7 +115,7 @@ static void registerConnection(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Connection", "const Vector3& getPosition() const", asMETHOD(Connection, getPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("Connection", "const Vector3& getPosition() const", asMETHOD(Connection, getPosition), asCALL_THISCALL);
     
     
     // Register Variant getPtr() for Connection
     // Register Variant getPtr() for Connection
-    engine->RegisterObjectMethod("Connection", "Connection@+ getConnection() const", asFUNCTION(getVariantPtr<Connection>), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Variant", "Connection@+ getConnection() const", asFUNCTION(getVariantPtr<Connection>), asCALL_CDECL_OBJLAST);
     
     
     engine->RegisterObjectType("NetUpdateInfo", sizeof(NetUpdateInfo), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
     engine->RegisterObjectType("NetUpdateInfo", sizeof(NetUpdateInfo), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_C);
     engine->RegisterObjectBehaviour("NetUpdateInfo", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructNetUpdateInfo), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("NetUpdateInfo", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructNetUpdateInfo), asCALL_CDECL_OBJLAST);

+ 4 - 5
Engine/Engine/RegisterUI.cpp

@@ -71,7 +71,7 @@ static void registerUIElement(asIScriptEngine* engine)
     engine->RegisterObjectMethod("UIElement", "void loadParameters(XMLFile@+, const string& in)", asFUNCTION(UIElementLoadParameters), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("UIElement", "void loadParameters(XMLFile@+, const string& in)", asFUNCTION(UIElementLoadParameters), asCALL_CDECL_OBJLAST);
     
     
     // Register Variant getPtr() for UIElement
     // Register Variant getPtr() for UIElement
-    engine->RegisterObjectMethod("UIElement", "UIElement@+ getUIElement() const", asFUNCTION(getVariantPtr<UIElement>), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Variant", "UIElement@+ getUIElement() const", asFUNCTION(getVariantPtr<UIElement>), asCALL_CDECL_OBJLAST);
 }
 }
 
 
 static void registerText(asIScriptEngine* engine)
 static void registerText(asIScriptEngine* engine)
@@ -121,15 +121,14 @@ static void registerButton(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Button", "void setHoverRect(int, int, int, int)", asMETHODPR(Button, setHoverRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setHoverRect(int, int, int, int)", asMETHODPR(Button, setHoverRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(const IntRect& in)", asMETHODPR(Button, setPressedRect, (const IntRect&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(const IntRect& in)", asMETHODPR(Button, setPressedRect, (const IntRect&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(int, int, int, int)", asMETHODPR(Button, setPressedRect, (int, int, int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setPressedRect(int, int, int, int)", asMETHODPR(Button, setPressedRect, (int, int, int, int), void), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "void setHoverDelay(float)", asMETHOD(Button, setHoverDelay), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "void setPresseddelay(float)", asMETHOD(Button, setPressedDelay), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabel(UIElement@+)", asMETHOD(Button, setLabel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "void setLabel(UIElement@+)", asMETHOD(Button, setLabel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Button", "void setLabelOffset(const IntVector2& in)", asMETHODPR(Button, setLabelOffset, (const IntVector2&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Button", "void setLabelOffset(int, int)", asMETHODPR(Button, setLabelOffset, (int, int), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getInactiveRect() const", asMETHOD(Button, getInactiveRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getInactiveRect() const", asMETHOD(Button, getInactiveRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getHoverRect() const", asMETHOD(Button, getHoverRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getHoverRect() const", asMETHOD(Button, getHoverRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getPressedRect() const", asMETHOD(Button, getPressedRect), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "const IntRect& getPressedRect() const", asMETHOD(Button, getPressedRect), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "float getHoverDelay() const", asMETHOD(Button, getHoverDelay), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Button", "float getPressedDelay() const", asMETHOD(Button, getPressedDelay), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "UIElement@+ getLabel() const", asMETHOD(Button, getLabel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Button", "UIElement@+ getLabel() const", asMETHOD(Button, getLabel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Button", "const IntVector2& getLabelOffset() const", asMETHOD(Button, getLabelOffset), asCALL_THISCALL);
     registerRefCasts<UIElement, Button>(engine, "UIElement", "Button");
     registerRefCasts<UIElement, Button>(engine, "UIElement", "Button");
 }
 }
 
 

+ 33 - 1
Engine/Math/MathDefs.h

@@ -36,7 +36,7 @@ static const int M_MAX_INT = 0x7fffffff;
 static const unsigned M_MIN_UNSIGNED = 0x00000000;
 static const unsigned M_MIN_UNSIGNED = 0x00000000;
 static const unsigned M_MAX_UNSIGNED = 0xffffffff;
 static const unsigned M_MAX_UNSIGNED = 0xffffffff;
 
 
-static const float M_EPSILON = 0.0000001f;
+static const float M_EPSILON = 0.000001f;
 static const float M_MIN_NEARCLIP = 0.01f;
 static const float M_MIN_NEARCLIP = 0.01f;
 static const float M_MAX_FOV = 160.0f;
 static const float M_MAX_FOV = 160.0f;
 static const float M_LARGE_VALUE = 100000000.0f;
 static const float M_LARGE_VALUE = 100000000.0f;
@@ -130,4 +130,36 @@ inline bool isPowerOfTwo(unsigned value)
     return value == 1;
     return value == 1;
 }
 }
 
 
+//! Fast square root
+inline float fastSqrt(float x)
+{
+    union
+    {
+        float f;
+        int i;
+    } u;
+    
+    u.f = x;
+    u.i -= 1 << 23;
+    u.i >>= 1;
+    u.i += 1 << 29;
+    return u.f;
+}
+
+//! Fast inverse square root
+inline float fastInvSqrt(float x)
+{
+    union
+    {
+        float f;
+        int i;
+    } u;
+    
+    float xHalf = 0.5f * x;
+    u.f = x;
+    u.i = 0x5f3759df - (u.i >> 1);
+    x = u.f * (1.5f - xHalf * u.f * u.f);
+    return x;
+}
+
 #endif // MATH_MATHDEFS_H
 #endif // MATH_MATHDEFS_H

+ 23 - 0
Engine/Math/Quaternion.h

@@ -167,6 +167,16 @@ public:
         return len;
         return len;
     }
     }
     
     
+    //! Normalize to unit length using fast inverse square root
+    void normalizeFast()
+    {
+        float invLen = fastInvSqrt(mW * mW + mX * mX + mY * mY + mZ * mZ);
+        mW *= invLen;
+        mX *= invLen;
+        mY *= invLen;
+        mZ *= invLen;
+    }
+    
     //! Set from an angle (in degrees) and axis
     //! Set from an angle (in degrees) and axis
     void fromAngleAxis(float angle, const Vector3& axis);
     void fromAngleAxis(float angle, const Vector3& axis);
     //! Set from Euler angles (in degrees)
     //! Set from Euler angles (in degrees)
@@ -185,6 +195,13 @@ public:
         return *this * invLen;
         return *this * invLen;
     }
     }
     
     
+    //! Return normalized to unit length, using fast inverse square root
+    Quaternion getNormalizedFast() const
+    {
+        float invLen = fastInvSqrt(mW * mW + mX * mX + mY * mY + mZ * mZ);
+        return *this * invLen;
+    }
+    
     //! Return inverse
     //! Return inverse
     Quaternion getInverse() const
     Quaternion getInverse() const
     {
     {
@@ -219,6 +236,12 @@ public:
         return (*this * (1.0f - t) + rhs * t).getNormalized();
         return (*this * (1.0f - t) + rhs * t).getNormalized();
     }
     }
     
     
+    //! Normalized interpolation with another quaternion, using fast inverse square root
+    Quaternion nlerpFast(const Quaternion& rhs, float t) const
+    {
+        return (*this * (1.0f - t) + rhs * t).getNormalizedFast();
+    }
+    
     //! Return Euler angles (in degrees)
     //! Return Euler angles (in degrees)
     void getEulerAngles(float& angleX, float& angleY, float& angleZ) const;
     void getEulerAngles(float& angleX, float& angleY, float& angleZ) const;
     //! Return yaw angle in degrees
     //! Return yaw angle in degrees

+ 21 - 0
Engine/Math/Vector2.h

@@ -187,12 +187,26 @@ public:
         return len;
         return len;
     }
     }
     
     
+    //! Normalize to unit length using fast inverse square root
+    void normalizeFast()
+    {
+        float invLen = fastInvSqrt(mX * mX + mY * mY);
+        mX *= invLen;
+        mY *= invLen;
+    }
+    
     //! Return length
     //! Return length
     float getLength() const
     float getLength() const
     {
     {
         return sqrtf(mX * mX + mY * mY);
         return sqrtf(mX * mX + mY * mY);
     }
     }
     
     
+    //! Return length using fast square root
+    float getLengthFast() const
+    {
+        return fastSqrt(mX * mX + mY * mY);
+    }
+    
     //! Return squared length
     //! Return squared length
     float getLengthSquared() const
     float getLengthSquared() const
     {
     {
@@ -228,6 +242,13 @@ public:
         return *this * invLen;
         return *this * invLen;
     }
     }
     
     
+    //! Return normalized to unit length using fast inverse square root
+    Vector2 getNormalizedFast() const
+    {
+        float invLen = fastInvSqrt(mX * mX + mY * mY);
+        return *this * invLen;
+    }
+    
     //! Return float data
     //! Return float data
     const float* getData() const { return &mX; }
     const float* getData() const { return &mX; }
     
     

+ 22 - 0
Engine/Math/Vector3.h

@@ -206,12 +206,27 @@ public:
         return len;
         return len;
     }
     }
     
     
+    //! Normalize to unit length using fast inverse square root
+    void normalizeFast()
+    {
+        float invLen = fastInvSqrt(mX * mX + mY * mY + mZ * mZ);
+        mX *= invLen;
+        mY *= invLen;
+        mZ *= invLen;
+    }
+    
     //! Return length
     //! Return length
     float getLength() const
     float getLength() const
     {
     {
         return sqrtf(mX * mX + mY * mY + mZ * mZ);
         return sqrtf(mX * mX + mY * mY + mZ * mZ);
     }
     }
     
     
+    //! Return length using fast square root
+    float getLengthFast() const
+    {
+        return fastSqrt(mX * mX + mY * mY + mZ * mZ);
+    }
+    
     //! Return squared length
     //! Return squared length
     float getLengthSquared() const
     float getLengthSquared() const
     {
     {
@@ -257,6 +272,13 @@ public:
         return *this * invLen;
         return *this * invLen;
     }
     }
     
     
+    //! Return normalized to unit length using fast inverse square root
+    Vector3 getNormalizedFast() const
+    {
+        float invLen = fastInvSqrt(mX * mX + mY * mY + mZ * mZ);
+        return *this * invLen;
+    }
+    
     //! Return float data
     //! Return float data
     const float* getData() const { return &mX; }
     const float* getData() const { return &mX; }
     
     

+ 2 - 2
Engine/Physics/RigidBody.cpp

@@ -372,8 +372,8 @@ void RigidBody::readNetUpdate(Deserializer& source, ResourceCache* cache, const
     if (bits & (1 | 2 | 64 | 128))
     if (bits & (1 | 2 | 64 | 128))
     {
     {
         // If the last network update was stationary, forcibly disable the body so it will not start drifting
         // If the last network update was stationary, forcibly disable the body so it will not start drifting
-        bool active = (getLinearVelocity().getLength() > getLinearRestThreshold()) ||
-            (getAngularVelocity().getLength() > getAngularRestThreshold());
+        bool active = (getLinearVelocity().getLengthFast() > getLinearRestThreshold()) ||
+            (getAngularVelocity().getLengthFast() > getAngularRestThreshold());
         
         
         if (!active)
         if (!active)
         {
         {

+ 2 - 0
Engine/Renderer/AnimatedModel.h

@@ -69,6 +69,8 @@ public:
     virtual void updateDistance(const FrameInfo& frame);
     virtual void updateDistance(const FrameInfo& frame);
     //! Prepare geometry for rendering
     //! Prepare geometry for rendering
     virtual void updateGeometry(const FrameInfo& frame, Renderer* renderer);
     virtual void updateGeometry(const FrameInfo& frame, Renderer* renderer);
+    //! Return geometry type, determines vertex shader variation
+    virtual GeometryType getGeometryType() { return GEOM_SKINNED; }
     //! Return vertex shader parameter
     //! Return vertex shader parameter
     virtual bool getVertexShaderParameter(unsigned batchIndex, VSParameter parameter, const float** data, unsigned* count);
     virtual bool getVertexShaderParameter(unsigned batchIndex, VSParameter parameter, const float** data, unsigned* count);
     //! Draw debug geometry
     //! Draw debug geometry

+ 102 - 72
Engine/Renderer/AnimationState.cpp

@@ -278,117 +278,147 @@ void AnimationState::apply()
     if (!isEnabled())
     if (!isEnabled())
         return;
         return;
     
     
-    for (std::map<unsigned, Bone*>::const_iterator i = mTrackToBoneMap.begin(); i != mTrackToBoneMap.end(); ++i)
+    // Check first if full weight or blending
+    if (mWeight == 1.0f)
     {
     {
-        const AnimationTrack* track = mAnimation->getTrack(i->first);
-        Bone* bone = i->second;
-        
-        if ((bone->isAnimationEnabled()) && (track->mKeyFrames.size()))
+        for (std::map<unsigned, Bone*>::const_iterator i = mTrackToBoneMap.begin(); i != mTrackToBoneMap.end(); ++i)
         {
         {
+            const AnimationTrack* track = mAnimation->getTrack(i->first);
+            Bone* bone = i->second;
+            
+            if ((!bone->isAnimationEnabled()) || (!track->mKeyFrames.size()))
+                continue;
+            
             unsigned& frame = mLastKeyFrame[i->first];
             unsigned& frame = mLastKeyFrame[i->first];
             track->getKeyFrameIndex(mTime, frame);
             track->getKeyFrameIndex(mTime, frame);
             
             
             // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
             // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
             unsigned nextFrame = frame + 1;
             unsigned nextFrame = frame + 1;
             bool interpolate = true;
             bool interpolate = true;
-            if (!mLooped)
+            if (nextFrame >= track->mKeyFrames.size())
             {
             {
-                if (nextFrame >= track->mKeyFrames.size())
+                if (!mLooped)
                 {
                 {
                     nextFrame = frame;
                     nextFrame = frame;
                     interpolate = false;
                     interpolate = false;
                 }
                 }
-            }
-            else
-            {
-                if (nextFrame >= track->mKeyFrames.size())
+                else
                     nextFrame = 0;
                     nextFrame = 0;
             }
             }
             
             
             const AnimationKeyFrame* keyFrame = &track->mKeyFrames[frame];
             const AnimationKeyFrame* keyFrame = &track->mKeyFrames[frame];
-            const AnimationKeyFrame* nextKeyFrame = &track->mKeyFrames[nextFrame];
-            float timeInterval = nextKeyFrame->mTime - keyFrame->mTime;
-            if (timeInterval < 0.0f)
-                timeInterval += mAnimation->getLength();
-            
             unsigned char channelMask = track->mChannelMask;
             unsigned char channelMask = track->mChannelMask;
             
             
             if (!interpolate)
             if (!interpolate)
             {
             {
                 // No interpolation, full weight
                 // No interpolation, full weight
-                if (mWeight == 1.0f)
+                if (channelMask & CHANNEL_POSITION)
+                    bone->setPosition(keyFrame->mPosition);
+                if (channelMask & CHANNEL_ROTATION)
+                    bone->setRotation(keyFrame->mRotation);
+                if (channelMask & CHANNEL_SCALE)
+                    bone->setScale(keyFrame->mScale);
+            }
+            else
+            {
+                const AnimationKeyFrame* nextKeyFrame = &track->mKeyFrames[nextFrame];
+                float timeInterval = nextKeyFrame->mTime - keyFrame->mTime;
+                if (timeInterval < 0.0f)
+                    timeInterval += mAnimation->getLength();
+                float t = clamp((mTime - keyFrame->mTime) / timeInterval, 0.0f, 1.0f);
+                
+                // Interpolation, full weight
+                if (channelMask & CHANNEL_POSITION)
+                    bone->setPosition(keyFrame->mPosition.lerp(nextKeyFrame->mPosition, t));
+                if (channelMask & CHANNEL_ROTATION)
                 {
                 {
-                    if (channelMask & CHANNEL_POSITION)
-                        bone->setPosition(keyFrame->mPosition);
-                    if (channelMask & CHANNEL_ROTATION)
-                        bone->setRotation(keyFrame->mRotation);
-                    if (channelMask & CHANNEL_SCALE)
-                        bone->setScale(keyFrame->mScale);
+                    if (!mUseNlerp)
+                        bone->setRotation(keyFrame->mRotation.slerp(nextKeyFrame->mRotation, t));
+                    else
+                        bone->setRotation(keyFrame->mRotation.nlerpFast(nextKeyFrame->mRotation, t));
+                }
+                if (channelMask & CHANNEL_SCALE)
+                    bone->setScale(keyFrame->mScale.lerp(nextKeyFrame->mScale, t));
+            }
+        }
+    }
+    else
+    {
+        for (std::map<unsigned, Bone*>::const_iterator i = mTrackToBoneMap.begin(); i != mTrackToBoneMap.end(); ++i)
+        {
+            const AnimationTrack* track = mAnimation->getTrack(i->first);
+            Bone* bone = i->second;
+            
+            if ((!bone->isAnimationEnabled()) || (!track->mKeyFrames.size()))
+                continue;
+            
+            unsigned& frame = mLastKeyFrame[i->first];
+            track->getKeyFrameIndex(mTime, frame);
+            
+            // Check if next frame to interpolate to is valid, or if wrapping is needed (looping animation only)
+            unsigned nextFrame = frame + 1;
+            bool interpolate = true;
+            if (nextFrame >= track->mKeyFrames.size())
+            {
+                if (!mLooped)
+                {
+                    nextFrame = frame;
+                    interpolate = false;
                 }
                 }
-                // No interpolation, blend between old transform & animation
                 else
                 else
+                    nextFrame = 0;
+            }
+            
+            const AnimationKeyFrame* keyFrame = &track->mKeyFrames[frame];
+            unsigned char channelMask = track->mChannelMask;
+            
+            if (!interpolate)
+            {
+                // No interpolation, blend between old transform & animation
+                if (channelMask & CHANNEL_POSITION)
+                    bone->setPosition(bone->getPosition().lerp(keyFrame->mPosition, mWeight));
+                if (channelMask & CHANNEL_ROTATION)
                 {
                 {
-                    if (channelMask & CHANNEL_POSITION)
-                        bone->setPosition(bone->getPosition().lerp(keyFrame->mPosition, mWeight));
-                    if (channelMask & CHANNEL_ROTATION)
-                    {
-                        if (!mUseNlerp)
-                            bone->setRotation(bone->getRotation().slerp(keyFrame->mRotation, mWeight));
-                        else
-                            bone->setRotation(bone->getRotation().nlerp(keyFrame->mRotation, mWeight));
-                    }
-                    if (channelMask & CHANNEL_SCALE)
-                        bone->setScale(bone->getScale().lerp(keyFrame->mScale, mWeight));
+                    if (!mUseNlerp)
+                        bone->setRotation(bone->getRotation().slerp(keyFrame->mRotation, mWeight));
+                    else
+                        bone->setRotation(bone->getRotation().nlerpFast(keyFrame->mRotation, mWeight));
                 }
                 }
+                if (channelMask & CHANNEL_SCALE)
+                    bone->setScale(bone->getScale().lerp(keyFrame->mScale, mWeight));
             }
             }
             else
             else
             {
             {
-                float t = 1.0f;
-                if (timeInterval > 0.0f)
-                    t = (mTime - keyFrame->mTime) / timeInterval;
+                const AnimationKeyFrame* nextKeyFrame = &track->mKeyFrames[nextFrame];
+                float timeInterval = nextKeyFrame->mTime - keyFrame->mTime;
+                if (timeInterval < 0.0f)
+                    timeInterval += mAnimation->getLength();
+                float t = clamp((mTime - keyFrame->mTime) / timeInterval, 0.0f, 1.0f);
                 
                 
-                // Interpolation, full weight
-                if (mWeight == 1.0f)
+                // Interpolation, blend between old transform & animation
+                if (channelMask & CHANNEL_POSITION)
                 {
                 {
-                    if (channelMask & CHANNEL_POSITION)
-                        bone->setPosition(keyFrame->mPosition.lerp(nextKeyFrame->mPosition, t));
-                    if (channelMask & CHANNEL_ROTATION)
-                    {
-                        if (!mUseNlerp)
-                            bone->setRotation(keyFrame->mRotation.slerp(nextKeyFrame->mRotation, t));
-                        else
-                            bone->setRotation(keyFrame->mRotation.nlerp(nextKeyFrame->mRotation, t));
-                    }
-                    if (channelMask & CHANNEL_SCALE)
-                        bone->setScale(keyFrame->mScale.lerp(nextKeyFrame->mScale, t));
+                    bone->setPosition(bone->getPosition().lerp(
+                        keyFrame->mPosition.lerp(nextKeyFrame->mPosition, t), mWeight));
                 }
                 }
-                // Interpolation, blend between old transform & animation
-                else
+                if (channelMask & CHANNEL_ROTATION)
                 {
                 {
-                    if (channelMask & CHANNEL_POSITION)
+                    if (!mUseNlerp)
                     {
                     {
-                        bone->setPosition(bone->getPosition().lerp(
-                            keyFrame->mPosition.lerp(nextKeyFrame->mPosition, t), mWeight));
+                        bone->setRotation(bone->getRotation().slerp(
+                            keyFrame->mRotation.slerp(nextKeyFrame->mRotation, t), mWeight));
                     }
                     }
-                    if (channelMask & CHANNEL_ROTATION)
+                    else
                     {
                     {
-                        if (!mUseNlerp)
-                        {
-                            bone->setRotation(bone->getRotation().slerp(
-                                keyFrame->mRotation.slerp(nextKeyFrame->mRotation, t), mWeight));
-                        }
-                        else
-                        {
-                            bone->setRotation(bone->getRotation().nlerp(
-                                keyFrame->mRotation.nlerp(nextKeyFrame->mRotation, t), mWeight));
-                        }
-                    }
-                    if (channelMask & CHANNEL_SCALE)
-                    {
-                        bone->setScale(bone->getScale().lerp(
-                            keyFrame->mScale.lerp(nextKeyFrame->mScale, t), mWeight));
+                        bone->setRotation(bone->getRotation().nlerpFast(
+                            keyFrame->mRotation.nlerpFast(nextKeyFrame->mRotation, t), mWeight));
                     }
                     }
                 }
                 }
+                if (channelMask & CHANNEL_SCALE)
+                {
+                    bone->setScale(bone->getScale().lerp(
+                        keyFrame->mScale.lerp(nextKeyFrame->mScale, t), mWeight));
+                }
             }
             }
         }
         }
     }
     }

+ 2 - 2
Engine/Renderer/AnimationState.h

@@ -70,7 +70,7 @@ public:
     void addTime(float delta);
     void addTime(float delta);
     //! Set blending priority
     //! Set blending priority
     void setPriority(int priority);
     void setPriority(int priority);
-    //! Set nlerp use instead of slerp, default false
+    //! Set to use nlerp instead of slerp for rotation, default false
     void setUseNlerp(bool enable);
     void setUseNlerp(bool enable);
     
     
     //! Return animation
     //! Return animation
@@ -87,7 +87,7 @@ public:
     float getTime() const;
     float getTime() const;
     //! Return blending priority
     //! Return blending priority
     int getPriority() const { return mPriority; }
     int getPriority() const { return mPriority; }
-    //! Return whether using nlerp
+    //! Return whether using nlerp for rotation
     bool getUseNlerp() const { return mUseNlerp; }
     bool getUseNlerp() const { return mUseNlerp; }
     //! Return whether network client smoothing active
     //! Return whether network client smoothing active
     bool isInterpolating() const { return mInterpolationFlags != 0; }
     bool isInterpolating() const { return mInterpolationFlags != 0; }

+ 1 - 1
Engine/Renderer/Batch.cpp

@@ -45,7 +45,7 @@ void Batch::calculateSortKey(bool stateHasPriority, bool frontToBack)
         distance = 65535 - distance;
         distance = 65535 - distance;
     
     
     // Shaders
     // Shaders
-    unsigned short shaders = mVertexShader->getHash() + mPixelShader->getHash();
+    unsigned short shaders = (mVertexShader ? mVertexShader->getHash() : 0) + (mPixelShader ? mPixelShader->getHash() : 0);
     
     
     // Material technique (determines textures and shader parameters)
     // Material technique (determines textures and shader parameters)
     unsigned short technique = *((unsigned short*)&mTechnique);
     unsigned short technique = *((unsigned short*)&mTechnique);

+ 1 - 1
Engine/Renderer/Camera.cpp

@@ -469,7 +469,7 @@ Vector3 Camera::getUpVector()
 float Camera::getDistance(const Vector3& worldPos)
 float Camera::getDistance(const Vector3& worldPos)
 {
 {
     if (!mOrthographic)
     if (!mOrthographic)
-        return (worldPos - getWorldPosition()).getLength();
+        return (worldPos - getWorldPosition()).getLengthFast();
     else
     else
         return fabsf((getInverseWorldTransform() * worldPos).mZ);
         return fabsf((getInverseWorldTransform() * worldPos).mZ);
 }
 }

+ 1 - 1
Engine/Renderer/DeferredView.cpp

@@ -212,7 +212,7 @@ void View::getBatchesDeferred()
                         Batch shadowBatch;
                         Batch shadowBatch;
                         shadowBatch.mNode = node;
                         shadowBatch.mNode = node;
                         shadowBatch.mCamera = &shadowCamera;
                         shadowBatch.mCamera = &shadowCamera;
-                        shadowBatch.mDistance = (node->getWorldPosition() - shadowCamera.getPosition()).getLength();
+                        shadowBatch.mDistance = (node->getWorldPosition() - shadowCamera.getPosition()).getLengthFast();
                         shadowBatch.mGeometry = geom;
                         shadowBatch.mGeometry = geom;
                         shadowBatch.mBatchIndex = l;
                         shadowBatch.mBatchIndex = l;
                         shadowBatch.mForwardLight = sSplitLights[j];
                         shadowBatch.mForwardLight = sSplitLights[j];

+ 1 - 1
Engine/Renderer/ForwardView.cpp

@@ -160,7 +160,7 @@ void View::getBatchesForward()
                         Batch shadowBatch;
                         Batch shadowBatch;
                         shadowBatch.mNode = node;
                         shadowBatch.mNode = node;
                         shadowBatch.mCamera = &shadowCamera;
                         shadowBatch.mCamera = &shadowCamera;
-                        shadowBatch.mDistance = (node->getWorldPosition() - shadowCamera.getPosition()).getLength();
+                        shadowBatch.mDistance = (node->getWorldPosition() - shadowCamera.getPosition()).getLengthFast();
                         shadowBatch.mGeometry = geom;
                         shadowBatch.mGeometry = geom;
                         shadowBatch.mBatchIndex = l;
                         shadowBatch.mBatchIndex = l;
                         shadowBatch.mForwardLight = sSplitLights[j];
                         shadowBatch.mForwardLight = sSplitLights[j];

+ 2 - 0
Engine/Renderer/GeometryNode.h

@@ -56,6 +56,8 @@ public:
     virtual void updateDistance(const FrameInfo& frame);
     virtual void updateDistance(const FrameInfo& frame);
     //! Prepare geometry for rendering
     //! Prepare geometry for rendering
     virtual void updateGeometry(const FrameInfo& frame, Renderer* renderer) = 0;
     virtual void updateGeometry(const FrameInfo& frame, Renderer* renderer) = 0;
+    //! Return geometry type, determines vertex shader variation
+    virtual GeometryType getGeometryType() { return GEOM_STATIC; }
     //! Return number of batches
     //! Return number of batches
     virtual unsigned getNumBatches() = 0;
     virtual unsigned getNumBatches() = 0;
     //! Return geometry by batch index
     //! Return geometry by batch index

+ 2 - 0
Engine/Renderer/InstancedModel.h

@@ -74,6 +74,8 @@ public:
     virtual void updateDistance(const FrameInfo& frame);
     virtual void updateDistance(const FrameInfo& frame);
     //! Prepare geometry for rendering
     //! Prepare geometry for rendering
     virtual void updateGeometry(const FrameInfo& frame, Renderer* renderer);
     virtual void updateGeometry(const FrameInfo& frame, Renderer* renderer);
+    //! Return geometry type, determines vertex shader variation
+    virtual GeometryType getGeometryType() { return GEOM_INSTANCED; }
     //! Return number of batches
     //! Return number of batches
     virtual unsigned getNumBatches();
     virtual unsigned getNumBatches();
     //! Return geometry by batch index
     //! Return geometry by batch index

+ 57 - 34
Engine/Renderer/Pipeline.cpp

@@ -168,6 +168,13 @@ static const unsigned short spotLightIndexData[] =
     7, 6, 5
     7, 6, 5
 };
 };
 
 
+static const std::string geometryVSVariations[] =
+{
+    "",
+    "Skinned",
+    "Instanced"
+};
+
 static const std::string gBufferPSVariations[] =
 static const std::string gBufferPSVariations[] =
 {
 {
     "",
     "",
@@ -497,14 +504,20 @@ VertexShader* Pipeline::getVertexShader(const std::string& name) const
 {
 {
     // Check for extra underscore with no variations and remove
     // Check for extra underscore with no variations and remove
     std::string fullName = replace(mShaderPath + name + mVSFormat, "_.", ".");
     std::string fullName = replace(mShaderPath + name + mVSFormat, "_.", ".");
-    return mCache->getResource<VertexShader>(fullName);
+    if (mCache->exists(fullName))
+        return mCache->getResource<VertexShader>(fullName);
+    else
+        return 0;
 }
 }
 
 
 PixelShader* Pipeline::getPixelShader(const std::string& name) const
 PixelShader* Pipeline::getPixelShader(const std::string& name) const
 {
 {
     // Check for extra underscore with no variations and remove
     // Check for extra underscore with no variations and remove
     std::string fullName = replace(mShaderPath + name + mPSFormat, "_.", ".");
     std::string fullName = replace(mShaderPath + name + mPSFormat, "_.", ".");
-    return mCache->getResource<PixelShader>(fullName);
+    if (mCache->exists(fullName))
+        return mCache->getResource<PixelShader>(fullName);
+    else
+        return 0;
 }
 }
 
 
 unsigned Pipeline::getNumGeometries(bool allViews) const
 unsigned Pipeline::getNumGeometries(bool allViews) const
@@ -682,42 +695,36 @@ Texture2D* Pipeline::getShadowMap(float resolution)
 
 
 void Pipeline::setBatchShaders(Batch& batch, MaterialTechnique* technique, MaterialPass* pass, bool allowShadows)
 void Pipeline::setBatchShaders(Batch& batch, MaterialTechnique* technique, MaterialPass* pass, bool allowShadows)
 {
 {
+    static std::set<Material*> errorDisplayed;
+    
+    batch.mTechnique = technique;
+    batch.mPass = pass;
+    
     // Check if shaders are unloaded or need reloading
     // Check if shaders are unloaded or need reloading
     std::vector<SharedPtr<VertexShader> >& vertexShaders = pass->getVertexShaders();
     std::vector<SharedPtr<VertexShader> >& vertexShaders = pass->getVertexShaders();
     std::vector<SharedPtr<PixelShader> >& pixelShaders = pass->getPixelShaders();
     std::vector<SharedPtr<PixelShader> >& pixelShaders = pass->getPixelShaders();
-    
     if ((!vertexShaders.size()) || (!pixelShaders.size()) || (technique->getShadersLoadedFrameNumber() !=
     if ((!vertexShaders.size()) || (!pixelShaders.size()) || (technique->getShadersLoadedFrameNumber() !=
         mShadersChangedFrameNumber))
         mShadersChangedFrameNumber))
     {
     {
         // First release all previous shaders, then load
         // First release all previous shaders, then load
         technique->releaseShaders();
         technique->releaseShaders();
         loadMaterialShaders(technique);
         loadMaterialShaders(technique);
-        
-        // Make sure that shaders for this pass are loaded now
-        if ((!vertexShaders.size()) || (!pixelShaders.size()))
-        {
-            // Do not log error, as it would result in a lot of spam
-            batch.mVertexShader = 0;
-            batch.mPixelShader = 0;
-            batch.mTechnique = 0;
-            batch.mPass = 0;
-            return;
-        }
     }
     }
     
     
-    batch.mTechnique = technique;
-    batch.mPass = pass;
-    
-    // Recognize light / vertex light pass from the amount of shaders
-    if ((vertexShaders.size() == 1) && (pixelShaders.size() == 1))
+    // Make sure shaders are loaded now
+    if ((vertexShaders.size()) && (pixelShaders.size()))
     {
     {
-        batch.mVertexShader = vertexShaders[0];
-        batch.mPixelShader = pixelShaders[0];
-    }
-    else
-    {
-        // Light pass
-        if (pixelShaders.size() > 1)
+        // Recognize light pass from the amount of shaders
+        if (pixelShaders.size() == 1)
+        {
+            unsigned vsi = 0;
+            if (batch.mNode->getNodeFlags() & NODE_GEOMETRY)
+                vsi = static_cast<GeometryNode*>(batch.mNode)->getGeometryType();
+            
+            batch.mVertexShader = vertexShaders[vsi];
+            batch.mPixelShader = pixelShaders[0];
+        }
+        else
         {
         {
             Light* light = batch.mForwardLight;
             Light* light = batch.mForwardLight;
             if (!light)
             if (!light)
@@ -730,6 +737,8 @@ void Pipeline::setBatchShaders(Batch& batch, MaterialTechnique* technique, Mater
             
             
             unsigned vsi = 0;
             unsigned vsi = 0;
             unsigned psi = 0;
             unsigned psi = 0;
+            if (batch.mNode->getNodeFlags() & NODE_GEOMETRY)
+                vsi = static_cast<GeometryNode*>(batch.mNode)->getGeometryType() * MAX_LIGHT_VS_VARIATIONS;
             
             
             // Negative lights have no specular or shadows
             // Negative lights have no specular or shadows
             if (!light->isNegative())
             if (!light->isNegative())
@@ -762,6 +771,17 @@ void Pipeline::setBatchShaders(Batch& batch, MaterialTechnique* technique, Mater
             batch.mPixelShader = pixelShaders[psi];
             batch.mPixelShader = pixelShaders[psi];
         }
         }
     }
     }
+    
+    // Log error if shaders could not be assigned, but only once per material
+    if ((!batch.mVertexShader) || (!batch.mPixelShader))
+    {
+        Material* parentMat = technique->getParent();
+        if (errorDisplayed.find(parentMat) == errorDisplayed.end())
+        {
+            errorDisplayed.insert(parentMat);
+            LOGERROR("Material " + parentMat->getName() + " has missing shaders");
+        }
+    }
 }
 }
 
 
 void Pipeline::setLightVolumeShaders(Batch& batch)
 void Pipeline::setLightVolumeShaders(Batch& batch)
@@ -939,21 +959,24 @@ void Pipeline::loadMaterialPassShaders(MaterialTechnique* technique, PassType pa
     switch (i->first)
     switch (i->first)
     {
     {
     default:
     default:
-        vertexShaders.resize(1);
+        vertexShaders.resize(MAX_GEOMETRYTYPES);
         pixelShaders.resize(1);
         pixelShaders.resize(1);
-        vertexShaders[0] = getVertexShader(vertexShaderName);
+        for (unsigned j = 0; j < MAX_GEOMETRYTYPES; ++j)
+            vertexShaders[j] = getVertexShader(vertexShaderName + geometryVSVariations[j]);
         pixelShaders[0] = getPixelShader(pixelShaderName);
         pixelShaders[0] = getPixelShader(pixelShaderName);
         break;
         break;
         
         
     case PASS_LIGHT:
     case PASS_LIGHT:
     case PASS_NEGATIVE:
     case PASS_NEGATIVE:
-        vertexShaders.resize(MAX_LIGHT_VS_VARIATIONS);
+        vertexShaders.resize(MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS);
         pixelShaders.resize(MAX_LIGHT_PS_VARIATIONS);
         pixelShaders.resize(MAX_LIGHT_PS_VARIATIONS);
         
         
-        for (unsigned j = 0; j < MAX_LIGHT_VS_VARIATIONS; ++j)
+        for (unsigned j = 0; j < MAX_GEOMETRYTYPES * MAX_LIGHT_VS_VARIATIONS; ++j)
         {
         {
-            if ((!(j & LVS_SHADOW)) || (allowShadows))
-                vertexShaders[j] = getVertexShader(vertexShaderName + lightVSVariations[j]);
+            unsigned g = j / MAX_LIGHT_VS_VARIATIONS;
+            unsigned l = j % MAX_LIGHT_VS_VARIATIONS;
+            if ((!(l & LVS_SHADOW)) || (allowShadows))
+                vertexShaders[j] = getVertexShader(vertexShaderName + lightVSVariations[l] + geometryVSVariations[g]);
             else
             else
                 vertexShaders[j].reset();
                 vertexShaders[j].reset();
         }
         }
@@ -1137,7 +1160,7 @@ void Pipeline::setupLightBatch(Batch& batch)
     light->overrideTransforms(0, *batch.mCamera, &model, &view);
     light->overrideTransforms(0, *batch.mCamera, &model, &view);
     
     
     float lightExtent = light->getVolumeExtent();
     float lightExtent = light->getVolumeExtent();
-    float lightViewDist = (light->getWorldPosition() - batch.mCamera->getWorldPosition()).getLength();
+    float lightViewDist = (light->getWorldPosition() - batch.mCamera->getWorldPosition()).getLengthFast();
     
     
     mRenderer->setAlphaTest(false);
     mRenderer->setAlphaTest(false);
     mRenderer->setBlendMode(light->isNegative() ? BLEND_MULTIPLY : BLEND_ADD);
     mRenderer->setBlendMode(light->isNegative() ? BLEND_MULTIPLY : BLEND_ADD);
@@ -1267,7 +1290,7 @@ void Pipeline::drawSplitLightToStencil(Camera& camera, Light* light, bool clear)
             light->overrideTransforms(0, camera, &model, &view);
             light->overrideTransforms(0, camera, &model, &view);
             
             
             float lightExtent = light->getVolumeExtent();
             float lightExtent = light->getVolumeExtent();
-            float lightViewDist = (light->getWorldPosition() - camera.getWorldPosition()).getLength();
+            float lightViewDist = (light->getWorldPosition() - camera.getWorldPosition()).getLengthFast();
             bool drawBackFaces = lightViewDist < (lightExtent + camera.getNearClip());
             bool drawBackFaces = lightViewDist < (lightExtent + camera.getNearClip());
             
             
             mRenderer->setAlphaTest(false);
             mRenderer->setAlphaTest(false);

+ 9 - 0
Engine/Renderer/RendererDefs.h

@@ -39,6 +39,15 @@ enum PrimitiveType
     LINE_LIST
     LINE_LIST
 };
 };
 
 
+//! Geometry type
+enum GeometryType
+{
+    GEOM_STATIC = 0,
+    GEOM_SKINNED,
+    GEOM_INSTANCED,
+    MAX_GEOMETRYTYPES
+};
+
 //! Blending mode
 //! Blending mode
 enum BlendMode
 enum BlendMode
 {
 {

+ 2 - 2
Engine/Renderer/View.cpp

@@ -361,7 +361,7 @@ void View::updateOccluders(std::vector<GeometryNode*>& occluders, Camera& camera
         
         
         // Check that occluder is big enough on the screen
         // Check that occluder is big enough on the screen
         const BoundingBox& box = node->getWorldBoundingBox();
         const BoundingBox& box = node->getWorldBoundingBox();
-        float diagonal = (box.mMax - box.mMin).getLength();
+        float diagonal = (box.mMax - box.mMin).getLengthFast();
         float compare;
         float compare;
         if (!camera.isOrthographic())
         if (!camera.isOrthographic())
             compare = diagonal * halfViewSize / node->getDistance();
             compare = diagonal * halfViewSize / node->getDistance();
@@ -804,7 +804,7 @@ bool View::isShadowCasterVisible(GeometryNode* geom, BoundingBox lightViewBox, c
         Ray extrusionRay(center, center.getNormalized());
         Ray extrusionRay(center, center.getNormalized());
         
         
         float extrusionDistance = shadowCamera.getFarClip();
         float extrusionDistance = shadowCamera.getFarClip();
-        float originalDistance = clamp(center.getLength(), M_EPSILON, extrusionDistance);
+        float originalDistance = clamp(center.getLengthFast(), M_EPSILON, extrusionDistance);
         
         
         // Because of the perspective, the bounding box must also grow when it is extruded to the distance
         // Because of the perspective, the bounding box must also grow when it is extruded to the distance
         float sizeFactor = extrusionDistance / originalDistance;
         float sizeFactor = extrusionDistance / originalDistance;

+ 1 - 1
Engine/Renderer/VolumeNode.cpp

@@ -282,7 +282,7 @@ void VolumeNode::setLightMask(unsigned mask)
 float VolumeNode::calculateDrawDistance(const Camera& camera, float minScreenSize)
 float VolumeNode::calculateDrawDistance(const Camera& camera, float minScreenSize)
 {
 {
     const BoundingBox& box = getWorldBoundingBox();
     const BoundingBox& box = getWorldBoundingBox();
-    float diagonal = (box.mMax - box.mMin).getLength();
+    float diagonal = (box.mMax - box.mMin).getLengthFast();
     float halfViewSize = camera.getHalfViewSize();
     float halfViewSize = camera.getHalfViewSize();
     
     
     return diagonal * halfViewSize / minScreenSize;
     return diagonal * halfViewSize / minScreenSize;

+ 42 - 39
Engine/UI/Button.cpp

@@ -35,8 +35,7 @@ Button::Button(const std::string& name) :
     mInactiveRect(0, 0, 0, 0),
     mInactiveRect(0, 0, 0, 0),
     mHoverRect(0, 0, 0, 0),
     mHoverRect(0, 0, 0, 0),
     mPressedRect(0, 0, 0, 0),
     mPressedRect(0, 0, 0, 0),
-    mHoverDelay(0.0f),
-    mPressedDelay(0.1f),
+    mLabelOffset(0, 0),
     mState(BUTTON_INACTIVE),
     mState(BUTTON_INACTIVE),
     mHoveringThisFrame(false)
     mHoveringThisFrame(false)
 {
 {
@@ -58,31 +57,16 @@ XMLElement Button::loadParameters(XMLFile* file, const std::string& elementName,
         setHoverRect(paramElem.getChildElement("hoverrect").getIntRect("value"));
         setHoverRect(paramElem.getChildElement("hoverrect").getIntRect("value"));
     if (paramElem.hasChildElement("pressedrect"))
     if (paramElem.hasChildElement("pressedrect"))
         setPressedRect(paramElem.getChildElement("pressedrect").getIntRect("value"));
         setPressedRect(paramElem.getChildElement("pressedrect").getIntRect("value"));
-    if (paramElem.hasChildElement("hoverdelay"))
-        setHoverDelay(paramElem.getChildElement("hoverdelay").getFloat("value"));
-    if (paramElem.hasChildElement("presseddelay"))
-        setPressedDelay(paramElem.getChildElement("presseddelay").getFloat("value"));
+    if (paramElem.hasChildElement("labeloffset"))
+        setLabelOffset(paramElem.getChildElement("labeloffset").getIntVector2("value"));
     
     
     return paramElem;
     return paramElem;
 }
 }
 
 
 void Button::update(float timeStep)
 void Button::update(float timeStep)
 {
 {
-    if ((mState != BUTTON_INACTIVE) && (mStateTime <= 0.0f))
-    {
-        if (!mHoveringThisFrame)
-        {
-            mState = BUTTON_INACTIVE;
-            mStateTime = 0.0f;
-        }
-        else
-        {
-            mState = BUTTON_HOVER;
-            mStateTime = mHoverDelay;
-        }
-    }
-    else
-        mStateTime -= timeStep;
+    if (!mHoveringThisFrame)
+        setState(BUTTON_INACTIVE);
     
     
     mHoveringThisFrame = false;
     mHoveringThisFrame = false;
 }
 }
@@ -107,13 +91,12 @@ void Button::getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quad
     BorderImage::getBatches(batches, quads, currentScissor);
     BorderImage::getBatches(batches, quads, currentScissor);
 }
 }
 
 
-void Button::onHover(const IntVector2& position, const IntVector2& screenPosition)
+void Button::onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 {
 {
-    if (mState != BUTTON_PRESSED)
-    {
-        mState = BUTTON_HOVER;
-        mStateTime = mHoverDelay;
-    }
+    if (buttons & MOUSEB_LEFT)
+        setState(BUTTON_PRESSED);
+    else
+        setState(BUTTON_HOVER);
     
     
     mHoveringThisFrame = true;
     mHoveringThisFrame = true;
 }
 }
@@ -122,8 +105,8 @@ void Button::onClick(const IntVector2& position, const IntVector2& screenPositio
 {
 {
     if (buttons & MOUSEB_LEFT)
     if (buttons & MOUSEB_LEFT)
     {
     {
-        mState = BUTTON_PRESSED;
-        mStateTime = mPressedDelay;
+        setState(BUTTON_PRESSED);
+        mHoveringThisFrame = true;
         
         
         using namespace Pressed;
         using namespace Pressed;
         
         
@@ -163,16 +146,6 @@ void Button::setPressedRect(int left, int top, int right, int bottom)
     mPressedRect = IntRect(left, top, right, bottom);
     mPressedRect = IntRect(left, top, right, bottom);
 }
 }
 
 
-void Button::setHoverDelay(float delay)
-{
-    mHoverDelay = delay;
-}
-
-void Button::setPressedDelay(float delay)
-{
-    mPressedDelay = delay;
-}
-
 void Button::setLabel(UIElement* label)
 void Button::setLabel(UIElement* label)
 {
 {
     removeChild(mLabel);
     removeChild(mLabel);
@@ -182,6 +155,36 @@ void Button::setLabel(UIElement* label)
         addChild(mLabel);
         addChild(mLabel);
         // Center the label element on the button forcibly
         // Center the label element on the button forcibly
         mLabel->setAlignment(HA_CENTER, VA_CENTER);
         mLabel->setAlignment(HA_CENTER, VA_CENTER);
+        updateLabelOffset();
+    }
+}
+
+void Button::setLabelOffset(const IntVector2& offset)
+{
+    mLabelOffset = offset;
+}
+
+void Button::setLabelOffset(int x, int y)
+{
+    mLabelOffset = IntVector2(x, y);
+}
+
+void Button::setState(ButtonState state)
+{
+    if (state != mState)
+    {
+        mState = state;
+        updateLabelOffset();
     }
     }
 }
 }
 
 
+void Button::updateLabelOffset()
+{
+    if (!mLabel)
+        return;
+    
+    if (mState == BUTTON_PRESSED)
+        mLabel->setPosition(mLabelOffset);
+    else
+        mLabel->setPosition(IntVector2::sZero);
+}

+ 14 - 15
Engine/UI/Button.h

@@ -50,7 +50,7 @@ public:
     //! Return UI rendering batches
     //! Return UI rendering batches
     virtual void getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor);
     virtual void getBatches(std::vector<UIBatch>& batches, std::vector<UIQuad>& quads, const IntRect& currentScissor);
     //! React to mouse hover
     //! React to mouse hover
-    virtual void onHover(const IntVector2& position, const IntVector2& screenPosition);
+    virtual void onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons);
     //! React to mouse click
     //! React to mouse click
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons);
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons);
     
     
@@ -66,12 +66,12 @@ public:
     void setPressedRect(const IntRect& rect);
     void setPressedRect(const IntRect& rect);
     //! Set pressed image rectangle
     //! Set pressed image rectangle
     void setPressedRect(int left, int top, int right, int bottom);
     void setPressedRect(int left, int top, int right, int bottom);
-    //! Set hovering image delay
-    void setHoverDelay(float delay);
-    //! Set pressed image delay
-    void setPressedDelay(float delay);
     //! Set optional label UI element
     //! Set optional label UI element
     void setLabel(UIElement* label);
     void setLabel(UIElement* label);
+    //! Set label offset on press
+    void setLabelOffset(const IntVector2& offset);
+    //! Set label offset on press
+    void setLabelOffset(int x, int y);
     
     
     //! Return inactive image rectangle
     //! Return inactive image rectangle
     const IntRect& getInactiveRect() const { return mInactiveRect; }
     const IntRect& getInactiveRect() const { return mInactiveRect; }
@@ -79,14 +79,17 @@ public:
     const IntRect& getHoverRect() const { return mHoverRect; }
     const IntRect& getHoverRect() const { return mHoverRect; }
     //! Return pressed image rectangle
     //! Return pressed image rectangle
     const IntRect& getPressedRect() const { return mPressedRect; }
     const IntRect& getPressedRect() const { return mPressedRect; }
-    //! Return hovering image delay
-    float getHoverDelay() const { return mHoverDelay; }
-    //! Return pressed image delay
-    float getPressedDelay() const { return mPressedDelay; }
     //! Return label UI element
     //! Return label UI element
     UIElement* getLabel() const { return mLabel; }
     UIElement* getLabel() const { return mLabel; }
+    //! Return label offset on press
+    const IntVector2& getLabelOffset() const { return mLabelOffset; }
     
     
 protected:
 protected:
+    //! Set new state
+    void setState(ButtonState state);
+    //! Set offset of label depending on button press state
+    void updateLabelOffset();
+    
     //! Label UI element
     //! Label UI element
     SharedPtr<UIElement> mLabel;
     SharedPtr<UIElement> mLabel;
     //! Inactive image rectangle
     //! Inactive image rectangle
@@ -95,12 +98,8 @@ protected:
     IntRect mHoverRect;
     IntRect mHoverRect;
     //! Pressed image rectangle
     //! Pressed image rectangle
     IntRect mPressedRect;
     IntRect mPressedRect;
-    //! Hovering image delay
-    float mHoverDelay;
-    //! Pressed image delay
-    float mPressedDelay;
-    //! State timer
-    float mStateTime;
+    //! Label offset on press
+    IntVector2 mLabelOffset;
     //! Current state
     //! Current state
     ButtonState mState;
     ButtonState mState;
     //! Hovering flag
     //! Hovering flag

+ 1 - 1
Engine/UI/UI.cpp

@@ -167,7 +167,7 @@ void UI::update(float timeStep)
         IntVector2 pos = mCursor->getPosition();
         IntVector2 pos = mCursor->getPosition();
         UIElement* element = getElementAt(pos);
         UIElement* element = getElementAt(pos);
         if (element)
         if (element)
-            element->onHover(element->screenToElement(pos), pos);
+            element->onHover(element->screenToElement(pos), pos, mMouseButtons);
     }
     }
     
     
     {
     {

+ 1 - 1
Engine/UI/UIElement.cpp

@@ -231,7 +231,7 @@ void UIElement::onChar(unsigned key)
 {
 {
 }
 }
 
 
-void UIElement::onHover(const IntVector2& position, const IntVector2& screenPosition)
+void UIElement::onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons)
 {
 {
 }
 }
 
 

+ 1 - 1
Engine/UI/UIElement.h

@@ -80,7 +80,7 @@ public:
     virtual float getDerivedOpacity();
     virtual float getDerivedOpacity();
     
     
     //! React to mouse hover
     //! React to mouse hover
-    virtual void onHover(const IntVector2& position, const IntVector2& screenPosition);
+    virtual void onHover(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons);
     //! React to mouse click
     //! React to mouse click
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons);
     virtual void onClick(const IntVector2& position, const IntVector2& screenPosition, unsigned buttons);
     //! React to mouse drag start
     //! React to mouse drag start

+ 3 - 3
Examples/Test/Application.cpp

@@ -200,7 +200,7 @@ void Application::init()
     
     
     XMLFile* uiSetup = mCache->getResource<XMLFile>("UI/UI.xml");
     XMLFile* uiSetup = mCache->getResource<XMLFile>("UI/UI.xml");
     
     
-    SharedPtr<Cursor> cursor(new Cursor("Cursor"));
+    Cursor* cursor = new Cursor("Cursor");
     cursor->loadParameters(uiSetup, "Cursor", mCache);
     cursor->loadParameters(uiSetup, "Cursor", mCache);
     cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
     cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
     ui->setCursor(cursor);
     ui->setCursor(cursor);
@@ -340,7 +340,7 @@ void Application::createScene()
         
         
         StaticModel* object = new StaticModel(octree);
         StaticModel* object = new StaticModel(octree);
         object->setModel(mCache->getResource<Model>("Models/Mushroom.mdl"));
         object->setModel(mCache->getResource<Model>("Models/Mushroom.mdl"));
-        object->setMaterial(mCache->getResource<Material>("Materials/MushroomStatic.xml"));
+        object->setMaterial(mCache->getResource<Material>("Materials/Mushroom.xml"));
         object->setCastShadows(true);
         object->setCastShadows(true);
         object->setOccluder(true);
         object->setOccluder(true);
         body->addChild(object);
         body->addChild(object);
@@ -355,7 +355,7 @@ void Application::createScene()
     {
     {
         InstancedModel* instanced = new InstancedModel(octree);
         InstancedModel* instanced = new InstancedModel(octree);
         instanced->setModel(mCache->getResource<Model>("Models/Mushroom.mdl"));
         instanced->setModel(mCache->getResource<Model>("Models/Mushroom.mdl"));
-        instanced->setMaterial(mCache->getResource<Material>("Materials/MushroomInstanced.xml"));
+        instanced->setMaterial(mCache->getResource<Material>("Materials/Mushroom.xml"));
         instanced->setPosition(Vector3(random() * 160.0f - 80.0f, 0.0f, random() * 160.0f - 80.0f));
         instanced->setPosition(Vector3(random() * 160.0f - 80.0f, 0.0f, random() * 160.0f - 80.0f));
         instanced->setCastShadows(true);
         instanced->setCastShadows(true);
         instanced->setNumInstances(50);
         instanced->setNumInstances(50);

+ 2 - 2
SourceAssets/Shaders/Deferred/GBuffer.xml

@@ -1,10 +1,10 @@
 <shaders>
 <shaders>
     <shader name="GBuffer" type="vs">
     <shader name="GBuffer" type="vs">
+        <option name="Normal" define="NORMALMAP" />
         <variation name="" />
         <variation name="" />
         <variation name="Skinned" define="SKINNED" />
         <variation name="Skinned" define="SKINNED" />
         <variation name="Instanced" define="INSTANCED" />
         <variation name="Instanced" define="INSTANCED" />
-        <option name="Normal" define="NORMALMAP" />
-    </shader>    
+    </shader>
     <shader name="GBuffer" type="ps">
     <shader name="GBuffer" type="ps">
         <option name="Diff" define="DIFFMAP" />
         <option name="Diff" define="DIFFMAP" />
         <option name="Normal" define="NORMALMAP" />
         <option name="Normal" define="NORMALMAP" />

+ 3 - 3
SourceAssets/Shaders/Forward.xml

@@ -1,8 +1,5 @@
 <shaders>
 <shaders>
     <shader name="Forward" type="vs">
     <shader name="Forward" type="vs">
-        <variation name="" />
-        <variation name="Skinned" define="SKINNED" />
-        <variation name="Instanced" define="INSTANCED" />
         <option name="Unlit" define="UNLIT">
         <option name="Unlit" define="UNLIT">
             <exclude name="Normal" />
             <exclude name="Normal" />
             <exclude name="Spot" />
             <exclude name="Spot" />
@@ -11,6 +8,9 @@
         <option name="Normal" define="NORMALMAP" />
         <option name="Normal" define="NORMALMAP" />
         <option name="Spot" define="SPOTLIGHT" />
         <option name="Spot" define="SPOTLIGHT" />
         <option name="Shadow" define="SHADOW" />
         <option name="Shadow" define="SHADOW" />
+        <variation name="" />
+        <variation name="Skinned" define="SKINNED" />
+        <variation name="Instanced" define="INSTANCED" />
     </shader>
     </shader>
     <shader name="Forward" type="ps">
     <shader name="Forward" type="ps">
         <option name="Diff" define="DIFFMAP" />
         <option name="Diff" define="DIFFMAP" />

+ 1 - 1
SourceAssets/Shaders/Prepass/GBuffer.xml

@@ -1,9 +1,9 @@
 <shaders>
 <shaders>
     <shader name="GBuffer" type="vs">
     <shader name="GBuffer" type="vs">
+        <option name="Normal" define="NORMALMAP" />
         <variation name="" />
         <variation name="" />
         <variation name="Skinned" define="SKINNED" />
         <variation name="Skinned" define="SKINNED" />
         <variation name="Instanced" define="INSTANCED" />
         <variation name="Instanced" define="INSTANCED" />
-        <option name="Normal" define="NORMALMAP" />
     </shader>
     </shader>
     <shader name="GBuffer" type="ps">
     <shader name="GBuffer" type="ps">
         <option name="Normal" define="NORMALMAP" />
         <option name="Normal" define="NORMALMAP" />