Browse Source

Urho and Third Party updates (+14 squashed commits)
Squashed commits:
[0adf60b] Update Delta on Android C#
[f6d7cc2] Only build 64 bit iOS
[7e978c5] Adjustments to build setup of atomic projects to get rid of dependency errors on windows builds.
[2478856] Fix c++11 assert in EventHandler().
[54cd173] UI::GetWidgetAt() returns 0 if ui subsystem is not initialized.
[6876671] Fix sdl build error on some systems.
[0485d02] Urho3D -> Atomic strings
[0b29649] Pick right overload when using AnimatedModel.Model property
[2899b97] Update Android activity to SDL 2.0.5
[6dbf584] Updating CoreData
[f57e6a3] Default IK subsystem off, readd necessary C# enum values for Box2D
[172f5d9] Updates
[31aec9e] [2D] Fix issue when rigid body has been deleted during event, remove unnecessary C# enum massaging
[bc4f8be] Urho and Third Party updates (+5 squashed commits)
Squashed commits:
[9da0435] SDL 2.0.5 update, macOS building running
[5d87733] Fix directx build errors
[50a7a5a] Prevents newly subscribed handlers from executing on very this frame. Fixes E_KEYUP causing FeatureSamples to exit instead of returning to menu.
[5d60c4c] Script binding generation adjustments
[c449f18] Sync with upstream 129205a9b1fd94573c81feba76f897990990e8ec

Rokas Kupstys 8 years ago
parent
commit
404afffddf
100 changed files with 1829 additions and 492 deletions
  1. 21 1
      AUTHORS.md
  2. 2 2
      Build/CMake/Modules/AtomicIOS.cmake
  3. 1 1
      Build/CMake/Modules/AtomicMac.cmake
  4. 118 33
      Data/AtomicEditor/Deployment/Android/src/org/libsdl/app/SDLActivity.java
  5. 1 1
      Resources/CoreData/Materials/Particle.xml
  6. 4 1
      Resources/CoreData/RenderPaths/Deferred.xml
  7. 3 1
      Resources/CoreData/RenderPaths/DeferredHWDepth.xml
  8. 3 1
      Resources/CoreData/RenderPaths/ForwardDepth.xml
  9. 4 4
      Resources/CoreData/RenderPaths/ForwardHWDepth.xml
  10. 3 1
      Resources/CoreData/RenderPaths/PBRDeferred.xml
  11. 3 1
      Resources/CoreData/RenderPaths/PBRDeferredHWDepth.xml
  12. 4 1
      Resources/CoreData/RenderPaths/Prepass.xml
  13. 3 1
      Resources/CoreData/RenderPaths/PrepassHWDepth.xml
  14. 20 8
      Resources/CoreData/Shaders/GLSL/IBL.glsl
  15. 22 10
      Resources/CoreData/Shaders/GLSL/Lighting.glsl
  16. 35 0
      Resources/CoreData/Shaders/GLSL/LitParticle.glsl
  17. 3 3
      Resources/CoreData/Shaders/GLSL/LitSolid.glsl
  18. 96 5
      Resources/CoreData/Shaders/GLSL/PBR.glsl
  19. 11 3
      Resources/CoreData/Shaders/GLSL/PBRDeferred.glsl
  20. 14 5
      Resources/CoreData/Shaders/GLSL/PBRLitSolid.glsl
  21. 3 3
      Resources/CoreData/Shaders/GLSL/Shadow.glsl
  22. 82 24
      Resources/CoreData/Shaders/GLSL/Text.glsl
  23. 19 7
      Resources/CoreData/Shaders/GLSL/Transform.glsl
  24. 14 4
      Resources/CoreData/Shaders/GLSL/Uniforms.glsl
  25. 0 3
      Resources/CoreData/Shaders/GLSL/Unlit.glsl
  26. 90 0
      Resources/CoreData/Shaders/GLSL/UnlitParticle.glsl
  27. 7 7
      Resources/CoreData/Shaders/GLSL/Vegetation.glsl
  28. 1 1
      Resources/CoreData/Shaders/HLSL/Depth.hlsl
  29. 37 14
      Resources/CoreData/Shaders/HLSL/IBL.hlsl
  30. 24 10
      Resources/CoreData/Shaders/HLSL/Lighting.hlsl
  31. 49 0
      Resources/CoreData/Shaders/HLSL/LitParticle.hlsl
  32. 4 4
      Resources/CoreData/Shaders/HLSL/LitSolid.hlsl
  33. 101 8
      Resources/CoreData/Shaders/HLSL/PBR.hlsl
  34. 10 2
      Resources/CoreData/Shaders/HLSL/PBRDeferred.hlsl
  35. 15 8
      Resources/CoreData/Shaders/HLSL/PBRLitSolid.hlsl
  36. 9 6
      Resources/CoreData/Shaders/HLSL/Shadow.hlsl
  37. 3 0
      Resources/CoreData/Shaders/HLSL/Skybox.hlsl
  38. 59 21
      Resources/CoreData/Shaders/HLSL/Text.hlsl
  39. 9 2
      Resources/CoreData/Shaders/HLSL/Transform.hlsl
  40. 10 0
      Resources/CoreData/Shaders/HLSL/Uniforms.hlsl
  41. 145 0
      Resources/CoreData/Shaders/HLSL/UnlitParticle.hlsl
  42. 6 6
      Resources/CoreData/Shaders/HLSL/Vegetation.hlsl
  43. 5 0
      Resources/CoreData/Techniques/DiffLitParticleAlphaSoft.xml
  44. 5 0
      Resources/CoreData/Techniques/DiffLitParticleAlphaSoftExpand.xml
  45. 3 0
      Resources/CoreData/Techniques/DiffUnlitParticleAdd.xml
  46. 3 0
      Resources/CoreData/Techniques/DiffUnlitParticleAddSoft.xml
  47. 3 0
      Resources/CoreData/Techniques/DiffUnlitParticleAddSoftExpand.xml
  48. 3 0
      Resources/CoreData/Techniques/DiffUnlitParticleAlpha.xml
  49. 3 0
      Resources/CoreData/Techniques/DiffUnlitParticleAlphaSoft.xml
  50. 3 0
      Resources/CoreData/Techniques/DiffUnlitParticleAlphaSoftExpand.xml
  51. 15 0
      Script/AtomicNET/AtomicNET/Graphics/AnimatedModel.cs
  52. 1 1
      Script/AtomicNET/AtomicNET/IO/File.cs
  53. 14 0
      Script/AtomicNET/Platform/Android/JavaSDL/src/main/java/org/libsdl/app/AtomicActivity.java
  54. 298 95
      Script/AtomicNET/Platform/Android/JavaSDL/src/main/java/org/libsdl/app/SDLActivity.java
  55. 87 74
      Script/AtomicNET/Platform/Android/JavaSDL/src/main/java/org/libsdl/app/SDLSurface.java
  56. BIN
      Script/AtomicNET/Platform/Android/JavaSDLBin/atomicjavasdl-release.aar
  57. 3 1
      Script/Packages/Atomic/Core.json
  58. 1 1
      Script/Packages/Atomic/IO.json
  59. 1 1
      Script/Packages/Atomic/Scene.json
  60. 3 8
      Source/Atomic/Atomic2D/AnimatedSprite2D.cpp
  61. 2 2
      Source/Atomic/Atomic2D/AnimatedSprite2D.h
  62. 7 12
      Source/Atomic/Atomic2D/AnimationSet2D.cpp
  63. 3 3
      Source/Atomic/Atomic2D/AnimationSet2D.h
  64. 1 1
      Source/Atomic/Atomic2D/Atomic2D.cpp
  65. 1 1
      Source/Atomic/Atomic2D/Atomic2D.h
  66. 44 0
      Source/Atomic/Atomic2D/Atomic2DEvents.h
  67. 1 1
      Source/Atomic/Atomic2D/CollisionBox2D.cpp
  68. 1 1
      Source/Atomic/Atomic2D/CollisionBox2D.h
  69. 1 1
      Source/Atomic/Atomic2D/CollisionChain2D.cpp
  70. 1 1
      Source/Atomic/Atomic2D/CollisionChain2D.h
  71. 1 1
      Source/Atomic/Atomic2D/CollisionCircle2D.cpp
  72. 1 1
      Source/Atomic/Atomic2D/CollisionCircle2D.h
  73. 1 1
      Source/Atomic/Atomic2D/CollisionEdge2D.cpp
  74. 1 1
      Source/Atomic/Atomic2D/CollisionEdge2D.h
  75. 1 1
      Source/Atomic/Atomic2D/CollisionPolygon2D.cpp
  76. 1 1
      Source/Atomic/Atomic2D/CollisionPolygon2D.h
  77. 9 1
      Source/Atomic/Atomic2D/CollisionShape2D.cpp
  78. 1 1
      Source/Atomic/Atomic2D/CollisionShape2D.h
  79. 36 3
      Source/Atomic/Atomic2D/Constraint2D.cpp
  80. 10 2
      Source/Atomic/Atomic2D/Constraint2D.h
  81. 27 3
      Source/Atomic/Atomic2D/ConstraintDistance2D.cpp
  82. 6 1
      Source/Atomic/Atomic2D/ConstraintDistance2D.h
  83. 11 3
      Source/Atomic/Atomic2D/ConstraintFriction2D.cpp
  84. 1 1
      Source/Atomic/Atomic2D/ConstraintFriction2D.h
  85. 6 2
      Source/Atomic/Atomic2D/ConstraintGear2D.cpp
  86. 1 1
      Source/Atomic/Atomic2D/ConstraintGear2D.h
  87. 26 6
      Source/Atomic/Atomic2D/ConstraintMotor2D.cpp
  88. 1 1
      Source/Atomic/Atomic2D/ConstraintMotor2D.h
  89. 21 16
      Source/Atomic/Atomic2D/ConstraintMouse2D.cpp
  90. 1 3
      Source/Atomic/Atomic2D/ConstraintMouse2D.h
  91. 31 7
      Source/Atomic/Atomic2D/ConstraintPrismatic2D.cpp
  92. 1 1
      Source/Atomic/Atomic2D/ConstraintPrismatic2D.h
  93. 1 1
      Source/Atomic/Atomic2D/ConstraintPulley2D.cpp
  94. 1 1
      Source/Atomic/Atomic2D/ConstraintPulley2D.h
  95. 31 7
      Source/Atomic/Atomic2D/ConstraintRevolute2D.cpp
  96. 1 1
      Source/Atomic/Atomic2D/ConstraintRevolute2D.h
  97. 6 2
      Source/Atomic/Atomic2D/ConstraintRope2D.cpp
  98. 1 1
      Source/Atomic/Atomic2D/ConstraintRope2D.h
  99. 11 3
      Source/Atomic/Atomic2D/ConstraintWeld2D.cpp
  100. 1 1
      Source/Atomic/Atomic2D/ConstraintWeld2D.h

+ 21 - 1
AUTHORS.md

@@ -72,27 +72,35 @@ Licensed under the MIT license, see [License.txt](https://github.com/urho3d/Urho
 
 
 ##Credits
 ##Credits
 Urho3D development, contributions and bugfixes by:
 Urho3D development, contributions and bugfixes by:
-- Lasse Öörni ([email protected], AgentC at GameDev.net)
+- Lasse Öörni
 - Wei Tjong Yao
 - Wei Tjong Yao
 - Aster Jian
 - Aster Jian
 - Vivienne Anthony
 - Vivienne Anthony
 - Colin Barrett
 - Colin Barrett
 - Erik Beran
 - Erik Beran
+- Gauthier Billot
 - Loic Blot
 - Loic Blot
 - Danny Boisvert
 - Danny Boisvert
 - Sergey Bosko
 - Sergey Bosko
+- Lisandro Bruzzo
 - Carlo Carollo
 - Carlo Carollo
 - Pete Chown
 - Pete Chown
 - Christian Clavet
 - Christian Clavet
 - Sebastian Delatorre (primitivewaste)
 - Sebastian Delatorre (primitivewaste)
 - Josh Engebretson
 - Josh Engebretson
+- Simon Flores
+- Manuel Freiberger
 - Chris Friesen
 - Chris Friesen
 - Alex Fuller
 - Alex Fuller
 - Henrik Heino
 - Henrik Heino
 - Mika Heinonen
 - Mika Heinonen
+- Victor Holt
+- Johnathan Jenkins
 - Jukka Jylänki
 - Jukka Jylänki
 - Graham King
 - Graham King
 - Jason Kinzer
 - Jason Kinzer
+- Cameron Kline
+- Jan Korous
 - Eugene Kozlov
 - Eugene Kozlov
 - Gunnar Kriik
 - Gunnar Kriik
 - Aliaksandr Kryvashein
 - Aliaksandr Kryvashein
@@ -100,11 +108,13 @@ Urho3D development, contributions and bugfixes by:
 - Rokas Kupstys
 - Rokas Kupstys
 - Ali Kämäräinen
 - Ali Kämäräinen
 - Pete Leigh
 - Pete Leigh
+- Arnis Lielturks
 - Frode 'Modanung' Lindeijer
 - Frode 'Modanung' Lindeijer
 - Thorbjørn Lindeijer
 - Thorbjørn Lindeijer
 - Nathanial Lydick
 - Nathanial Lydick
 - Xavier Maupeu
 - Xavier Maupeu
 - Jonne Nauha
 - Jonne Nauha
+- Huy Nguyen
 - Paul Noome
 - Paul Noome
 - David Palacios
 - David Palacios
 - Alex Parlett
 - Alex Parlett
@@ -113,27 +123,35 @@ Urho3D development, contributions and bugfixes by:
 - Vladimir Pobedinsky
 - Vladimir Pobedinsky
 - Franck Poulain
 - Franck Poulain
 - Pranjal Raihan
 - Pranjal Raihan
+- Mariusz Richtscheid
 - Nick Royer
 - Nick Royer
+- Jonathan Sandusky
 - Miika Santala
 - Miika Santala
 - Anatoly Sennov
 - Anatoly Sennov
+- Matan Shukry
 - Bengt Soderstrom
 - Bengt Soderstrom
 - Hualin Song
 - Hualin Song
 - James Thomas
 - James Thomas
 - Joshua Tippetts
 - Joshua Tippetts
+- Konstantin Tomashevich
 - Yusuf Umar
 - Yusuf Umar
+- Mateus Vendramini
 - Daniel Wiberg
 - Daniel Wiberg
 - Steven Zhang
 - Steven Zhang
 - AGreatFish
 - AGreatFish
 - BlueMagnificent
 - BlueMagnificent
 - Enhex
 - Enhex
+- Fastran
 - Firegorilla
 - Firegorilla
 - Gordon-F
 - Gordon-F
 - Lumak
 - Lumak
 - Magic.Lixin
 - Magic.Lixin
 - Mike3D
 - Mike3D
 - MonkeyFirst
 - MonkeyFirst
+- Ner'zhul
 - Newb I the Newbd
 - Newb I the Newbd
 - OvermindDL1
 - OvermindDL1
+- PredatorMF
 - Scellow
 - Scellow
 - Skrylar
 - Skrylar
 - TheComet93
 - TheComet93
@@ -149,6 +167,7 @@ Urho3D development, contributions and bugfixes by:
 - dragonCASTjosh
 - dragonCASTjosh
 - feltech
 - feltech
 - fredakilla
 - fredakilla
+- gleblebedev
 - hdunderscore
 - hdunderscore
 - lvshiling
 - lvshiling
 - marynate
 - marynate
@@ -156,6 +175,7 @@ Urho3D development, contributions and bugfixes by:
 - neat3d
 - neat3d
 - nemerle
 - nemerle
 - ninjastone
 - ninjastone
+- orefkov
 - proller
 - proller
 - raould
 - raould
 - rasteron
 - rasteron

+ 2 - 2
Build/CMake/Modules/AtomicIOS.cmake

@@ -10,7 +10,7 @@ set(CMAKE_OSX_SYSROOT iphoneos)    # Set Base SDK to "Latest iOS"
 set(CMAKE_OSX_DEPLOYMENT_TARGET "")
 set(CMAKE_OSX_DEPLOYMENT_TARGET "")
 set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES)
 set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES)
 
 
-set(CMAKE_OSX_ARCHITECTURES $(ARCHS_STANDARD_INCLUDING_64_BIT))
+set(CMAKE_OSX_ARCHITECTURES arm64)
 
 
 # This is a CMake hack in order to make standard CMake check modules that use try_compile() internally work on iOS platform
 # This is a CMake hack in order to make standard CMake check modules that use try_compile() internally work on iOS platform
 # The injected "flags" are not compiler flags, they are actually CMake variables meant for another CMake subprocess that builds the source file being passed in the try_compile() command
 # The injected "flags" are not compiler flags, they are actually CMake variables meant for another CMake subprocess that builds the source file being passed in the try_compile() command
@@ -24,4 +24,4 @@ message(${IOS_SYSROOT})
 
 
 set(CMAKE_FIND_ROOT_PATH ${IOS_SYSROOT})
 set(CMAKE_FIND_ROOT_PATH ${IOS_SYSROOT})
 
 
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AudioToolbox -framework CoreAudio -framework CoreGraphics -framework Foundation -framework OpenGLES -framework QuartzCore -framework UIKit -framework CoreMotion -framework GameController")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AudioToolbox -framework AVFoundation -framework CoreAudio -framework CoreGraphics -framework Foundation -framework OpenGLES -framework QuartzCore -framework UIKit -framework CoreMotion -framework GameController")

+ 1 - 1
Build/CMake/Modules/AtomicMac.cmake

@@ -20,4 +20,4 @@ else ()
 endif ()
 endif ()
 
 
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -std=gnu++11 -stdlib=libc++")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -std=gnu++11 -stdlib=libc++")
-set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -framework AudioUnit -framework Carbon -framework Cocoa -framework CoreAudio -framework CoreVideo -framework ForceFeedback -framework IOKit -framework OpenGL -framework CoreServices -framework Security")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -framework AudioToolbox -framework Carbon -framework Cocoa -framework CoreAudio -framework CoreVideo -framework ForceFeedback -framework IOKit -framework OpenGL -framework CoreServices -framework Security")

+ 118 - 33
Data/AtomicEditor/Deployment/Android/src/org/libsdl/app/SDLActivity.java

@@ -21,7 +21,7 @@ import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsoluteLayout;
+import android.widget.RelativeLayout;
 import android.widget.Button;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.TextView;
@@ -60,6 +60,7 @@ public class SDLActivity extends Activity {
 
 
     // Audio
     // Audio
     protected static AudioTrack mAudioTrack;
     protected static AudioTrack mAudioTrack;
+    protected static AudioRecord mAudioRecord;
 
 
     // Urho3D: flag to load the .so and a new method load them
     // Urho3D: flag to load the .so and a new method load them
     private static boolean mIsSharedLibraryLoaded = false;
     private static boolean mIsSharedLibraryLoaded = false;
@@ -92,6 +93,7 @@ public class SDLActivity extends Activity {
         mJoystickHandler = null;
         mJoystickHandler = null;
         mSDLThread = null;
         mSDLThread = null;
         mAudioTrack = null;
         mAudioTrack = null;
+        mAudioRecord = null;
         mExitCalledFromJava = false;
         mExitCalledFromJava = false;
         mIsPaused = false;
         mIsPaused = false;
         mIsSurfaceReady = false;
         mIsSurfaceReady = false;
@@ -182,7 +184,7 @@ public class SDLActivity extends Activity {
             mJoystickHandler = new SDLJoystickHandler();
             mJoystickHandler = new SDLJoystickHandler();
         }
         }
 
 
-        mLayout = new AbsoluteLayout(this);
+        mLayout = new RelativeLayout(this);
         mLayout.addView(mSurface);
         mLayout.addView(mSurface);
 
 
         setContentView(mLayout);
         setContentView(mLayout);
@@ -380,7 +382,10 @@ public class SDLActivity extends Activity {
                 break;
                 break;
             case COMMAND_TEXTEDIT_HIDE:
             case COMMAND_TEXTEDIT_HIDE:
                 if (mTextEdit != null) {
                 if (mTextEdit != null) {
-                    mTextEdit.setVisibility(View.GONE);
+                    // Note: On some devices setting view to GONE creates a flicker in landscape.
+                    // Setting the View's sizes to 0 is similar to GONE but without the flicker.
+                    // The sizes will be set to useful values when the keyboard is shown again.
+                    mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0));
 
 
                     InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
                     InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
                     imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
                     imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
@@ -518,8 +523,9 @@ public class SDLActivity extends Activity {
 
 
         @Override
         @Override
         public void run() {
         public void run() {
-            AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(
-                    w, h + HEIGHT_PADDING, x, y);
+            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING);
+            params.leftMargin = x;
+            params.topMargin = y;
 
 
             if (mTextEdit == null) {
             if (mTextEdit == null) {
                 mTextEdit = new DummyEdit(getContext());
                 mTextEdit = new DummyEdit(getContext());
@@ -557,7 +563,7 @@ public class SDLActivity extends Activity {
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      */
      */
-    public static int audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+    public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
         int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
         int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
         int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
         int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
         int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
         int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
@@ -636,13 +642,72 @@ public class SDLActivity extends Activity {
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      */
      */
-    public static void audioQuit() {
+    public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+        int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
+        int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
+        int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
+
+        Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+        // Let the user pick a larger buffer if they really want -- but ye
+        // gods they probably shouldn't, the minimums are horrifyingly high
+        // latency already
+        desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+        if (mAudioRecord == null) {
+            mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
+                    channelConfig, audioFormat, desiredFrames * frameSize);
+
+            // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
+            if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
+                Log.e(TAG, "Failed during initialization of AudioRecord");
+                mAudioRecord.release();
+                mAudioRecord = null;
+                return -1;
+            }
+
+            mAudioRecord.startRecording();
+        }
+
+        Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+        return 0;
+    }
+
+    /** This method is called by SDL using JNI. */
+    public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
+        // !!! FIXME: this is available in API Level 23. Until then, we always block.  :(
+        //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+        return mAudioRecord.read(buffer, 0, buffer.length);
+    }
+
+    /** This method is called by SDL using JNI. */
+    public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
+        // !!! FIXME: this is available in API Level 23. Until then, we always block.  :(
+        //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+        return mAudioRecord.read(buffer, 0, buffer.length);
+    }
+
+
+    /** This method is called by SDL using JNI. */
+    public static void audioClose() {
         if (mAudioTrack != null) {
         if (mAudioTrack != null) {
             mAudioTrack.stop();
             mAudioTrack.stop();
+            mAudioTrack.release();
             mAudioTrack = null;
             mAudioTrack = null;
         }
         }
     }
     }
 
 
+    /** This method is called by SDL using JNI. */
+    public static void captureClose() {
+        if (mAudioRecord != null) {
+            mAudioRecord.stop();
+            mAudioRecord.release();
+            mAudioRecord = null;
+        }
+    }
+
+
     // Input
     // Input
 
 
     /**
     /**
@@ -677,6 +742,21 @@ public class SDLActivity extends Activity {
         }
         }
     }
     }
 
 
+    // Check if a given device is considered a possible SDL joystick
+    public static boolean isDeviceSDLJoystick(int deviceId) {
+        InputDevice device = InputDevice.getDevice(deviceId);
+        // We cannot use InputDevice.isVirtual before API 16, so let's accept
+        // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
+        if ((device == null) || (deviceId < 0)) {
+            return false;
+        }
+        int sources = device.getSources();
+        return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
+                ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
+                ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
+        );
+    }
+
     // APK expansion files support
     // APK expansion files support
 
 
     /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
     /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
@@ -685,15 +765,6 @@ public class SDLActivity extends Activity {
     /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
     /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
     private Method expansionFileMethod;
     private Method expansionFileMethod;
 
 
-    /**
-     * This method was called by SDL using JNI.
-     * @deprecated because of an incorrect name
-     */
-    @Deprecated
-    public InputStream openAPKExtensionInputStream(String fileName) throws IOException {
-        return openAPKExpansionInputStream(fileName);
-    }
-
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      * @return an InputStream on success or null if no expansion file was used.
      * @return an InputStream on success or null if no expansion file was used.
@@ -1183,11 +1254,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     @Override
     @Override
     public boolean onKey(View  v, int keyCode, KeyEvent event) {
     public boolean onKey(View  v, int keyCode, KeyEvent event) {
         // Dispatch the different events depending on where they come from
         // Dispatch the different events depending on where they come from
-        // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
-        // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD
-
-        if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 ||
-                   (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
+        // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
+        // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
+        //
+        // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
+        // SOURCE_JOYSTICK, while its key events arrive from the keyboard source
+        // So, retrieve the device itself and check all of its sources
+        if (SDLActivity.isDeviceSDLJoystick(event.getDeviceId())) {
+            // Note that we process events with specific key codes here
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
                 if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
                     return true;
                     return true;
@@ -1199,7 +1273,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
             }
         }
         }
 
 
-        if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
+        if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 //Log.v("SDL", "key down: " + keyCode);
                 //Log.v("SDL", "key down: " + keyCode);
                 SDLActivity.onNativeKeyDown(keyCode);
                 SDLActivity.onNativeKeyDown(keyCode);
@@ -1212,6 +1286,20 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
             }
         }
         }
 
 
+        if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) {
+            // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
+            // they are ignored here because sending them as mouse input to SDL is messy
+            if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
+                switch (event.getAction()) {
+                case KeyEvent.ACTION_DOWN:
+                case KeyEvent.ACTION_UP:
+                    // mark the event as handled or it will be handled by system
+                    // handling KEYCODE_BACK by system will call onBackPressed()
+                    return true;
+                }
+            }
+        }
+
         return false;
         return false;
     }
     }
 
 
@@ -1230,7 +1318,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
         // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
         if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) {
         if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) {
             if (Build.VERSION.SDK_INT < 14) {
             if (Build.VERSION.SDK_INT < 14) {
-                mouseButton = 1;    // For Android==12 all mouse buttons are the left button
+                mouseButton = 1; // all mouse buttons are the left button
             } else {
             } else {
                 try {
                 try {
                     mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
                     mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
@@ -1345,7 +1433,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
             }
             SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
             SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
                                       y / SensorManager.GRAVITY_EARTH,
                                       y / SensorManager.GRAVITY_EARTH,
-                                      event.values[2] / SensorManager.GRAVITY_EARTH - 1);
+                                      event.values[2] / SensorManager.GRAVITY_EARTH);
         }
         }
     }
     }
 }
 }
@@ -1389,7 +1477,7 @@ class DummyEdit extends View implements View.OnKeyListener {
         // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
         // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
         // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
         // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
         // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
         // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
-        // FIXME: A more effective solution would be to change our Layout from AbsoluteLayout to Relative or Linear
+        // FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
         // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
         // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
         // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
         // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
         if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
         if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
@@ -1428,7 +1516,7 @@ class SDLInputConnection extends BaseInputConnection {
          */
          */
         int keyCode = event.getKeyCode();
         int keyCode = event.getKeyCode();
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            if (event.isPrintingKey()) {
+            if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) {
                 commitText(String.valueOf((char) event.getUnicodeChar()), 1);
                 commitText(String.valueOf((char) event.getUnicodeChar()), 1);
             }
             }
             SDLActivity.onNativeKeyDown(keyCode);
             SDLActivity.onNativeKeyDown(keyCode);
@@ -1529,9 +1617,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
             if (joystick == null) {
             if (joystick == null) {
                 joystick = new SDLJoystick();
                 joystick = new SDLJoystick();
                 InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
                 InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
-
-                // Urho3D - revert back commit 34a0b0478654e8dfaf111aecc0e4535875c4ec87 as it does more harm than good
-                if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+                if (SDLActivity.isDeviceSDLJoystick(deviceIds[i])) {
                     joystick.device_id = deviceIds[i];
                     joystick.device_id = deviceIds[i];
                     joystick.name = joystickDevice.getName();
                     joystick.name = joystickDevice.getName();
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
@@ -1540,7 +1626,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     Collections.sort(ranges, new RangeComparator());
                     Collections.sort(ranges, new RangeComparator());
                     for (InputDevice.MotionRange range : ranges ) {
                     for (InputDevice.MotionRange range : ranges ) {
-                        if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) {
+                        if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
                             if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
                             if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
                                 range.getAxis() == MotionEvent.AXIS_HAT_Y) {
                                 range.getAxis() == MotionEvent.AXIS_HAT_Y) {
                                 joystick.hats.add(range);
                                 joystick.hats.add(range);
@@ -1594,7 +1680,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
 
 
     @Override
     @Override
     public boolean handleMotionEvent(MotionEvent event) {
     public boolean handleMotionEvent(MotionEvent event) {
-        if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
+        if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
             int actionPointerIndex = event.getActionIndex();
             int actionPointerIndex = event.getActionIndex();
             int action = event.getActionMasked();
             int action = event.getActionMasked();
             switch(action) {
             switch(action) {
@@ -1633,8 +1719,7 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
             case InputDevice.SOURCE_JOYSTICK:
             case InputDevice.SOURCE_JOYSTICK:
             case InputDevice.SOURCE_GAMEPAD:
             case InputDevice.SOURCE_GAMEPAD:
             case InputDevice.SOURCE_DPAD:
             case InputDevice.SOURCE_DPAD:
-                SDLActivity.handleJoystickMotionEvent(event);
-                return true;
+                return SDLActivity.handleJoystickMotionEvent(event);
 
 
             case InputDevice.SOURCE_MOUSE:
             case InputDevice.SOURCE_MOUSE:
                 action = event.getActionMasked();
                 action = event.getActionMasked();

+ 1 - 1
Resources/CoreData/Materials/Particle.xml

@@ -1,4 +1,4 @@
 <material>
 <material>
-    <technique name="Techniques/DiffVColAdd.xml" />
+    <technique name="Techniques/DiffUnlitParticleAdd.xml" />
     <texture unit="diffuse" name="Textures/Flare.dds" />
     <texture unit="diffuse" name="Textures/Flare.dds" />
 </material>
 </material>

+ 4 - 1
Resources/CoreData/RenderPaths/Deferred.xml

@@ -2,6 +2,7 @@
     <rendertarget name="albedo" sizedivisor="1 1" format="rgba" />
     <rendertarget name="albedo" sizedivisor="1 1" format="rgba" />
     <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
     <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
     <rendertarget name="depth" sizedivisor="1 1" format="lineardepth" />
     <rendertarget name="depth" sizedivisor="1 1" format="lineardepth" />
+    <command type="clear" color="1 1 1 1" output="depth" />
     <command type="clear" color="fog" depth="1.0" stencil="0" />
     <command type="clear" color="fog" depth="1.0" stencil="0" />
     <command type="scenepass" pass="deferred" marktostencil="true" vertexlights="true" metadata="gbuffer">
     <command type="scenepass" pass="deferred" marktostencil="true" vertexlights="true" metadata="gbuffer">
         <output index="0" name="viewport" />
         <output index="0" name="viewport" />
@@ -18,6 +19,8 @@
     <command type="scenepass" pass="refract">
     <command type="scenepass" pass="refract">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" />
     <command type="scenepass" pass="postalpha" sort="backtofront" />
 </renderpath>
 </renderpath>

+ 3 - 1
Resources/CoreData/RenderPaths/DeferredHWDepth.xml

@@ -18,6 +18,8 @@
     <command type="scenepass" pass="refract" depthstencil="depth">
     <command type="scenepass" pass="refract" depthstencil="depth">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" psdefines="HWDEPTH">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
 </renderpath>
 </renderpath>

+ 3 - 1
Resources/CoreData/RenderPaths/ForwardDepth.xml

@@ -9,6 +9,8 @@
     <command type="scenepass" pass="refract">
     <command type="scenepass" pass="refract">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" />
     <command type="scenepass" pass="postalpha" sort="backtofront" />
 </renderpath>
 </renderpath>

+ 4 - 4
Resources/CoreData/RenderPaths/ForwardHWDepth.xml

@@ -1,14 +1,14 @@
 <renderpath>
 <renderpath>
     <rendertarget name="depth" sizedivisor="1 1" format="readabledepth" />
     <rendertarget name="depth" sizedivisor="1 1" format="readabledepth" />
-    <command type="clear" depth="1.0" output="depth" />
-    <command type="scenepass" pass="shadow" output="depth" />
-    <command type="clear" color="fog" depthstencil="depth" />
+    <command type="clear" color="fog" depth="1.0" stencil="0" depthstencil="depth" />
     <command type="scenepass" pass="base" vertexlights="true" metadata="base" depthstencil="depth" />
     <command type="scenepass" pass="base" vertexlights="true" metadata="base" depthstencil="depth" />
     <command type="forwardlights" pass="light" depthstencil="depth" />
     <command type="forwardlights" pass="light" depthstencil="depth" />
     <command type="scenepass" pass="postopaque" depthstencil="depth" />
     <command type="scenepass" pass="postopaque" depthstencil="depth" />
     <command type="scenepass" pass="refract" depthstencil="depth">
     <command type="scenepass" pass="refract" depthstencil="depth">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth"  />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" psdefines="HWDEPTH">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
 </renderpath>
 </renderpath>

+ 3 - 1
Resources/CoreData/RenderPaths/PBRDeferred.xml

@@ -25,6 +25,8 @@
     <command type="scenepass" pass="refract">
     <command type="scenepass" pass="refract">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" />
     <command type="scenepass" pass="postalpha" sort="backtofront" />
 </renderpath>
 </renderpath>

+ 3 - 1
Resources/CoreData/RenderPaths/PBRDeferredHWDepth.xml

@@ -24,6 +24,8 @@
     <command type="scenepass" pass="refract" depthstencil="depth">
     <command type="scenepass" pass="refract" depthstencil="depth">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" psdefines="HWDEPTH">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
 </renderpath>
 </renderpath>

+ 4 - 1
Resources/CoreData/RenderPaths/Prepass.xml

@@ -2,6 +2,7 @@
     <rendertarget name="light" sizedivisor="1 1"  format="rgba" />
     <rendertarget name="light" sizedivisor="1 1"  format="rgba" />
     <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
     <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
     <rendertarget name="depth" sizedivisor="1 1"  format="lineardepth" />
     <rendertarget name="depth" sizedivisor="1 1"  format="lineardepth" />
+    <command type="clear" color="1 1 1 1" output="depth" />
     <command type="clear" color="fog" depth="1.0" stencil="0" />
     <command type="clear" color="fog" depth="1.0" stencil="0" />
     <command type="scenepass" pass="prepass" marktostencil="true" metadata="gbuffer">
     <command type="scenepass" pass="prepass" marktostencil="true" metadata="gbuffer">
         <output index="0" name="normal" />
         <output index="0" name="normal" />
@@ -19,6 +20,8 @@
     <command type="scenepass" pass="refract">
     <command type="scenepass" pass="refract">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" />
     <command type="scenepass" pass="postalpha" sort="backtofront" />
 </renderpath>
 </renderpath>

+ 3 - 1
Resources/CoreData/RenderPaths/PrepassHWDepth.xml

@@ -16,6 +16,8 @@
     <command type="scenepass" pass="refract" depthstencil="depth">
     <command type="scenepass" pass="refract" depthstencil="depth">
         <texture unit="environment" name="viewport" />
         <texture unit="environment" name="viewport" />
     </command>
     </command>
-    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" />
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" psdefines="HWDEPTH">
+        <texture unit="depth" name="depth" />
+    </command>
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
     <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
 </renderpath>
 </renderpath>

+ 20 - 8
Resources/CoreData/Shaders/GLSL/IBL.glsl

@@ -236,10 +236,10 @@
         return mix(normal, reflection, lerpFactor);
         return mix(normal, reflection, lerpFactor);
     }
     }
 
 
-    float GetMipFromRougness(float roughness)
+    float GetMipFromRoughness(float roughness)
     {
     {
-        float smoothness = 1.0 - roughness;
-        return (1.0 - smoothness * smoothness) * 10.0;
+        float Level = 3 - 1.15 * log2( roughness );
+        return 9.0 - 1 - Level;
     }
     }
 
 
 
 
@@ -253,6 +253,18 @@
         return SpecularColor * AB.x + AB.y;
         return SpecularColor * AB.x + AB.y;
     }
     }
 
 
+    vec3 FixCubeLookup(vec3 v) 
+    {
+        float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
+        float scale = (1024 - 1) / 1024;
+
+        if (abs(v.x) != M) v.x += scale;
+        if (abs(v.y) != M) v.y += scale;
+        if (abs(v.z) != M) v.z += scale; 
+
+        return v;
+    }
+
     /// Calculate IBL contributation
     /// Calculate IBL contributation
     ///     reflectVec: reflection vector for cube sampling
     ///     reflectVec: reflection vector for cube sampling
     ///     wsNormal: surface normal in word space
     ///     wsNormal: surface normal in word space
@@ -267,17 +279,17 @@
         // PMREM Mipmapmode https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering/
         // PMREM Mipmapmode https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering/
         //float GlossScale = 16.0;
         //float GlossScale = 16.0;
         //float GlossBias = 5.0;
         //float GlossBias = 5.0;
-        float mipSelect = roughness * 9.0; //exp2(GlossScale * roughness * roughness + GlossBias) - exp2(GlossBias);
+        float mipSelect = GetMipFromRoughness(roughness); //exp2(GlossScale * roughness * roughness + GlossBias) - exp2(GlossBias);
 
 
         // OpenGL ES does not support textureLod without extensions and does not have the sZoneCubeMap sampler,
         // OpenGL ES does not support textureLod without extensions and does not have the sZoneCubeMap sampler,
         // so for now, sample without explicit LOD, and from the environment sampler, where the zone texture will be put
         // so for now, sample without explicit LOD, and from the environment sampler, where the zone texture will be put
         // on mobile hardware
         // on mobile hardware
         #ifndef GL_ES
         #ifndef GL_ES
-            vec3 cube = textureLod(sZoneCubeMap, reflectVec, mipSelect).rgb;
-            vec3 cubeD = textureLod(sZoneCubeMap, wsNormal, 9.0).rgb;
+            vec3 cube = textureLod(sZoneCubeMap, FixCubeLookup(reflectVec), mipSelect).rgb;
+            vec3 cubeD = textureLod(sZoneCubeMap, FixCubeLookup(wsNormal), 9.0).rgb;
         #else
         #else
-            vec3 cube = textureCube(sEnvCubeMap, reflectVec).rgb;
-            vec3 cubeD = textureCube(sEnvCubeMap, wsNormal).rgb;
+            vec3 cube = textureCube(sEnvCubeMap, FixCubeLookup(reflectVec)).rgb;
+            vec3 cubeD = textureCube(sEnvCubeMap, FixCubeLookup(wsNormal)).rgb;
         #endif
         #endif
 
 
         // Fake the HDR texture
         // Fake the HDR texture

+ 22 - 10
Resources/CoreData/Shaders/GLSL/Lighting.glsl

@@ -127,17 +127,29 @@ float GetDiffuse(vec3 normal, vec3 worldPos, out vec3 lightDir)
 
 
 float GetAtten(vec3 normal, vec3 worldPos, out vec3 lightDir)
 float GetAtten(vec3 normal, vec3 worldPos, out vec3 lightDir)
 {
 {
-     #ifdef DIRLIGHT
-        lightDir = cLightDirPS;
-        return clamp(dot(normal, lightDir), 0.0, 1.0);
-    #else
-        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
-        float lightDist = length(lightVec);
-        float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) / (pow(lightDist, 2.0) + 1.0);
+    lightDir = cLightDirPS;
+    return clamp(dot(normal, lightDir), 0.0, 1.0);
+}
+
+float GetAttenPoint(vec3 normal, vec3 worldPos, out vec3 lightDir)
+{
+    vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+    float lightDist = length(lightVec);
+    float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) * 3.14159265358979323846 / (4.0 * 3.14159265358979323846)*(pow(lightDist, 2.0) + 1.0);
+    lightDir = lightVec / lightDist;
+    return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
+
+}
+
+float GetAttenSpot(vec3 normal, vec3 worldPos, out vec3 lightDir)
+{
+    vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+    float lightDist = length(lightVec);
+    float falloff = pow(clamp(1.0 - pow(lightDist / 1.0, 4.0), 0.0, 1.0), 2.0) / (pow(lightDist, 2.0) + 1.0);
+
+    lightDir = lightVec / lightDist;
+    return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
 
 
-        lightDir = lightVec / vec3(lightDist, lightDist, lightDist);
-        return clamp(dot(normal, lightDir), 0.0, 1.0) * falloff;
-    #endif
 }
 }
 
 
 float GetDiffuseVolumetric(vec3 worldPos)
 float GetDiffuseVolumetric(vec3 worldPos)

+ 35 - 0
Resources/CoreData/Shaders/GLSL/LitParticle.glsl

@@ -1,6 +1,7 @@
 #include "Uniforms.glsl"
 #include "Uniforms.glsl"
 #include "Samplers.glsl"
 #include "Samplers.glsl"
 #include "Transform.glsl"
 #include "Transform.glsl"
+#include "ScreenPos.glsl"
 #include "Lighting.glsl"
 #include "Lighting.glsl"
 #include "Fog.glsl"
 #include "Fog.glsl"
 
 
@@ -9,6 +10,10 @@ varying vec4 vWorldPos;
 #ifdef VERTEXCOLOR
 #ifdef VERTEXCOLOR
     varying vec4 vColor;
     varying vec4 vColor;
 #endif
 #endif
+#ifdef SOFTPARTICLES
+    varying vec4 vScreenPos;
+    uniform float cSoftParticleFadeScale;
+#endif
 #ifdef PERPIXEL
 #ifdef PERPIXEL
     #ifdef SHADOW
     #ifdef SHADOW
         #ifndef GL_ES
         #ifndef GL_ES
@@ -35,6 +40,10 @@ void VS()
     vTexCoord = GetTexCoord(iTexCoord);
     vTexCoord = GetTexCoord(iTexCoord);
     vWorldPos = vec4(worldPos, GetDepth(gl_Position));
     vWorldPos = vec4(worldPos, GetDepth(gl_Position));
 
 
+    #ifdef SOFTPARTICLES
+        vScreenPos = GetScreenPos(gl_Position);
+    #endif
+
     #ifdef VERTEXCOLOR
     #ifdef VERTEXCOLOR
         vColor = iColor;
         vColor = iColor;
     #endif
     #endif
@@ -93,6 +102,32 @@ void PS()
         float fogFactor = GetFogFactor(vWorldPos.w);
         float fogFactor = GetFogFactor(vWorldPos.w);
     #endif
     #endif
 
 
+    // Soft particle fade
+    // In expand mode depth test should be off. In that case do manual alpha discard test first to reduce fill rate
+    #ifdef SOFTPARTICLES
+        #ifdef EXPAND
+            if (diffColor.a < 0.01)
+                discard;
+        #endif
+
+        float particleDepth = vWorldPos.w;
+        #ifdef HWDEPTH
+            float depth = ReconstructDepth(texture2DProj(sDepthBuffer, vScreenPos).r);
+        #else
+            float depth = DecodeDepth(texture2DProj(sDepthBuffer, vScreenPos).rgb);
+        #endif
+
+        #ifdef EXPAND
+            float diffZ = max(particleDepth - depth, 0.0) * (cFarClipPS - cNearClipPS);
+            float fade = clamp(diffZ * cSoftParticleFadeScale, 0.0, 1.0);
+        #else
+            float diffZ = (depth - particleDepth) * (cFarClipPS - cNearClipPS);
+            float fade = clamp(1.0 - diffZ * cSoftParticleFadeScale, 0.0, 1.0);
+        #endif
+
+        diffColor.a = max(diffColor.a - fade, 0.0);
+    #endif
+
     #ifdef PERPIXEL
     #ifdef PERPIXEL
         // Per-pixel forward lighting
         // Per-pixel forward lighting
         vec3 lightColor;
         vec3 lightColor;

+ 3 - 3
Resources/CoreData/Shaders/GLSL/LitSolid.glsl

@@ -54,10 +54,10 @@ void VS()
     #endif
     #endif
 
 
     #ifdef NORMALMAP
     #ifdef NORMALMAP
-        vec3 tangent = GetWorldTangent(modelMatrix);
-        vec3 bitangent = cross(tangent, vNormal) * iTangent.w;
+        vec4 tangent = GetWorldTangent(modelMatrix);
+        vec3 bitangent = cross(tangent.xyz, vNormal) * tangent.w;
         vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
         vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
-        vTangent = vec4(tangent, bitangent.z);
+        vTangent = vec4(tangent.xyz, bitangent.z);
     #else
     #else
         vTexCoord = GetTexCoord(iTexCoord);
         vTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif

+ 96 - 5
Resources/CoreData/Shaders/GLSL/PBR.glsl

@@ -1,6 +1,81 @@
 #include "BRDF.glsl"
 #include "BRDF.glsl"
 #ifdef COMPILEPS
 #ifdef COMPILEPS
 
 
+    vec3 SphereLight(vec3 worldPos, vec3 lightVec, vec3 normal, vec3 toCamera, float roughness, vec3 specColor, out float ndl)
+    {
+        vec3 pos   = (cLightPosPS.xyz - worldPos);
+        float radius = cLightRad;
+
+        vec3 reflectVec   = reflect(-toCamera, normal);
+        vec3 centreToRay  = dot(pos, reflectVec) * reflectVec - pos;
+        vec3 closestPoint = pos + centreToRay * clamp(radius / length(centreToRay), 0.0, 1.0);
+
+        vec3 l = normalize(closestPoint);
+        vec3 h = normalize(toCamera + l);
+
+        ndl       = clamp(dot(normal, l), 0.0, 1.0);
+        float hdn = clamp(dot(h, normal), 0.0, 1.0);
+        float hdv = dot(h, toCamera);
+        float ndv = clamp(dot(normal, toCamera), 0.0, 1.0);
+
+        float distL      = length(pos);
+        float alpha      = roughness * roughness;
+        float alphaPrime = clamp(radius / (distL * 2.0) + alpha, 0.0, 1.0);
+
+        vec3 fresnelTerm = Fresnel(specColor, hdv) ;
+        float distTerm     = Distribution(hdn, alphaPrime);
+        float visTerm      = Visibility(ndl, ndv, roughness);
+
+        return distTerm * visTerm * fresnelTerm ;
+    }
+
+    vec3 TubeLight(vec3 worldPos, vec3 lightVec, vec3 normal, vec3 toCamera, float roughness, vec3 specColor, out float ndl)
+    {
+        float radius      = cLightRad;
+        float len         = cLightLength; 
+        vec3 pos         = (cLightPosPS.xyz - worldPos);
+        vec3 reflectVec  = reflect(-toCamera, normal);
+        
+        vec3 L01 = cLightDirPS * len;
+        vec3 L0 = pos - 0.5 * L01;
+        vec3 L1 = pos + 0.5 * L01;
+        vec3 ld = L1 - L0;
+
+        float distL0    = length( L0 );
+        float distL1    = length( L1 );
+
+        float NoL0      = dot( L0, normal ) / ( 2.0 * distL0 );
+        float NoL1      = dot( L1, normal ) / ( 2.0 * distL1 );
+        ndl             = ( 2.0 * clamp( NoL0 + NoL1, 0.0, 1.0 ) ) 
+                        / ( distL0 * distL1 + dot( L0, L1 ) + 2.0 );
+    
+        float a = len * len;
+        float b = dot( reflectVec, L01 );
+        float t = clamp( dot( L0, b * reflectVec - L01 ) / (a - b*b), 0.0, 1.0 );
+        
+        vec3 closestPoint   = L0 + ld * clamp(t, 0.0, 1.0);
+        vec3 centreToRay    = dot( closestPoint, reflectVec ) * reflectVec - closestPoint;
+        closestPoint          = closestPoint + centreToRay * clamp(radius / length(centreToRay), 0.0, 1.0);
+
+        vec3 l = normalize(closestPoint);
+        vec3 h = normalize(toCamera + l);
+
+        ndl       =  clamp(dot(normal, lightVec), 0.0, 1.0);
+        float hdn = clamp(dot(h, normal), 0.0, 1.0);
+        float hdv = dot(h, toCamera);
+        float ndv = clamp(dot(normal, toCamera), 0.0 ,1.0);
+
+        float distL      = length(closestPoint);
+        float alpha      = roughness * roughness;
+        float alphaPrime = clamp(radius / (distL * 2.0) + alpha, 0.0, 1.0);
+
+        vec3 fresnelTerm = Fresnel(specColor, hdv) ;
+        float distTerm     = Distribution(hdn, alphaPrime);
+        float visTerm      = Visibility(ndl, ndv, roughness);
+
+        return distTerm * visTerm * fresnelTerm ;
+    }
+
 	//Return the PBR BRDF value
 	//Return the PBR BRDF value
 	// lightDir  = the vector to the light
 	// lightDir  = the vector to the light
 	// lightVev  = normalised lightDir
 	// lightVev  = normalised lightDir
@@ -9,7 +84,7 @@
 	// roughness = roughness of the pixel
 	// roughness = roughness of the pixel
 	// diffColor = the rgb color of the pixel
 	// diffColor = the rgb color of the pixel
 	// specColor = the rgb specular color of the pixel
 	// specColor = the rgb specular color of the pixel
-	vec3 GetBRDF(vec3 lightDir, vec3 lightVec, vec3 toCamera, vec3 normal, float roughness, vec3 diffColor, vec3 specColor)
+	vec3 GetBRDF(vec3 worldPos, vec3 lightDir, vec3 lightVec, vec3 toCamera, vec3 normal, float roughness, vec3 diffColor, vec3 specColor)
 	{
 	{
         vec3 Hn = normalize(toCamera + lightDir);
         vec3 Hn = normalize(toCamera + lightDir);
         float vdh = clamp((dot(toCamera, Hn)), M_EPSILON, 1.0);
         float vdh = clamp((dot(toCamera, Hn)), M_EPSILON, 1.0);
@@ -21,11 +96,27 @@
         vec3 specularFactor = vec3(0.0, 0.0, 0.0);
         vec3 specularFactor = vec3(0.0, 0.0, 0.0);
 
 
         #ifdef SPECULAR
         #ifdef SPECULAR
-            vec3 fresnelTerm = Fresnel(specColor, vdh) ;
-            float distTerm = Distribution(ndh, roughness);
-            float visTerm = Visibility(ndl, ndv, roughness);
+            if(cLightRad > 0.0)
+            {
+                if(cLightLength > 0.0)
+                {
+                    specularFactor = TubeLight(worldPos, lightVec, normal, toCamera, roughness, specColor, ndl);
+                    specularFactor *= ndl;
+                }
+                else
+                {
+                    specularFactor = SphereLight(worldPos, lightVec, normal, toCamera, roughness, specColor, ndl);
+                    specularFactor *= ndl;
+                }
+            }
+            else
+            {
+                vec3 fresnelTerm = Fresnel(specColor, vdh) ;
+                float distTerm = Distribution(ndh, roughness);
+                float visTerm = Visibility(ndl, ndv, roughness);
 
 
-            specularFactor = fresnelTerm * distTerm * visTerm  / M_PI;
+                specularFactor = fresnelTerm * distTerm * visTerm  / M_PI;
+            }
         #endif
         #endif
 
 
         return diffuseFactor + specularFactor;
         return diffuseFactor + specularFactor;

+ 11 - 3
Resources/CoreData/Shaders/GLSL/PBRDeferred.glsl

@@ -86,7 +86,16 @@ void PS()
     vec4 projWorldPos = vec4(worldPos, 1.0);
     vec4 projWorldPos = vec4(worldPos, 1.0);
 
 
     vec3 lightDir;
     vec3 lightDir;
-    float atten = GetAtten(normal, worldPos, lightDir);
+
+    float atten = 1;
+
+    #if defined(DIRLIGHT)
+        atten = GetAtten(normal, worldPos, lightDir);
+    #elif defined(SPOTLIGHT)
+        atten = GetAttenSpot(normal, worldPos, lightDir);
+    #else
+        atten = GetAttenPoint(normal, worldPos, lightDir);
+    #endif
 
 
     float shadow = 1;
     float shadow = 1;
     #ifdef SHADOW
     #ifdef SHADOW
@@ -108,8 +117,7 @@ void PS()
 
 
     float ndl = clamp(abs(dot(normal, lightVec)), M_EPSILON, 1.0);
     float ndl = clamp(abs(dot(normal, lightVec)), M_EPSILON, 1.0);
 
 
-
-    vec3 BRDF = GetBRDF(lightDir, lightVec, toCamera, normal, roughness, albedoInput.rgb, specColor);
+    vec3 BRDF = GetBRDF(worldPos, lightDir, lightVec, toCamera, normal, roughness, albedoInput.rgb, specColor);
 
 
     gl_FragColor.a = 1.0;
     gl_FragColor.a = 1.0;
     gl_FragColor.rgb = BRDF * lightColor * (atten * shadow) / M_PI;
     gl_FragColor.rgb = BRDF * lightColor * (atten * shadow) / M_PI;

+ 14 - 5
Resources/CoreData/Shaders/GLSL/PBRLitSolid.glsl

@@ -58,10 +58,10 @@ void VS()
     #endif
     #endif
 
 
     #if defined(NORMALMAP) || defined(DIRBILLBOARD) || defined(IBL)
     #if defined(NORMALMAP) || defined(DIRBILLBOARD) || defined(IBL)
-        vec3 tangent = GetWorldTangent(modelMatrix);
-        vec3 bitangent = cross(tangent, vNormal) * iTangent.w;
+        vec4 tangent = GetWorldTangent(modelMatrix);
+        vec3 bitangent = cross(tangent.xyz, vNormal) * tangent.w;
         vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
         vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
-        vTangent = vec4(tangent, bitangent.z);
+        vTangent = vec4(tangent.xyz, bitangent.z);
     #else
     #else
         vTexCoord = GetTexCoord(iTexCoord);
         vTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif
@@ -172,7 +172,16 @@ void PS()
         vec3 lightDir;
         vec3 lightDir;
         vec3 finalColor;
         vec3 finalColor;
 
 
-        float atten = GetAtten(normal, vWorldPos.xyz, lightDir);
+        float atten = 1;
+
+        #if defined(DIRLIGHT)
+            atten = GetAtten(normal, vWorldPos.xyz, lightDir);
+        #elif defined(SPOTLIGHT)
+            atten = GetAttenSpot(normal, vWorldPos.xyz, lightDir);
+        #else
+            atten = GetAttenPoint(normal, vWorldPos.xyz, lightDir);
+        #endif
+
         float shadow = 1.0;
         float shadow = 1.0;
         #ifdef SHADOW
         #ifdef SHADOW
             shadow = GetShadow(vShadowPos, vWorldPos.w);
             shadow = GetShadow(vShadowPos, vWorldPos.w);
@@ -189,7 +198,7 @@ void PS()
         vec3 lightVec = normalize(lightDir);
         vec3 lightVec = normalize(lightDir);
         float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
         float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
 
 
-        vec3 BRDF = GetBRDF(lightDir, lightVec, toCamera, normal, roughness, diffColor.rgb, specColor);
+        vec3 BRDF = GetBRDF(vWorldPos.xyz, lightDir, lightVec, toCamera, normal, roughness, diffColor.rgb, specColor);
 
 
         finalColor.rgb = BRDF * lightColor * (atten * shadow) / M_PI;
         finalColor.rgb = BRDF * lightColor * (atten * shadow) / M_PI;
 
 

+ 3 - 3
Resources/CoreData/Shaders/GLSL/Shadow.glsl

@@ -3,7 +3,7 @@
 #include "Transform.glsl"
 #include "Transform.glsl"
 
 
 #ifdef VSM_SHADOW
 #ifdef VSM_SHADOW
-    varying vec3 vTexCoord;
+    varying vec4 vTexCoord;
 #else
 #else
     varying vec2 vTexCoord;
     varying vec2 vTexCoord;
 #endif
 #endif
@@ -14,7 +14,7 @@ void VS()
     vec3 worldPos = GetWorldPos(modelMatrix);
     vec3 worldPos = GetWorldPos(modelMatrix);
     gl_Position = GetClipPos(worldPos);
     gl_Position = GetClipPos(worldPos);
     #ifdef VSM_SHADOW
     #ifdef VSM_SHADOW
-        vTexCoord = vec3(GetTexCoord(iTexCoord), gl_Position.z / gl_Position.w * 0.5 + 0.5);
+        vTexCoord = vec4(GetTexCoord(iTexCoord), gl_Position.z, gl_Position.w);
     #else
     #else
         vTexCoord = GetTexCoord(iTexCoord);
         vTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif
@@ -29,7 +29,7 @@ void PS()
     #endif
     #endif
 
 
     #ifdef VSM_SHADOW
     #ifdef VSM_SHADOW
-        float depth = vTexCoord.z;
+        float depth = vTexCoord.z / vTexCoord.w * 0.5 + 0.5;
         gl_FragColor = vec4(depth, depth * depth, 1.0, 1.0);
         gl_FragColor = vec4(depth, depth * depth, 1.0, 1.0);
     #else
     #else
         gl_FragColor = vec4(1.0);
         gl_FragColor = vec4(1.0);

+ 82 - 24
Resources/CoreData/Shaders/GLSL/Text.glsl

@@ -19,46 +19,104 @@ void VS()
     mat4 modelMatrix = iModelMatrix;
     mat4 modelMatrix = iModelMatrix;
     vec3 worldPos = GetWorldPos(modelMatrix);
     vec3 worldPos = GetWorldPos(modelMatrix);
     gl_Position = GetClipPos(worldPos);
     gl_Position = GetClipPos(worldPos);
-    
+
     vTexCoord = iTexCoord;
     vTexCoord = iTexCoord;
     vColor = iColor;
     vColor = iColor;
 }
 }
 
 
-void PS()
-{
-    gl_FragColor.rgb = vColor.rgb;
+/*
+    1) Simplest SDF shader:
 
 
-#ifdef SIGNED_DISTANCE_FIELD
     float distance = texture2D(sDiffMap, vTexCoord).a;
     float distance = texture2D(sDiffMap, vTexCoord).a;
-    if (distance < 0.5)
-    {
-    #ifdef TEXT_EFFECT_SHADOW
-        if (texture2D(sDiffMap, vTexCoord - cShadowOffset).a > 0.5)
-            gl_FragColor = cShadowColor;
-        else
-    #endif
-        gl_FragColor.a = 0.0;
-    }
+    if (distance >= 0.5)
+        gl_FragColor.a = vColor.a; // This is glyph
     else
     else
+        gl_FragColor.a = 0.0; // Outside glyph
+
+    2) Glyph with antialiazed border:
+
+    float distance = texture2D(sDiffMap, vTexCoord).a;
+    gl_FragColor.a = vColor.a * smoothstep(0.495, 0.505, distance);
+
+    3) Quality improvement for far and small text:
+
+    float distance = texture2D(sDiffMap, vTexCoord).a;
+    // How much "distance" is changed for neighboring pixels.
+    // If text is far then width is big. Far text will be blurred.
+    float width = fwidth(distance);
+    gl_FragColor.a = vColor.a * smoothstep(0.5 - width, 0.5 + width, distance);
+*/
+
+#if defined(COMPILEPS) && defined(SIGNED_DISTANCE_FIELD)
+    float GetAlpha(float distance, float width)
     {
     {
+        return smoothstep(0.5 - width, 0.5 + width, distance);
+    }
+
+    // Comment this define to turn off supersampling
+    #define SUPERSAMPLING
+#endif
+
+void PS()
+{
+#ifdef SIGNED_DISTANCE_FIELD
+    gl_FragColor.rgb = vColor.rgb;
+    float distance = texture2D(sDiffMap, vTexCoord).a;
+
     #ifdef TEXT_EFFECT_STROKE
     #ifdef TEXT_EFFECT_STROKE
-        if (distance < 0.525)
-            gl_FragColor.rgb = cStrokeColor.rgb;
+        #ifdef SUPERSAMPLING
+            float outlineFactor = smoothstep(0.5, 0.525, distance); // Border of glyph
+            gl_FragColor.rgb = mix(cStrokeColor.rgb, vColor.rgb, outlineFactor);
+        #else
+            if (distance < 0.525)
+               gl_FragColor.rgb = cStrokeColor.rgb;
+        #endif
     #endif
     #endif
 
 
     #ifdef TEXT_EFFECT_SHADOW
     #ifdef TEXT_EFFECT_SHADOW
-        if (texture2D(sDiffMap, vTexCoord + cShadowOffset).a < 0.5)
-            gl_FragColor.a = vColor.a;
+        if (texture2D(sDiffMap, vTexCoord - cShadowOffset).a > 0.5 && distance <= 0.5)
+            gl_FragColor = cShadowColor;
+        #ifndef SUPERSAMPLING
+        else if (distance <= 0.5)
+            gl_FragColor.a = 0;
+        #endif
         else
         else
     #endif
     #endif
-        gl_FragColor.a = vColor.a * smoothstep(0.5, 0.505, distance);
-    }
+        {
+            float width = fwidth(distance);
+            float alpha = GetAlpha(distance, width);
+
+            #ifdef SUPERSAMPLING
+                vec2 deltaUV = 0.354 * fwidth(vTexCoord); // (1.0 / sqrt(2.0)) / 2.0 = 0.354
+                vec4 square = vec4(vTexCoord - deltaUV, vTexCoord + deltaUV);
+
+                float distance2 = texture2D(sDiffMap, square.xy).a;
+                float distance3 = texture2D(sDiffMap, square.zw).a;
+                float distance4 = texture2D(sDiffMap, square.xw).a;
+                float distance5 = texture2D(sDiffMap, square.zy).a;
+
+                alpha += GetAlpha(distance2, width)
+                       + GetAlpha(distance3, width)
+                       + GetAlpha(distance4, width)
+                       + GetAlpha(distance5, width);
+
+                // For calculating of average correct would be dividing by 5.
+                // But when text is blurred, its brightness is lost. Therefore divide by 4.
+                alpha = alpha * 0.25;
+            #endif
+
+            gl_FragColor.a = alpha;
+        }
 #else
 #else
-    // Non-SDF font will likely be monochrome, in which case the alpha channel will be on the R channel on OpenGL 3
-    #ifdef GL3
-        gl_FragColor.a = vColor.a * texture2D(sDiffMap, vTexCoord).r;
+    #ifdef ALPHAMAP
+        gl_FragColor.rgb = vColor.rgb;
+        #ifdef GL3
+            gl_FragColor.a = vColor.a * texture2D(sDiffMap, vTexCoord).r;
+        #else
+            gl_FragColor.a = vColor.a * texture2D(sDiffMap, vTexCoord).a;
+        #endif
     #else
     #else
-        gl_FragColor.a = vColor.a * texture2D(sDiffMap, vTexCoord).a;
+        gl_FragColor = vColor * texture2D(sDiffMap, vTexCoord);
     #endif
     #endif
 #endif
 #endif
 }
 }

+ 19 - 7
Resources/CoreData/Shaders/GLSL/Transform.glsl

@@ -147,7 +147,7 @@ vec3 GetTrailNormal(vec4 iPos, vec3 iParentPos, vec3 iForward)
 #if defined(SKINNED)
 #if defined(SKINNED)
     #define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices)
     #define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices)
 #elif defined(INSTANCED)
 #elif defined(INSTANCED)
-    #define iModelMatrix GetInstanceMatrix();
+    #define iModelMatrix GetInstanceMatrix()
 #else
 #else
     #define iModelMatrix cModel
     #define iModelMatrix cModel
 #endif
 #endif
@@ -182,9 +182,15 @@ vec3 GetWorldNormal(mat4 modelMatrix)
     #endif
     #endif
 }
 }
 
 
-vec3 GetWorldTangent(mat4 modelMatrix)
+vec4 GetWorldTangent(mat4 modelMatrix)
 {
 {
-    return normalize(iTangent.xyz * GetNormalMatrix(modelMatrix));
+    #if defined(BILLBOARD)
+        return vec4(normalize(vec3(1.0, 0.0, 0.0) * cBillboardRot), 1.0);
+    #elif defined(DIRBILLBOARD)
+        return vec4(normalize(vec3(1.0, 0.0, 0.0) * GetNormalMatrix(modelMatrix)), 1.0);
+    #else
+        return vec4(normalize(iTangent.xyz * GetNormalMatrix(modelMatrix)), iTangent.w);
+    #endif
 }
 }
 
 
 #else
 #else
@@ -193,15 +199,21 @@ vec3 GetWorldTangent(mat4 modelMatrix)
 #ifdef GL3
 #ifdef GL3
 #define varying in
 #define varying in
 
 
-// \todo: should not hardcode the number of MRT outputs according to defines
+#ifndef MRT_COUNT
+
 #if defined(DEFERRED)
 #if defined(DEFERRED)
-out vec4 fragData[4];
+#define MRT_COUNT 4
 #elif defined(PREPASS)
 #elif defined(PREPASS)
-out vec4 fragData[2];
+#define MRT_COUNT 2
 #else
 #else
-out vec4 fragData[1];
+#define MRT_COUNT 1
 #endif
 #endif
 
 
+#endif
+
+out vec4 fragData[MRT_COUNT];
+
+
 #define gl_FragColor fragData[0]
 #define gl_FragColor fragData[0]
 #define gl_FragData fragData
 #define gl_FragData fragData
 #endif
 #endif

+ 14 - 4
Resources/CoreData/Shaders/GLSL/Uniforms.glsl

@@ -71,7 +71,11 @@ uniform vec4 cMatSpecColor;
 #ifdef PBR
 #ifdef PBR
     uniform float cRoughness;
     uniform float cRoughness;
     uniform float cMetallic;
     uniform float cMetallic;
+    uniform float cLightRad;
+    uniform float cLightLength;
 #endif
 #endif
+uniform vec3 cZoneMin;
+uniform vec3 cZoneMax;
 uniform float cNearClipPS;
 uniform float cNearClipPS;
 uniform float cFarClipPS;
 uniform float cFarClipPS;
 uniform vec4 cShadowCubeAdjust;
 uniform vec4 cShadowCubeAdjust;
@@ -174,6 +178,8 @@ uniform ZonePS
     vec4 cAmbientColor;
     vec4 cAmbientColor;
     vec4 cFogParams;
     vec4 cFogParams;
     vec3 cFogColor;
     vec3 cFogColor;
+    vec3 cZoneMin;
+    vec3 cZoneMax;
 };
 };
 
 
 uniform LightPS
 uniform LightPS
@@ -191,6 +197,10 @@ uniform LightPS
 #ifdef VSM_SHADOW
 #ifdef VSM_SHADOW
     vec2 cVSMShadowParams;
     vec2 cVSMShadowParams;
 #endif
 #endif
+#ifdef PBR
+    float cLightRad;
+    float cLightLength;
+#endif
 };
 };
 
 
 #ifndef CUSTOM_MATERIAL_CBUFFER
 #ifndef CUSTOM_MATERIAL_CBUFFER
@@ -200,10 +210,10 @@ uniform MaterialPS
     vec3 cMatEmissiveColor;
     vec3 cMatEmissiveColor;
     vec3 cMatEnvMapColor;
     vec3 cMatEnvMapColor;
     vec4 cMatSpecColor;
     vec4 cMatSpecColor;
-    #ifdef PBR
-        float cRoughness;
-        float cMetallic;
-    #endif
+#ifdef PBR
+    float cRoughness;
+    float cMetallic;
+#endif
 };
 };
 #endif
 #endif
 
 

+ 0 - 3
Resources/CoreData/Shaders/GLSL/Unlit.glsl

@@ -20,9 +20,6 @@ void VS()
 
 
     #ifdef VERTEXCOLOR
     #ifdef VERTEXCOLOR
         vColor = iColor;
         vColor = iColor;
-        //#ifdef TRAIL
-        //    vColor = vec4(normalize(cCameraPos), 1.0);
-        //#endif
     #endif
     #endif
 
 
 }
 }

+ 90 - 0
Resources/CoreData/Shaders/GLSL/UnlitParticle.glsl

@@ -0,0 +1,90 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Fog.glsl"
+
+varying vec2 vTexCoord;
+varying vec4 vWorldPos;
+#ifdef VERTEXCOLOR
+    varying vec4 vColor;
+#endif
+#ifdef SOFTPARTICLES
+    varying vec4 vScreenPos;
+    uniform float cSoftParticleFadeScale;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetTexCoord(iTexCoord);
+    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
+
+    #ifdef SOFTPARTICLES
+        vScreenPos = GetScreenPos(gl_Position);
+    #endif
+
+    #ifdef VERTEXCOLOR
+        vColor = iColor;
+    #endif
+
+}
+
+void PS()
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        vec4 diffColor = cMatDiffColor * texture2D(sDiffMap, vTexCoord);
+        #ifdef ALPHAMASK
+            if (diffColor.a < 0.5)
+                discard;
+        #endif
+    #else
+        vec4 diffColor = cMatDiffColor;
+    #endif
+
+    #ifdef VERTEXCOLOR
+        diffColor *= vColor;
+    #endif
+
+    // Get fog factor
+    #ifdef HEIGHTFOG
+        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
+    #else
+        float fogFactor = GetFogFactor(vWorldPos.w);
+    #endif
+
+    // Soft particle fade
+    // In expand mode depth test should be off. In that case do manual alpha discard test first to reduce fill rate
+    #ifdef SOFTPARTICLES
+        #ifdef EXPAND
+            if (diffColor.a < 0.01)
+                discard;
+        #endif
+
+        float particleDepth = vWorldPos.w;
+        #ifdef HWDEPTH
+            float depth = ReconstructDepth(texture2DProj(sDepthBuffer, vScreenPos).r);
+        #else
+            float depth = DecodeDepth(texture2DProj(sDepthBuffer, vScreenPos).rgb);
+        #endif
+
+        #ifdef EXPAND
+            float diffZ = max(particleDepth - depth, 0.0) * (cFarClipPS - cNearClipPS);
+            float fade = clamp(diffZ * cSoftParticleFadeScale, 0.0, 1.0);
+        #else
+            float diffZ = (depth - particleDepth) * (cFarClipPS - cNearClipPS);
+            float fade = clamp(1.0 - diffZ * cSoftParticleFadeScale, 0.0, 1.0);
+        #endif
+
+        #ifndef ADDITIVE
+            diffColor.a = max(diffColor.a - fade, 0.0);
+        #else
+            diffColor.rgb = max(diffColor.rgb - fade, vec3(0.0, 0.0, 0.0));
+        #endif
+    #endif
+
+    gl_FragColor = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
+}

+ 7 - 7
Resources/CoreData/Shaders/GLSL/Vegetation.glsl

@@ -48,7 +48,7 @@ void VS()
 {
 {
     mat4 modelMatrix = iModelMatrix;
     mat4 modelMatrix = iModelMatrix;
     vec3 worldPos = GetWorldPos(modelMatrix);
     vec3 worldPos = GetWorldPos(modelMatrix);
-    float height = worldPos.y - cModel[1][3];
+    float height = worldPos.y - modelMatrix[1][3];
 
 
     float windStrength = max(height - cWindHeightPivot, 0.0) * cWindHeightFactor;
     float windStrength = max(height - cWindHeightPivot, 0.0) * cWindHeightFactor;
     float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
     float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
@@ -64,10 +64,10 @@ void VS()
     #endif
     #endif
 
 
     #ifdef NORMALMAP
     #ifdef NORMALMAP
-        vec3 tangent = GetWorldTangent(modelMatrix);
-        vec3 bitangent = cross(tangent, vNormal) * iTangent.w;
+        vec4 tangent = GetWorldTangent(modelMatrix);
+        vec3 bitangent = cross(tangent.xyz, vNormal) * tangent.w;
         vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
         vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
-        vTangent = vec4(tangent, bitangent.z);
+        vTangent = vec4(tangent.xyz, bitangent.z);
     #else
     #else
         vTexCoord = GetTexCoord(iTexCoord);
         vTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif
@@ -86,7 +86,7 @@ void VS()
             // Spotlight projection: transform from world space to projector texture coordinates
             // Spotlight projection: transform from world space to projector texture coordinates
             vSpotPos = projWorldPos * cLightMatrices[0];
             vSpotPos = projWorldPos * cLightMatrices[0];
         #endif
         #endif
-    
+
         #ifdef POINTLIGHT
         #ifdef POINTLIGHT
             vCubeMaskVec = (worldPos - cLightPos.xyz) * mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz);
             vCubeMaskVec = (worldPos - cLightPos.xyz) * mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz);
         #endif
         #endif
@@ -100,12 +100,12 @@ void VS()
         #else
         #else
             vVertexLight = GetAmbient(GetZonePos(worldPos));
             vVertexLight = GetAmbient(GetZonePos(worldPos));
         #endif
         #endif
-        
+
         #ifdef NUMVERTEXLIGHTS
         #ifdef NUMVERTEXLIGHTS
             for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
             for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
                 vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
                 vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
         #endif
         #endif
-        
+
         vScreenPos = GetScreenPos(gl_Position);
         vScreenPos = GetScreenPos(gl_Position);
 
 
         #ifdef ENVCUBEMAP
         #ifdef ENVCUBEMAP

+ 1 - 1
Resources/CoreData/Shaders/HLSL/Depth.hlsl

@@ -32,7 +32,7 @@ void PS(
     out float4 oColor : OUTCOLOR0)
     out float4 oColor : OUTCOLOR0)
 {
 {
     #ifdef ALPHAMASK
     #ifdef ALPHAMASK
-        float alpha = Sample2D(sDiffMap, iTexCoord.xy).a;
+        float alpha = Sample2D(DiffMap, iTexCoord.xy).a;
         if (alpha < 0.5)
         if (alpha < 0.5)
             discard;
             discard;
     #endif
     #endif

+ 37 - 14
Resources/CoreData/Shaders/HLSL/IBL.hlsl

@@ -227,23 +227,35 @@
         return lerp(normal, reflection, lerpFactor);
         return lerp(normal, reflection, lerpFactor);
     }
     }
 
 
-    float GetMipFromRougness(float roughness)
+    float GetMipFromRoughness(float roughness)
     {
     {
-        const float smoothness = 1.0 - roughness;
-        return (1.0 - smoothness * smoothness) * 10.0;
+        float Level = 3 - 1.15 * log2( roughness );
+        return 9.0 - 1 - Level;
     }
     }
 
 
 
 
-    float3 EnvBRDFApprox (float3 SpecularColor, float Roughness, float NoV)
+    float3 EnvBRDFApprox (float3 specColor, float roughness, float ndv)
     {
     {
         const float4 c0 = float4(-1, -0.0275, -0.572, 0.022 );
         const float4 c0 = float4(-1, -0.0275, -0.572, 0.022 );
         const float4 c1 = float4(1, 0.0425, 1.0, -0.04 );
         const float4 c1 = float4(1, 0.0425, 1.0, -0.04 );
-        float4 r = Roughness * c0 + c1;
-        float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
+        float4 r = roughness * c0 + c1;
+        float a004 = min( r.x * r.x, exp2( -9.28 * ndv ) ) * r.x + r.y;
         float2 AB = float2( -1.04, 1.04 ) * a004 + r.zw;
         float2 AB = float2( -1.04, 1.04 ) * a004 + r.zw;
-        return SpecularColor * AB.x + AB.y;
+        return specColor * AB.x + AB.y;
     }
     }
 
 
+    float3 FixCubeLookup(float3 v) 
+    {
+        float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
+        float scale = (1024 - 1) / 1024;
+
+        if (abs(v.x) != M) v.x += scale;
+        if (abs(v.y) != M) v.y += scale;
+        if (abs(v.z) != M) v.z += scale; 
+
+        return v;
+    }
+    
     /// Calculate IBL contributation
     /// Calculate IBL contributation
     ///     reflectVec: reflection vector for cube sampling
     ///     reflectVec: reflection vector for cube sampling
     ///     wsNormal: surface normal in word space
     ///     wsNormal: surface normal in word space
@@ -251,17 +263,28 @@
     ///     roughness: surface roughness
     ///     roughness: surface roughness
     ///     ambientOcclusion: ambient occlusion
     ///     ambientOcclusion: ambient occlusion
     float3 ImageBasedLighting(in float3 reflectVec, in float3 tangent, in float3 bitangent, in float3 wsNormal, in float3 toCamera, in float3 diffColor, in float3 specColor, in float roughness, inout float3 reflectionCubeColor)
     float3 ImageBasedLighting(in float3 reflectVec, in float3 tangent, in float3 bitangent, in float3 wsNormal, in float3 toCamera, in float3 diffColor, in float3 specColor, in float roughness, inout float3 reflectionCubeColor)
-    {
+    { 
         reflectVec = GetSpecularDominantDir(wsNormal, reflectVec, roughness);
         reflectVec = GetSpecularDominantDir(wsNormal, reflectVec, roughness);
         const float ndv = saturate(dot(-toCamera, wsNormal));
         const float ndv = saturate(dot(-toCamera, wsNormal));
 
 
-        // PMREM Mipmapmode https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering/
-        //const float GlossScale = 16.0;
-        //const float GlossBias = 5.0;
-        const float mipSelect = roughness * 9.0;// exp2(GlossScale * roughness + GlossBias) - exp2(GlossBias);
+        /// Test: Parallax correction, currently not working
+
+        // float3 intersectMax = (cZoneMax - toCamera) / reflectVec;
+        // float3 intersectMin = (cZoneMin - toCamera) / reflectVec;
+        
+        // float3 furthestPlane = max(intersectMax, intersectMin);
+        
+        // float planeDistance = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
+
+        // // Get the intersection position
+        // float3 intersectionPos = toCamera + reflectVec * planeDistance;
+        // // Get corrected reflection
+        // reflectVec = intersectionPos - ((cZoneMin + cZoneMax )/ 2);
 
 
-        float3 cube = SampleCubeLOD(ZoneCubeMap, float4(reflectVec, mipSelect)).rgb;
-        float3 cubeD = SampleCubeLOD(ZoneCubeMap, float4(wsNormal, 9.0)).rgb;
+        const float mipSelect = GetMipFromRoughness(roughness);
+        float3 cube = SampleCubeLOD(ZoneCubeMap, float4(FixCubeLookup(reflectVec), mipSelect)).rgb;
+        float3 cubeD = SampleCubeLOD(ZoneCubeMap, float4(FixCubeLookup(wsNormal), 9.0)).rgb;
+        
         // Fake the HDR texture
         // Fake the HDR texture
         float brightness = clamp(cAmbientColor.a, 0.0, 1.0);
         float brightness = clamp(cAmbientColor.a, 0.0, 1.0);
         float darknessCutoff = clamp((cAmbientColor.a - 1.0) * 0.1, 0.0, 0.25);
         float darknessCutoff = clamp((cAmbientColor.a - 1.0) * 0.1, 0.0, 0.25);

+ 24 - 10
Resources/CoreData/Shaders/HLSL/Lighting.hlsl

@@ -138,19 +138,33 @@ float GetDiffuse(float3 normal, float3 worldPos, out float3 lightDir)
 
 
 float GetAtten(float3 normal, float3 worldPos, out float3 lightDir)
 float GetAtten(float3 normal, float3 worldPos, out float3 lightDir)
 {
 {
-     #ifdef DIRLIGHT
-        lightDir = cLightDirPS;
-        return saturate(dot(normal, lightDir));
-    #else
-        float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
-        float lightDist = length(lightVec);
-        float falloff = pow(saturate(1.0 - pow(lightDist / 1.0, 4.0)), 2.0) / (pow(lightDist, 2.0) + 1.0);
+    lightDir = cLightDirPS;
+    return saturate(dot(normal, lightDir));
+    
+}
+
+float GetAttenPoint(float3 normal, float3 worldPos, out float3 lightDir)
+{
+    float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+    float lightDist = length(lightVec);
+    float falloff = pow(saturate(1.0 - pow(lightDist / 1.0, 4.0)), 2.0) * 3.14159265358979323846 / (4 * 3.14159265358979323846)*(pow(lightDist, 2.0) + 1.0);
+    lightDir = lightVec / lightDist;
+    return saturate(dot(normal, lightDir)) * falloff;
+
+}
+
+float GetAttenSpot(float3 normal, float3 worldPos, out float3 lightDir)
+{
+    float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+    float lightDist = length(lightVec);
+    float falloff = pow(saturate(1.0 - pow(lightDist / 1.0, 4.0)), 2.0) / (pow(lightDist, 2.0) + 1.0);
+
+    lightDir = lightVec / lightDist;
+    return saturate(dot(normal, lightDir)) * falloff;
 
 
-        lightDir = lightVec / lightDist;
-        return saturate(dot(normal, lightDir)) * falloff;
-    #endif
 }
 }
 
 
+
 float GetDiffuseVolumetric(float3 worldPos)
 float GetDiffuseVolumetric(float3 worldPos)
 {
 {
     #ifdef DIRLIGHT
     #ifdef DIRLIGHT

+ 49 - 0
Resources/CoreData/Shaders/HLSL/LitParticle.hlsl

@@ -2,8 +2,22 @@
 #include "Samplers.hlsl"
 #include "Samplers.hlsl"
 #include "Transform.hlsl"
 #include "Transform.hlsl"
 #include "Lighting.hlsl"
 #include "Lighting.hlsl"
+#include "ScreenPos.hlsl"
 #include "Fog.hlsl"
 #include "Fog.hlsl"
 
 
+#if defined(COMPILEPS) && defined(SOFTPARTICLES)
+#ifndef D3D11
+// D3D9 uniform
+uniform float cSoftParticleFadeScale;
+#else
+// D3D11 constant buffer
+cbuffer CustomPS : register(b6)
+{
+    float cSoftParticleFadeScale;
+}
+#endif
+#endif
+
 void VS(float4 iPos : POSITION,
 void VS(float4 iPos : POSITION,
     #if !defined(BILLBOARD) && !defined(TRAILFACECAM)
     #if !defined(BILLBOARD) && !defined(TRAILFACECAM)
         float3 iNormal : NORMAL,
         float3 iNormal : NORMAL,
@@ -28,6 +42,9 @@ void VS(float4 iPos : POSITION,
         float4 iTangent : TANGENT,
         float4 iTangent : TANGENT,
     #endif
     #endif
     out float2 oTexCoord : TEXCOORD0,
     out float2 oTexCoord : TEXCOORD0,
+    #ifdef SOFTPARTICLES
+        out float4 oScreenPos : TEXCOORD1,
+    #endif
     out float4 oWorldPos : TEXCOORD3,
     out float4 oWorldPos : TEXCOORD3,
     #if PERPIXEL
     #if PERPIXEL
         #ifdef SHADOW
         #ifdef SHADOW
@@ -65,6 +82,10 @@ void VS(float4 iPos : POSITION,
         oClip = dot(oPos, cClipPlane);
         oClip = dot(oPos, cClipPlane);
     #endif
     #endif
 
 
+    #ifdef SOFTPARTICLES
+        oScreenPos = GetScreenPos(oPos);
+    #endif
+
     #ifdef VERTEXCOLOR
     #ifdef VERTEXCOLOR
         oColor = iColor;
         oColor = iColor;
     #endif
     #endif
@@ -98,6 +119,9 @@ void VS(float4 iPos : POSITION,
 }
 }
 
 
 void PS(float2 iTexCoord : TEXCOORD0,
 void PS(float2 iTexCoord : TEXCOORD0,
+    #ifdef SOFTPARTICLES
+        float4 iScreenPos: TEXCOORD1,
+    #endif
     float4 iWorldPos : TEXCOORD3,
     float4 iWorldPos : TEXCOORD3,
     #ifdef PERPIXEL
     #ifdef PERPIXEL
         #ifdef SHADOW
         #ifdef SHADOW
@@ -143,6 +167,31 @@ void PS(float2 iTexCoord : TEXCOORD0,
         float fogFactor = GetFogFactor(iWorldPos.w);
         float fogFactor = GetFogFactor(iWorldPos.w);
     #endif
     #endif
 
 
+    // Soft particle fade
+    // In expand mode depth test should be off. In that case do manual alpha discard test first to reduce fill rate
+    #ifdef SOFTPARTICLES
+        #ifdef EXPAND
+            if (diffColor.a < 0.01)
+                discard;
+        #endif
+
+        float particleDepth = iWorldPos.w;
+        float depth = Sample2DProj(DepthBuffer, iScreenPos).r;
+        #ifdef HWDEPTH
+            depth = ReconstructDepth(depth);
+        #endif
+
+        #ifdef EXPAND
+            float diffZ = max(particleDepth - depth, 0.0) * (cFarClipPS - cNearClipPS);
+            float fade = saturate(diffZ * cSoftParticleFadeScale);
+        #else
+            float diffZ = (depth - particleDepth) * (cFarClipPS - cNearClipPS);
+            float fade = saturate(1.0 - diffZ * cSoftParticleFadeScale);
+        #endif
+
+        diffColor.a = max(diffColor.a - fade, 0.0);
+    #endif
+
     #ifdef PERPIXEL
     #ifdef PERPIXEL
         // Per-pixel forward lighting
         // Per-pixel forward lighting
         float3 lightColor;
         float3 lightColor;

+ 4 - 4
Resources/CoreData/Shaders/HLSL/LitSolid.hlsl

@@ -18,7 +18,7 @@ void VS(float4 iPos : POSITION,
     #if defined(LIGHTMAP) || defined(AO)
     #if defined(LIGHTMAP) || defined(AO)
         float2 iTexCoord2 : TEXCOORD1,
         float2 iTexCoord2 : TEXCOORD1,
     #endif
     #endif
-    #if defined(NORMALMAP) || defined(TRAILFACECAM) || defined(TRAILBONE)
+    #if (defined(NORMALMAP) || defined(TRAILFACECAM) || defined(TRAILBONE)) && !defined(BILLBOARD) && !defined(DIRBILLBOARD)
         float4 iTangent : TANGENT,
         float4 iTangent : TANGENT,
     #endif
     #endif
     #ifdef SKINNED
     #ifdef SKINNED
@@ -87,10 +87,10 @@ void VS(float4 iPos : POSITION,
     #endif
     #endif
 
 
     #ifdef NORMALMAP
     #ifdef NORMALMAP
-        float3 tangent = GetWorldTangent(modelMatrix);
-        float3 bitangent = cross(tangent, oNormal) * iTangent.w;
+        float4 tangent = GetWorldTangent(modelMatrix);
+        float3 bitangent = cross(tangent.xyz, oNormal) * tangent.w;
         oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
         oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
-        oTangent = float4(tangent, bitangent.z);
+        oTangent = float4(tangent.xyz, bitangent.z);
     #else
     #else
         oTexCoord = GetTexCoord(iTexCoord);
         oTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif

+ 101 - 8
Resources/CoreData/Shaders/HLSL/PBR.hlsl

@@ -1,32 +1,125 @@
 #include "BRDF.hlsl"
 #include "BRDF.hlsl"
 #ifdef COMPILEPS
 #ifdef COMPILEPS
 
 
+    
+
+    float3 SphereLight(float3 worldPos, float3 lightVec, float3 normal, float3 toCamera, float roughness, float3 specColor, out float ndl)
+    {
+        float3 pos   = (cLightPosPS.xyz - worldPos);
+        float radius = cLightRad;
+
+        float3 reflectVec   = reflect(-toCamera, normal);
+        float3 centreToRay  = dot(pos, reflectVec) * reflectVec - pos;
+        float3 closestPoint = pos + centreToRay * saturate(radius / length(centreToRay));
+
+        float3 l = normalize(closestPoint);
+        float3 h = normalize(toCamera + l);
+
+        ndl       = saturate(dot(normal, l));
+        float hdn = saturate(dot(h, normal));
+        float hdv = dot(h, toCamera);
+        float ndv = saturate(dot(normal, toCamera));
+
+        float distL      = length(pos);
+        float alpha      = roughness * roughness;
+        float alphaPrime = saturate(radius / (distL * 2.0) + alpha);
+
+        const float3 fresnelTerm = Fresnel(specColor, hdv) ;
+        const float distTerm     = Distribution(hdn, alphaPrime);
+        const float visTerm      = Visibility(ndl, ndv, roughness);
+
+        return distTerm * visTerm * fresnelTerm ;
+    }
+
+    float3 TubeLight(float3 worldPos, float3 lightVec, float3 normal, float3 toCamera, float roughness, float3 specColor, out float ndl)
+    {
+         float radius      = cLightRad;
+         float len         = cLightLength; 
+        float3 pos         = (cLightPosPS.xyz - worldPos);
+        float3 reflectVec  = reflect(-toCamera, normal);
+        
+        float3 L01 = cLightDirPS * len;
+        float3 L0 = pos - 0.5 * L01;
+        float3 L1 = pos + 0.5 * L01;
+        float3 ld = L1 - L0;
+
+        float distL0    = length( L0 );
+        float distL1    = length( L1 );
+
+        float NoL0      = dot( L0, normal ) / ( 2.0 * distL0 );
+        float NoL1      = dot( L1, normal ) / ( 2.0 * distL1 );
+        ndl             = ( 2.0 * clamp( NoL0 + NoL1, 0.0, 1.0 ) ) 
+                        / ( distL0 * distL1 + dot( L0, L1 ) + 2.0 );
+    
+        float a = len * len;
+        float b = dot( reflectVec, L01 );
+        float t = saturate( dot( L0, b * reflectVec - L01 ) / (a - b*b) );
+        
+        float3 closestPoint   = L0 + ld * saturate( t);
+        float3 centreToRay    = dot( closestPoint, reflectVec ) * reflectVec - closestPoint;
+        closestPoint          = closestPoint + centreToRay * saturate(radius / length(centreToRay));
+
+        float3 l = normalize(closestPoint);
+        float3 h = normalize(toCamera + l);
+
+        ndl       =  saturate(dot(normal, lightVec));
+        float hdn = saturate(dot(h, normal));
+        float hdv = dot(h, toCamera);
+        float ndv = saturate(dot(normal, toCamera));
+
+        float distL      = length(closestPoint);
+        float alpha      = roughness * roughness;
+        float alphaPrime = saturate(radius / (distL * 2.0) + alpha);
+
+        const float3 fresnelTerm = Fresnel(specColor, hdv) ;
+        const float distTerm     = Distribution(hdn, alphaPrime);
+        const float visTerm      = Visibility(ndl, ndv, roughness);
+
+        return distTerm * visTerm * fresnelTerm ;
+    }
+
 	//Return the PBR BRDF value
 	//Return the PBR BRDF value
 	// lightDir  = the vector to the light
 	// lightDir  = the vector to the light
-	// lightVev  = normalised lightDir
+	// lightVec  = normalised lightDir
 	// toCamera  = vector to the camera
 	// toCamera  = vector to the camera
 	// normal    = surface normal of the pixel
 	// normal    = surface normal of the pixel
 	// roughness = roughness of the pixel
 	// roughness = roughness of the pixel
 	// diffColor = the rgb color of the pixel
 	// diffColor = the rgb color of the pixel
 	// specColor = the rgb specular color of the pixel
 	// specColor = the rgb specular color of the pixel
-	float3 GetBRDF(float3 lightDir, float3 lightVec, float3 toCamera, float3 normal, float roughness, float3 diffColor, float3 specColor)
+	float3 GetBRDF(float3 worldPos, float3 lightDir, float3 lightVec, float3 toCamera, float3 normal, float roughness, float3 diffColor, float3 specColor)
 	{
 	{
 
 
         const float3 Hn = normalize(toCamera + lightDir);
         const float3 Hn = normalize(toCamera + lightDir);
         const float vdh = clamp((dot(toCamera, Hn)), M_EPSILON, 1.0);
         const float vdh = clamp((dot(toCamera, Hn)), M_EPSILON, 1.0);
         const float ndh = clamp((dot(normal, Hn)), M_EPSILON, 1.0);
         const float ndh = clamp((dot(normal, Hn)), M_EPSILON, 1.0);
-        const float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
+        float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
         const float ndv = clamp((dot(normal, toCamera)), M_EPSILON, 1.0);
         const float ndv = clamp((dot(normal, toCamera)), M_EPSILON, 1.0);
 
 
-        const float3 diffuseFactor = Diffuse(diffColor, roughness, ndv, ndl, vdh);
+        const float3 diffuseFactor = Diffuse(diffColor, roughness, ndv, ndl, vdh)  * ndl;
         float3 specularFactor = 0;
         float3 specularFactor = 0;
 
 
         #ifdef SPECULAR
         #ifdef SPECULAR
-            const float3 fresnelTerm = Fresnel(specColor, vdh) ;
-            const float distTerm = Distribution(ndh, roughness);
-            const float visTerm = Visibility(ndl, ndv, roughness);
+            if(cLightRad > 0.0)
+            {
+                if(cLightLength > 0.0)
+                {
+                    specularFactor = TubeLight(worldPos, lightVec, normal, toCamera, roughness, specColor, ndl);
+                    specularFactor *= ndl;
+                }
+                else
+                {
+                    specularFactor = SphereLight(worldPos, lightVec, normal, toCamera, roughness, specColor, ndl);
+                    specularFactor *= ndl;
+                }
+            }
+            else
+            {
+                const float3 fresnelTerm = Fresnel(specColor, vdh) ;
+                const float distTerm = Distribution(ndh, roughness);
+                const float visTerm = Visibility(ndl, ndv, roughness);
+                specularFactor = distTerm * visTerm * fresnelTerm * ndl/ M_PI;
+            }
 
 
-            specularFactor = distTerm * visTerm * fresnelTerm / M_PI;
         #endif
         #endif
 
 
         return diffuseFactor + specularFactor;
         return diffuseFactor + specularFactor;

+ 10 - 2
Resources/CoreData/Shaders/HLSL/PBRDeferred.hlsl

@@ -93,7 +93,15 @@ void PS(
     const float4 projWorldPos = float4(worldPos, 1.0);
     const float4 projWorldPos = float4(worldPos, 1.0);
 
 
     float3 lightDir;
     float3 lightDir;
-    float atten = GetAtten(normal, worldPos, lightDir);
+     float atten = 1;
+
+        #if defined(DIRLIGHT)
+            atten = GetAtten(normal, worldPos, lightDir);
+        #elif defined(SPOTLIGHT)
+            atten = GetAttenSpot(normal, worldPos, lightDir);
+        #else
+            atten = GetAttenPoint(normal, worldPos, lightDir);
+        #endif
 
 
     float shadow = 1;
     float shadow = 1;
     #ifdef SHADOW
     #ifdef SHADOW
@@ -113,7 +121,7 @@ void PS(
     const float3 lightVec = normalize(lightDir);
     const float3 lightVec = normalize(lightDir);
     const float ndl = clamp(abs(dot(normal, lightVec)), M_EPSILON, 1.0);
     const float ndl = clamp(abs(dot(normal, lightVec)), M_EPSILON, 1.0);
 
 
-    float3 BRDF = GetBRDF(lightDir, lightVec, toCamera, normal, roughness, albedoInput.rgb, specColor);
+    float3 BRDF = GetBRDF(worldPos, lightDir, lightVec, toCamera, normal, roughness, albedoInput.rgb, specColor);
 
 
     oColor.a = 1;
     oColor.a = 1;
     oColor.rgb  = BRDF * lightColor * shadow * atten / M_PI;
     oColor.rgb  = BRDF * lightColor * shadow * atten / M_PI;

+ 15 - 8
Resources/CoreData/Shaders/HLSL/PBRLitSolid.hlsl

@@ -1,9 +1,9 @@
 #include "Uniforms.hlsl"
 #include "Uniforms.hlsl"
 #include "Samplers.hlsl"
 #include "Samplers.hlsl"
+#include "Constants.hlsl"
 #include "Transform.hlsl"
 #include "Transform.hlsl"
 #include "ScreenPos.hlsl"
 #include "ScreenPos.hlsl"
 #include "Lighting.hlsl"
 #include "Lighting.hlsl"
-#include "Constants.hlsl"
 #include "Fog.hlsl"
 #include "Fog.hlsl"
 #include "PBR.hlsl"
 #include "PBR.hlsl"
 #include "IBL.hlsl"
 #include "IBL.hlsl"
@@ -21,7 +21,7 @@ void VS(float4 iPos : POSITION,
     #if defined(LIGHTMAP) || defined(AO)
     #if defined(LIGHTMAP) || defined(AO)
         float2 iTexCoord2 : TEXCOORD1,
         float2 iTexCoord2 : TEXCOORD1,
     #endif
     #endif
-    #if defined(NORMALMAP)|| defined(IBL) || defined(TRAILFACECAM) || defined(TRAILBONE)
+    #if (defined(NORMALMAP)|| defined(IBL) || defined(TRAILFACECAM) || defined(TRAILBONE)) && !defined(BILLBOARD) && !defined(DIRBILLBOARD)
         float4 iTangent : TANGENT,
         float4 iTangent : TANGENT,
     #endif
     #endif
     #ifdef SKINNED
     #ifdef SKINNED
@@ -90,10 +90,10 @@ void VS(float4 iPos : POSITION,
     #endif
     #endif
 
 
     #if defined(NORMALMAP) || defined(IBL)
     #if defined(NORMALMAP) || defined(IBL)
-        const float3 tangent = GetWorldTangent(modelMatrix);
-        const float3 bitangent = cross(tangent, oNormal) * iTangent.w;
+        const float4 tangent = GetWorldTangent(modelMatrix);
+        const float3 bitangent = cross(tangent.xyz, oNormal) * tangent.w;
         oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
         oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
-        oTangent = float4(tangent, bitangent.z);
+        oTangent = float4(tangent.xyz, bitangent.z);
     #else
     #else
         oTexCoord = GetTexCoord(iTexCoord);
         oTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif
@@ -226,7 +226,7 @@ void PS(
     diffColor.rgb = diffColor.rgb - diffColor.rgb * metalness; // Modulate down the diffuse
     diffColor.rgb = diffColor.rgb - diffColor.rgb * metalness; // Modulate down the diffuse
 
 
     // Get normal
     // Get normal
-    #if defined(NORMALMAP) || defined(DIRBILLBOARD) || defined(IBL)
+    #if defined(NORMALMAP) || defined(IBL)
         const float3 tangent = normalize(iTangent.xyz);
         const float3 tangent = normalize(iTangent.xyz);
         const float3 bitangent = normalize(float3(iTexCoord.zw, iTangent.w));
         const float3 bitangent = normalize(float3(iTexCoord.zw, iTangent.w));
         const float3x3 tbn = float3x3(tangent, bitangent, iNormal);
         const float3x3 tbn = float3x3(tangent, bitangent, iNormal);
@@ -252,8 +252,15 @@ void PS(
         float3 lightDir;
         float3 lightDir;
         float3 lightColor;
         float3 lightColor;
         float3 finalColor;
         float3 finalColor;
+        float atten = 1;
 
 
-        float atten = GetAtten(normal, iWorldPos.xyz, lightDir);
+        #if defined(DIRLIGHT)
+            atten = GetAtten(normal, iWorldPos.xyz, lightDir);
+        #elif defined(SPOTLIGHT)
+            atten = GetAttenSpot(normal, iWorldPos.xyz, lightDir);
+        #else
+            atten = GetAttenPoint(normal, iWorldPos.xyz, lightDir);
+        #endif
 
 
         float shadow = 1.0;
         float shadow = 1.0;
 
 
@@ -275,7 +282,7 @@ void PS(
         const float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
         const float ndl = clamp((dot(normal, lightVec)), M_EPSILON, 1.0);
 
 
 
 
-        float3 BRDF = GetBRDF(lightDir, lightVec, toCamera, normal, roughness, diffColor.rgb, specColor);
+        float3 BRDF = GetBRDF(iWorldPos.xyz, lightDir, lightVec, toCamera, normal, roughness, diffColor.rgb, specColor);
         finalColor.rgb = BRDF * lightColor * (atten * shadow) / M_PI;
         finalColor.rgb = BRDF * lightColor * (atten * shadow) / M_PI;
 
 
         #ifdef AMBIENT
         #ifdef AMBIENT

+ 9 - 6
Resources/CoreData/Shaders/HLSL/Shadow.hlsl

@@ -3,6 +3,9 @@
 #include "Transform.hlsl"
 #include "Transform.hlsl"
 
 
 void VS(float4 iPos : POSITION,
 void VS(float4 iPos : POSITION,
+    #ifndef NOUV
+        float2 iTexCoord : TEXCOORD0,
+    #endif
     #ifdef SKINNED
     #ifdef SKINNED
         float4 iBlendWeights : BLENDWEIGHT,
         float4 iBlendWeights : BLENDWEIGHT,
         int4 iBlendIndices : BLENDINDICES,
         int4 iBlendIndices : BLENDINDICES,
@@ -10,11 +13,11 @@ void VS(float4 iPos : POSITION,
     #ifdef INSTANCED
     #ifdef INSTANCED
         float4x3 iModelInstance : TEXCOORD4,
         float4x3 iModelInstance : TEXCOORD4,
     #endif
     #endif
-    #ifndef NOUV
-        float2 iTexCoord : TEXCOORD0,
+    #if defined(BILLBOARD) || defined(DIRBILLBOARD)
+        float2 iSize : TEXCOORD1,
     #endif
     #endif
     #ifdef VSM_SHADOW
     #ifdef VSM_SHADOW
-        out float3 oTexCoord : TEXCOORD0,
+        out float4 oTexCoord : TEXCOORD0,
     #else
     #else
         out float2 oTexCoord : TEXCOORD0,
         out float2 oTexCoord : TEXCOORD0,
     #endif
     #endif
@@ -29,7 +32,7 @@ void VS(float4 iPos : POSITION,
     float3 worldPos = GetWorldPos(modelMatrix);
     float3 worldPos = GetWorldPos(modelMatrix);
     oPos = GetClipPos(worldPos);
     oPos = GetClipPos(worldPos);
     #ifdef VSM_SHADOW
     #ifdef VSM_SHADOW
-        oTexCoord = float3(GetTexCoord(iTexCoord), oPos.z/oPos.w);
+        oTexCoord = float4(GetTexCoord(iTexCoord), oPos.z, oPos.w);
     #else
     #else
         oTexCoord = GetTexCoord(iTexCoord);
         oTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif
@@ -37,7 +40,7 @@ void VS(float4 iPos : POSITION,
 
 
 void PS(
 void PS(
     #ifdef VSM_SHADOW
     #ifdef VSM_SHADOW
-        float3 iTexCoord : TEXCOORD0,
+        float4 iTexCoord : TEXCOORD0,
     #else
     #else
         float2 iTexCoord : TEXCOORD0,
         float2 iTexCoord : TEXCOORD0,
     #endif
     #endif
@@ -50,7 +53,7 @@ void PS(
     #endif
     #endif
 
 
     #ifdef VSM_SHADOW
     #ifdef VSM_SHADOW
-        float depth = iTexCoord.z;
+        float depth = iTexCoord.z / iTexCoord.w;
         oColor = float4(depth, depth * depth, 1.0, 1.0);
         oColor = float4(depth, depth * depth, 1.0, 1.0);
     #else
     #else
         oColor = 1.0;
         oColor = 1.0;

+ 3 - 0
Resources/CoreData/Shaders/HLSL/Skybox.hlsl

@@ -3,6 +3,9 @@
 #include "Transform.hlsl"
 #include "Transform.hlsl"
 
 
 void VS(float4 iPos : POSITION,
 void VS(float4 iPos : POSITION,
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD4,
+    #endif
     out float3 oTexCoord : TEXCOORD0,
     out float3 oTexCoord : TEXCOORD0,
     out float4 oPos : OUTPOSITION)
     out float4 oPos : OUTPOSITION)
 {
 {

+ 59 - 21
Resources/CoreData/Shaders/HLSL/Text.hlsl

@@ -37,38 +37,76 @@ void VS(float4 iPos : POSITION,
     oTexCoord = iTexCoord;
     oTexCoord = iTexCoord;
 }
 }
 
 
+// See notes in GLSL shader
+#if defined(COMPILEPS) && defined(SIGNED_DISTANCE_FIELD)
+    float GetAlpha(float distance, float width)
+    {
+        return smoothstep(0.5 - width, 0.5 + width, distance);
+    }
+
+    // Comment this define to turn off supersampling
+    #define SUPERSAMPLING
+#endif
+
+
 void PS(float2 iTexCoord : TEXCOORD0,
 void PS(float2 iTexCoord : TEXCOORD0,
     float4 iColor : COLOR0,
     float4 iColor : COLOR0,
     out float4 oColor : OUTCOLOR0)
     out float4 oColor : OUTCOLOR0)
 {
 {
-    oColor.rgb = iColor.rgb;
-
 #ifdef SIGNED_DISTANCE_FIELD
 #ifdef SIGNED_DISTANCE_FIELD
+    oColor.rgb = iColor.rgb;
     float distance = Sample2D(DiffMap, iTexCoord).a;
     float distance = Sample2D(DiffMap, iTexCoord).a;
-    if (distance < 0.5f)
-    {
-    #ifdef TEXT_EFFECT_SHADOW
-        if (Sample2D(DiffMap, iTexCoord - cShadowOffset).a > 0.5f)
-            oColor = cShadowColor;
-        else
-    #endif
-        oColor.a = 0.0f;
-    }
-    else
-    {
+
     #ifdef TEXT_EFFECT_STROKE
     #ifdef TEXT_EFFECT_STROKE
-        if (distance < 0.525f)
-            oColor.rgb = cStrokeColor.rgb;
+        #ifdef SUPERSAMPLING
+            float outlineFactor = smoothstep(0.5, 0.525, distance); // Border of glyph
+            oColor.rgb = lerp(cStrokeColor.rgb, iColor.rgb, outlineFactor);
+        #else
+            if (distance < 0.525)
+                oColor.rgb = cStrokeColor.rgb;
+        #endif
     #endif
     #endif
 
 
     #ifdef TEXT_EFFECT_SHADOW
     #ifdef TEXT_EFFECT_SHADOW
-        if (Sample2D(DiffMap, iTexCoord + cShadowOffset).a < 0.5f)
-            oColor.a = iColor.a;
+        if (Sample2D(DiffMap, iTexCoord - cShadowOffset).a > 0.5 && distance <= 0.5)
+            oColor = cShadowColor;
+        #ifndef SUPERSAMPLING
+        else if (distance <= 0.5)
+            oColor.a = 0.0;
+        #endif
         else
         else
     #endif
     #endif
-        oColor.a = iColor.a * smoothstep(0.5f, 0.505f, distance);
-    }
+        {
+            float width = fwidth(distance);
+            float alpha = GetAlpha(distance, width);
+
+            #ifdef SUPERSAMPLING
+                float2 deltaUV = 0.354 * fwidth(iTexCoord); // (1.0 / sqrt(2.0)) / 2.0 = 0.354
+                float4 square = float4(iTexCoord - deltaUV, iTexCoord + deltaUV);
+
+                float distance2 = Sample2D(DiffMap, square.xy).a;
+                float distance3 = Sample2D(DiffMap, square.zw).a;
+                float distance4 = Sample2D(DiffMap, square.xw).a;
+                float distance5 = Sample2D(DiffMap, square.zy).a;
+
+                alpha += GetAlpha(distance2, width)
+                       + GetAlpha(distance3, width)
+                       + GetAlpha(distance4, width)
+                       + GetAlpha(distance5, width);
+            
+                // For calculating of average correct would be dividing by 5.
+                // But when text is blurred, its brightness is lost. Therefore divide by 4.
+                alpha = alpha * 0.25;
+            #endif
+
+            oColor.a = alpha;
+        }
 #else
 #else
-    oColor.a = iColor.a * Sample2D(DiffMap, iTexCoord).a;
+    #ifdef ALPHAMAP
+        oColor.rgb = iColor.rgb;
+        oColor.a = iColor.a * Sample2D(DiffMap, iTexCoord).a;
+    #else
+        oColor = iColor* Sample2D(DiffMap, iTexCoord);
+    #endif
 #endif
 #endif
-}
+}

+ 9 - 2
Resources/CoreData/Shaders/HLSL/Transform.hlsl

@@ -106,7 +106,7 @@ float3 GetTrailNormal(float4 iPos, float3 iParentPos, float3 iForward)
 #endif
 #endif
 
 
 #if defined(SKINNED)
 #if defined(SKINNED)
-    #define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices);
+    #define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices)
 #elif defined(INSTANCED)
 #elif defined(INSTANCED)
     #define iModelMatrix iModelInstance
     #define iModelMatrix iModelInstance
 #else
 #else
@@ -137,7 +137,14 @@ float3 GetTrailNormal(float4 iPos, float3 iParentPos, float3 iForward)
     #define GetWorldNormal(modelMatrix) normalize(mul(iNormal, (float3x3)modelMatrix))
     #define GetWorldNormal(modelMatrix) normalize(mul(iNormal, (float3x3)modelMatrix))
 #endif
 #endif
 
 
-#define GetWorldTangent(modelMatrix) normalize(mul(iTangent.xyz, (float3x3)modelMatrix))
+#if defined(BILLBOARD)
+    #define GetWorldTangent(modelMatrix) float4(normalize(mul(float3(1.0, 0.0, 0.0), cBillboardRot)), 1.0)
+#elif defined(DIRBILLBOARD)
+    #define GetWorldTangent(modelMatrix) float4(normalize(mul(float3(1.0, 0.0, 0.0), (float3x3)modelMatrix)), 1.0)
+#else
+    #define GetWorldTangent(modelMatrix) float4(normalize(mul(iTangent.xyz, (float3x3)modelMatrix)), iTangent.w)
+#endif
+
 #endif
 #endif
 
 
 #ifdef COMPILEPS
 #ifdef COMPILEPS

+ 10 - 0
Resources/CoreData/Shaders/HLSL/Uniforms.hlsl

@@ -60,7 +60,11 @@ uniform float4 cMatSpecColor;
 #ifdef PBR
 #ifdef PBR
     uniform float cRoughness;
     uniform float cRoughness;
     uniform float cMetallic;
     uniform float cMetallic;
+    uniform float cLightRad;
+    uniform float cLightLength;
 #endif
 #endif
+uniform float3 cZoneMin;
+uniform float3 cZoneMax;
 uniform float cNearClipPS;
 uniform float cNearClipPS;
 uniform float cFarClipPS;
 uniform float cFarClipPS;
 uniform float4 cShadowCubeAdjust;
 uniform float4 cShadowCubeAdjust;
@@ -163,6 +167,8 @@ cbuffer ZonePS : register(b2)
     float4 cAmbientColor;
     float4 cAmbientColor;
     float4 cFogParams;
     float4 cFogParams;
     float3 cFogColor;
     float3 cFogColor;
+    float3 cZoneMin;
+    float3 cZoneMax;
 }
 }
 
 
 cbuffer LightPS : register(b3)
 cbuffer LightPS : register(b3)
@@ -178,6 +184,10 @@ cbuffer LightPS : register(b3)
     float4 cShadowSplits;
     float4 cShadowSplits;
     float2 cVSMShadowParams;
     float2 cVSMShadowParams;
     float4x4 cLightMatricesPS[4];
     float4x4 cLightMatricesPS[4];
+    #ifdef PBR
+        float cLightRad;
+        float cLightLength;
+    #endif
 }
 }
 
 
 #ifndef CUSTOM_MATERIAL_CBUFFER
 #ifndef CUSTOM_MATERIAL_CBUFFER

+ 145 - 0
Resources/CoreData/Shaders/HLSL/UnlitParticle.hlsl

@@ -0,0 +1,145 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Fog.hlsl"
+
+#if defined(COMPILEPS) && defined(SOFTPARTICLES)
+#ifndef D3D11
+// D3D9 uniform
+uniform float cSoftParticleFadeScale;
+#else
+// D3D11 constant buffer
+cbuffer CustomPS : register(b6)
+{
+    float cSoftParticleFadeScale;
+}
+#endif
+#endif
+
+void VS(float4 iPos : POSITION,
+    #ifndef NOUV
+        float2 iTexCoord : TEXCOORD0,
+    #endif
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD4,
+    #endif
+    #if defined(BILLBOARD) || defined(DIRBILLBOARD)
+        float2 iSize : TEXCOORD1,
+    #endif
+    #if defined(DIRBILLBOARD) || defined(TRAILBONE)
+        float3 iNormal : NORMAL,
+    #endif
+    #if defined(TRAILFACECAM) || defined(TRAILBONE)
+        float4 iTangent : TANGENT,
+    #endif
+    out float2 oTexCoord : TEXCOORD0,
+    #ifdef SOFTPARTICLES
+        out float4 oScreenPos : TEXCOORD1,
+    #endif
+    out float4 oWorldPos : TEXCOORD2,
+    #ifdef VERTEXCOLOR
+        out float4 oColor : COLOR0,
+    #endif
+    #if defined(D3D11) && defined(CLIPPLANE)
+        out float oClip : SV_CLIPDISTANCE0,
+    #endif
+    out float4 oPos : OUTPOSITION)
+{
+    // Define a 0,0 UV coord if not expected from the vertex data
+    #ifdef NOUV
+    float2 iTexCoord = float2(0.0, 0.0);
+    #endif
+
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetTexCoord(iTexCoord);
+    oWorldPos = float4(worldPos, GetDepth(oPos));
+
+    #if defined(D3D11) && defined(CLIPPLANE)
+        oClip = dot(oPos, cClipPlane);
+    #endif
+
+    #ifdef SOFTPARTICLES
+        oScreenPos = GetScreenPos(oPos);
+    #endif
+
+    #ifdef VERTEXCOLOR
+        oColor = iColor;
+    #endif
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    #ifdef SOFTPARTICLES
+        float4 iScreenPos: TEXCOORD1,
+    #endif
+    float4 iWorldPos: TEXCOORD2,
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    #if defined(D3D11) && defined(CLIPPLANE)
+        float iClip : SV_CLIPDISTANCE0,
+    #endif
+    out float4 oColor : OUTCOLOR0)
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        float4 diffColor = cMatDiffColor * Sample2D(DiffMap, iTexCoord);
+        #ifdef ALPHAMASK
+            if (diffColor.a < 0.5)
+                discard;
+        #endif
+    #else
+        float4 diffColor = cMatDiffColor;
+    #endif
+
+    #ifdef VERTEXCOLOR
+        diffColor *= iColor;
+    #endif
+
+    // Get fog factor
+    #ifdef HEIGHTFOG
+        float fogFactor = GetHeightFogFactor(iWorldPos.w, iWorldPos.y);
+    #else
+        float fogFactor = GetFogFactor(iWorldPos.w);
+    #endif
+    
+    // Soft particle fade
+    // In expand mode depth test should be off. In that case do manual alpha discard test first to reduce fill rate
+    #ifdef SOFTPARTICLES
+        #if defined(EXPAND) && !defined(ADDITIVE)
+            if (diffColor.a < 0.01)
+                discard;
+        #endif
+
+        float particleDepth = iWorldPos.w;
+        float depth = Sample2DProj(DepthBuffer, iScreenPos).r;
+        #ifdef HWDEPTH
+            depth = ReconstructDepth(depth);
+        #endif
+
+        #ifdef EXPAND
+            float diffZ = max(particleDepth - depth, 0.0) * (cFarClipPS - cNearClipPS);
+            float fade = saturate(diffZ * cSoftParticleFadeScale);
+        #else
+            float diffZ = (depth - particleDepth) * (cFarClipPS - cNearClipPS);
+            float fade = saturate(1.0 - diffZ * cSoftParticleFadeScale);
+        #endif
+
+        #ifndef ADDITIVE
+            diffColor.a = max(diffColor.a - fade, 0.0);
+        #else
+            diffColor.rgb = max(diffColor.rgb - fade, float3(0.0, 0.0, 0.0));
+        #endif
+    #endif
+
+    oColor = float4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
+}

+ 6 - 6
Resources/CoreData/Shaders/HLSL/Vegetation.hlsl

@@ -39,7 +39,7 @@ void VS(float4 iPos : POSITION,
     #if defined(LIGHTMAP) || defined(AO)
     #if defined(LIGHTMAP) || defined(AO)
         float2 iTexCoord2 : TEXCOORD1,
         float2 iTexCoord2 : TEXCOORD1,
     #endif
     #endif
-    #if defined(NORMALMAP) || defined(TRAILFACECAM) || defined(TRAILBONE)
+    #if (defined(NORMALMAP) || defined(TRAILFACECAM) || defined(TRAILBONE)) && !defined(BILLBOARD) && !defined(DIRBILLBOARD)
         float4 iTangent : TANGENT,
         float4 iTangent : TANGENT,
     #endif
     #endif
     #ifdef SKINNED
     #ifdef SKINNED
@@ -95,7 +95,7 @@ void VS(float4 iPos : POSITION,
 
 
     float4x3 modelMatrix = iModelMatrix;
     float4x3 modelMatrix = iModelMatrix;
     float3 worldPos = GetWorldPos(modelMatrix);
     float3 worldPos = GetWorldPos(modelMatrix);
-    float height = worldPos.y - cModel._m31;
+    float height = worldPos.y - modelMatrix._m31;
 
 
     float windStrength = max(height - cWindHeightPivot, 0.0) * cWindHeightFactor;
     float windStrength = max(height - cWindHeightPivot, 0.0) * cWindHeightFactor;
     float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
     float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
@@ -115,10 +115,10 @@ void VS(float4 iPos : POSITION,
     #endif
     #endif
 
 
     #ifdef NORMALMAP
     #ifdef NORMALMAP
-        float3 tangent = GetWorldTangent(modelMatrix);
-        float3 bitangent = cross(tangent, oNormal) * iTangent.w;
+        float4 tangent = GetWorldTangent(modelMatrix);
+        float3 bitangent = cross(tangent.xyz, oNormal) * tangent.w;
         oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
         oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
-        oTangent = float4(tangent, bitangent.z);
+        oTangent = float4(tangent.xyz, bitangent.z);
     #else
     #else
         oTexCoord = GetTexCoord(iTexCoord);
         oTexCoord = GetTexCoord(iTexCoord);
     #endif
     #endif
@@ -155,7 +155,7 @@ void VS(float4 iPos : POSITION,
             for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
             for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
                 oVertexLight += GetVertexLight(i, worldPos, oNormal) * cVertexLights[i * 3].rgb;
                 oVertexLight += GetVertexLight(i, worldPos, oNormal) * cVertexLights[i * 3].rgb;
         #endif
         #endif
-        
+
         oScreenPos = GetScreenPos(oPos);
         oScreenPos = GetScreenPos(oPos);
 
 
         #ifdef ENVCUBEMAP
         #ifdef ENVCUBEMAP

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

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

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

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

+ 3 - 0
Resources/CoreData/Techniques/DiffUnlitParticleAdd.xml

@@ -0,0 +1,3 @@
+<technique vs="UnlitParticle" ps="UnlitParticle" vsdefines="VERTEXCOLOR" psdefines="DIFFMAP VERTEXCOLOR ADDITIVE">
+    <pass name="alpha" depthwrite="false" blend="add" />
+</technique>

+ 3 - 0
Resources/CoreData/Techniques/DiffUnlitParticleAddSoft.xml

@@ -0,0 +1,3 @@
+<technique vs="UnlitParticle" ps="UnlitParticle" vsdefines="VERTEXCOLOR SOFTPARTICLES" psdefines="DIFFMAP VERTEXCOLOR ADDITIVE SOFTPARTICLES">
+    <pass name="alpha" depthwrite="false" blend="add" />
+</technique>

+ 3 - 0
Resources/CoreData/Techniques/DiffUnlitParticleAddSoftExpand.xml

@@ -0,0 +1,3 @@
+<technique vs="UnlitParticle" ps="UnlitParticle" vsdefines="VERTEXCOLOR SOFTPARTICLES" psdefines="DIFFMAP VERTEXCOLOR ADDITIVE SOFTPARTICLES EXPAND">
+    <pass name="alpha" depthwrite="false" depthtest="false" blend="add" />
+</technique>

+ 3 - 0
Resources/CoreData/Techniques/DiffUnlitParticleAlpha.xml

@@ -0,0 +1,3 @@
+<technique vs="UnlitParticle" ps="UnlitParticle" vsdefines="VERTEXCOLOR" psdefines="DIFFMAP VERTEXCOLOR">
+    <pass name="alpha" depthwrite="false" blend="alpha" />
+</technique>

+ 3 - 0
Resources/CoreData/Techniques/DiffUnlitParticleAlphaSoft.xml

@@ -0,0 +1,3 @@
+<technique vs="UnlitParticle" ps="UnlitParticle" vsdefines="VERTEXCOLOR SOFTPARTICLES" psdefines="DIFFMAP VERTEXCOLOR SOFTPARTICLES">
+    <pass name="alpha" depthwrite="false" blend="alpha" />
+</technique>

+ 3 - 0
Resources/CoreData/Techniques/DiffUnlitParticleAlphaSoftExpand.xml

@@ -0,0 +1,3 @@
+<technique vs="UnlitParticle" ps="UnlitParticle" vsdefines="VERTEXCOLOR SOFTPARTICLES" psdefines="DIFFMAP VERTEXCOLOR SOFTPARTICLES EXPAND">
+    <pass name="alpha" depthwrite="false" depthtest="false" blend="alpha" />
+</technique>

+ 15 - 0
Script/AtomicNET/AtomicNET/Graphics/AnimatedModel.cs

@@ -7,6 +7,21 @@ namespace AtomicEngine
     public partial class AnimatedModel : StaticModel
     public partial class AnimatedModel : StaticModel
     {
     {
 
 
+        
+        new public Model Model
+        {
+            get
+            {
+                return GetModel();
+            }
+            set
+            {
+                // AnimatedModel overloads StaticModel::SetModel(Model* model) with AnimatedModel::SetModel(Model*, bool createBones = false)
+                // need to make sure we pick right overload, otherwise will call wrong method native side
+                SetModel(value, true);
+            }
+        }
+
         public Skeleton Skeleton
         public Skeleton Skeleton
         {
         {
             get
             get

+ 1 - 1
Script/AtomicNET/AtomicNET/IO/File.cs

@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
 
 
 namespace AtomicEngine
 namespace AtomicEngine
 {
 {
-    public partial class File : AObject, Deserializer, Serializer
+    public partial class File : AObject, AbstractFile
     {
     {
         private class Stream : System.IO.Stream
         private class Stream : System.IO.Stream
         {
         {

+ 14 - 0
Script/AtomicNET/Platform/Android/JavaSDL/src/main/java/org/libsdl/app/AtomicActivity.java

@@ -20,6 +20,20 @@ public class AtomicActivity extends Activity {
         setContentView(mLayout);
         setContentView(mLayout);
     }
     }
 
 
+    // ATOMIC BEGIN
+    /**
+     * This method is called by SDL if SDL did not handle a message itself.
+     * This happens if a received message contains an unsupported command.
+     * Method can be overwritten to handle Messages in a different class.
+     * @param command the command of the message.
+     * @param param the parameter of the message. May be null.
+     * @return if the message was handled in overridden method.
+     */
+    protected boolean onUnhandledMessage(int command, Object param) {
+        return false;
+    }
+    //ATOMIC END
+
     @Override
     @Override
     protected void onResume() {
     protected void onResume() {
         super.onResume();
         super.onResume();

+ 298 - 95
Script/AtomicNET/Platform/Android/JavaSDL/src/main/java/org/libsdl/app/SDLActivity.java

@@ -21,7 +21,7 @@ import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.AbsoluteLayout;
+import android.widget.RelativeLayout;
 import android.widget.Button;
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.TextView;
@@ -37,7 +37,9 @@ import android.content.pm.ActivityInfo;
 /**
 /**
  SDL Activity
  SDL Activity
  */
  */
+// ATOMIC BEGIN
 public class SDLActivity {
 public class SDLActivity {
+// ATOMIC END
     private static final String TAG = "SDL";
     private static final String TAG = "SDL";
 
 
     // Keep track of the paused state
     // Keep track of the paused state
@@ -49,7 +51,9 @@ public class SDLActivity {
     public static boolean mSeparateMouseAndTouch;
     public static boolean mSeparateMouseAndTouch;
 
 
     // Main components
     // Main components
+    // ATOMIC BEGIN
     protected static Activity mSingleton;
     protected static Activity mSingleton;
+    // ATOMIC END
     protected static SDLSurface mSurface;
     protected static SDLSurface mSurface;
     protected static View mTextEdit;
     protected static View mTextEdit;
     protected static ViewGroup mLayout;
     protected static ViewGroup mLayout;
@@ -60,10 +64,35 @@ public class SDLActivity {
 
 
     // Audio
     // Audio
     protected static AudioTrack mAudioTrack;
     protected static AudioTrack mAudioTrack;
+    protected static AudioRecord mAudioRecord;
 
 
     // Urho3D: flag to load the .so and a new method load them
     // Urho3D: flag to load the .so and a new method load them
     private static boolean mIsSharedLibraryLoaded = false;
     private static boolean mIsSharedLibraryLoaded = false;
 
 
+    // ATOMIC BEGIN
+    public static SDLSurface createSurface(Activity activity) {
+            SDLActivity.initialize();
+            mSingleton = activity;
+
+            if (!mIsSharedLibraryLoaded) {
+                System.loadLibrary("AtomicNETNative");
+                mIsSharedLibraryLoaded = true;
+            }
+            // Set up the surface
+            mSurface = new SDLSurface(activity.getApplication());
+
+            if(Build.VERSION.SDK_INT >= 12) {
+                mJoystickHandler = new SDLJoystickHandler_API12();
+            }
+            else {
+                mJoystickHandler = new SDLJoystickHandler();
+            }
+
+            return mSurface;
+        }
+    // ATOMIC END
+
+
     protected boolean onLoadLibrary(ArrayList<String> libraryNames) {
     protected boolean onLoadLibrary(ArrayList<String> libraryNames) {
         for (final String name : libraryNames) {
         for (final String name : libraryNames) {
             System.loadLibrary(name);
             System.loadLibrary(name);
@@ -71,6 +100,17 @@ public class SDLActivity {
         return true;
         return true;
     }
     }
 
 
+    /**
+     * This method is called by SDL before starting the native application thread.
+     * It can be overridden to provide the arguments after the application name.
+     * The default implementation returns an empty array. It never returns null.
+     * @return arguments for the native application.
+     */
+    static protected String[] getArguments() {
+        // Urho3D: always return the "app_process" as the first argument instead of empty array
+        return new String[]{"app_process"};
+    }
+
     public static void initialize() {
     public static void initialize() {
         // The static nature of the singleton and Android quirkyness force us to initialize everything here
         // The static nature of the singleton and Android quirkyness force us to initialize everything here
         // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
         // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
@@ -81,22 +121,93 @@ public class SDLActivity {
         mJoystickHandler = null;
         mJoystickHandler = null;
         mSDLThread = null;
         mSDLThread = null;
         mAudioTrack = null;
         mAudioTrack = null;
+        mAudioRecord = null;
         mExitCalledFromJava = false;
         mExitCalledFromJava = false;
         mIsPaused = false;
         mIsPaused = false;
         mIsSurfaceReady = false;
         mIsSurfaceReady = false;
         mHasFocus = true;
         mHasFocus = true;
     }
     }
 
 
-    public static SDLSurface createSurface(Activity activity) {
+    // ATOMIC BEGIN
+    /*
+    // Setup
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log.v(TAG, "Device: " + android.os.Build.DEVICE);
+        Log.v(TAG, "Model: " + android.os.Build.MODEL);
+        Log.v(TAG, "onCreate(): " + mSingleton);
+        super.onCreate(savedInstanceState);
+
         SDLActivity.initialize();
         SDLActivity.initialize();
-        mSingleton = activity;
+        // So we can call stuff from static callbacks
+        mSingleton = this;
 
 
+        // Urho3D: auto load all the shared libraries available in the library path
         if (!mIsSharedLibraryLoaded) {
         if (!mIsSharedLibraryLoaded) {
-            System.loadLibrary("AtomicNETNative");
-            mIsSharedLibraryLoaded = true;
+            String libraryPath = getApplicationInfo().nativeLibraryDir;
+            File[] files = new File(libraryPath).listFiles(new FilenameFilter() {
+                @Override
+                public boolean accept(File dir, String filename) {
+                    // Only list libraries, i.e. exclude gdbserver when it presents
+                    // ATOMIC BEGIN
+                    // Do not load any file as a library that contains the word gdbserver, ever!
+                    if ( filename.contains("gdbserver")) {
+                        return false;
+                    }
+                    // ATOMIC END
+                    return filename.matches("^lib.*\\.so$");
+                }
+            });
+            Arrays.sort(files, new Comparator<File>() {
+                @Override
+                public int compare(File lhs, File rhs) {
+                    return Long.valueOf(lhs.lastModified()).compareTo(rhs.lastModified());
+                }
+            });
+            ArrayList<String> libraryNames = new ArrayList<String>(files.length);
+            for (final File libraryFilename : files) {
+                String name = libraryFilename.getName().replaceAll("^lib(.*)\\.so$", "$1");
+                libraryNames.add(name);
+            }
+
+            // Load shared libraries
+            String errorMsgBrokenLib = "";
+            try {
+                if (onLoadLibrary(libraryNames))
+                    mIsSharedLibraryLoaded = true;
+            } catch(UnsatisfiedLinkError e) {
+                errorMsgBrokenLib = e.getMessage();
+            } catch(Exception e) {
+                errorMsgBrokenLib = e.getMessage();
+            }
+
+            if (!errorMsgBrokenLib.isEmpty())
+            {
+                AlertDialog.Builder dlgAlert  = new AlertDialog.Builder(this);
+                dlgAlert.setMessage("An error occurred while trying to start the application. Please try again and/or reinstall."
+                      + System.getProperty("line.separator")
+                      + System.getProperty("line.separator")
+                      + "Error: " + errorMsgBrokenLib);
+                dlgAlert.setTitle("SDL Error");
+                dlgAlert.setPositiveButton("Exit",
+                    new DialogInterface.OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog,int id) {
+                            // if this button is clicked, close current activity
+                            SDLActivity.mSingleton.finish();
+                        }
+                    });
+               dlgAlert.setCancelable(false);
+               dlgAlert.create().show();
+
+               return;
+            }
         }
         }
+
         // Set up the surface
         // Set up the surface
+        // ATOMIC BEGIN
         mSurface = new SDLSurface(activity.getApplication());
         mSurface = new SDLSurface(activity.getApplication());
+        // ATOMIC END
 
 
         if(Build.VERSION.SDK_INT >= 12) {
         if(Build.VERSION.SDK_INT >= 12) {
             mJoystickHandler = new SDLJoystickHandler_API12();
             mJoystickHandler = new SDLJoystickHandler_API12();
@@ -105,15 +216,33 @@ public class SDLActivity {
             mJoystickHandler = new SDLJoystickHandler();
             mJoystickHandler = new SDLJoystickHandler();
         }
         }
 
 
-        return mSurface;
-    }
+        mLayout = new RelativeLayout(this);
+        mLayout.addView(mSurface);
+
+        setContentView(mLayout);
+
+        // Get filename from "Open with" of another application
+        Intent intent = getIntent();
+
+        if (intent != null && intent.getData() != null) {
+            String filename = intent.getData().getPath();
+            if (filename != null) {
+                Log.v(TAG, "Got filename: " + filename);
+                SDLActivity.onNativeDropFile(filename);
+            }
+        }
+    } */
 
 
     // Events
     // Events
+
+    // ATOMIC SDLActivity activity methods changes to static, so can be called by C# activity
+
     public static void onPause() {
     public static void onPause() {
+
         Log.v(TAG, "onPause()");
         Log.v(TAG, "onPause()");
 
 
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
-            return;
+           return;
         }
         }
 
 
         SDLActivity.handlePause();
         SDLActivity.handlePause();
@@ -123,7 +252,7 @@ public class SDLActivity {
         Log.v(TAG, "onResume()");
         Log.v(TAG, "onResume()");
 
 
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
-            return;
+           return;
         }
         }
 
 
         SDLActivity.handleResume();
         SDLActivity.handleResume();
@@ -131,10 +260,11 @@ public class SDLActivity {
 
 
 
 
     public static void onWindowFocusChanged(boolean hasFocus) {
     public static void onWindowFocusChanged(boolean hasFocus) {
+
         Log.v(TAG, "onWindowFocusChanged(): " + hasFocus);
         Log.v(TAG, "onWindowFocusChanged(): " + hasFocus);
 
 
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
-            return;
+           return;
         }
         }
 
 
         SDLActivity.mHasFocus = hasFocus;
         SDLActivity.mHasFocus = hasFocus;
@@ -147,7 +277,7 @@ public class SDLActivity {
         Log.v(TAG, "onLowMemory()");
         Log.v(TAG, "onLowMemory()");
 
 
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
-            return;
+           return;
         }
         }
 
 
         SDLActivity.nativeLowMemory();
         SDLActivity.nativeLowMemory();
@@ -157,9 +287,9 @@ public class SDLActivity {
         Log.v(TAG, "onDestroy()");
         Log.v(TAG, "onDestroy()");
 
 
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
-            // Reset everything in case the user re opens the app
-            SDLActivity.initialize();
-            return;
+           // Reset everything in case the user re opens the app
+           SDLActivity.initialize();
+           return;
         }
         }
 
 
         // Send a quit message to the application
         // Send a quit message to the application
@@ -185,19 +315,19 @@ public class SDLActivity {
     public static boolean dispatchKeyEvent(KeyEvent event) {
     public static boolean dispatchKeyEvent(KeyEvent event) {
 
 
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
         if (!SDLActivity.mIsSharedLibraryLoaded) {  // Urho3D
-            return false;
+           return false;
         }
         }
 
 
         int keyCode = event.getKeyCode();
         int keyCode = event.getKeyCode();
         // Ignore certain special keys so they're handled by Android
         // Ignore certain special keys so they're handled by Android
         // Urho3D: also ignore the Home key
         // Urho3D: also ignore the Home key
         if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
         if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
-                keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
-                keyCode == KeyEvent.KEYCODE_HOME ||
-                keyCode == KeyEvent.KEYCODE_CAMERA ||
-                keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */
-                keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */
-                ) {
+            keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
+            keyCode == KeyEvent.KEYCODE_HOME ||
+            keyCode == KeyEvent.KEYCODE_CAMERA ||
+            keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */
+            keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */
+            ) {
             return false;
             return false;
         }
         }
         return true;
         return true;
@@ -226,16 +356,22 @@ public class SDLActivity {
             mSurface.handleResume();
             mSurface.handleResume();
         }
         }
     }
     }
+
+    // ATOMIC BEGIN
+    public static boolean FinishActivityOnNativeExit = true;
+    // ATOMIC END
+
     /* The native thread has finished */
     /* The native thread has finished */
-    public static void handleNativeExit() throws Exception {
+    public static void handleNativeExit() {
         SDLActivity.mSDLThread = null;
         SDLActivity.mSDLThread = null;
-        Log.d(TAG, "handleNativeExit");
-        if (mSingleton != null && FinishActivityOnNativeExit){
+
+        // ATOMIC BEGIN
+        if (mSingleton != null && FinishActivityOnNativeExit) {
             mSingleton.finish();
             mSingleton.finish();
         }
         }
+        // ATOMIC END
     }
     }
 
 
-    public static boolean FinishActivityOnNativeExit = true;
 
 
     // Messages from the SDLMain thread
     // Messages from the SDLMain thread
     static final int COMMAND_CHANGE_TITLE = 1;
     static final int COMMAND_CHANGE_TITLE = 1;
@@ -271,41 +407,49 @@ public class SDLActivity {
                 return;
                 return;
             }
             }
             switch (msg.arg1) {
             switch (msg.arg1) {
-                case COMMAND_CHANGE_TITLE:
-                    if (context instanceof Activity) {
-                        ((Activity) context).setTitle((String)msg.obj);
+            case COMMAND_CHANGE_TITLE:
+                if (context instanceof Activity) {
+                    ((Activity) context).setTitle((String)msg.obj);
+                } else {
+                    Log.e(TAG, "error handling message, getContext() returned no Activity");
+                }
+                break;
+            case COMMAND_TEXTEDIT_HIDE:
+                if (mTextEdit != null) {
+                    // Note: On some devices setting view to GONE creates a flicker in landscape.
+                    // Setting the View's sizes to 0 is similar to GONE but without the flicker.
+                    // The sizes will be set to useful values when the keyboard is shown again.
+                    mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0));
+
+                    InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
+                }
+                break;
+            case COMMAND_SET_KEEP_SCREEN_ON:
+            {
+                Window window = ((Activity) context).getWindow();
+                if (window != null) {
+                    if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
+                        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                     } else {
                     } else {
-                        Log.e(TAG, "error handling message, getContext() returned no Activity");
-                    }
-                    break;
-                case COMMAND_TEXTEDIT_HIDE:
-                    if (mTextEdit != null) {
-                        mTextEdit.setVisibility(View.GONE);
-
-                        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
-                        imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
-                    }
-                    break;
-                case COMMAND_SET_KEEP_SCREEN_ON:
-                {
-                    Window window = ((Activity) context).getWindow();
-                    if (window != null) {
-                        if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
-                            window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-                        } else {
-                            window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-                        }
+                        window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                     }
                     }
-                    break;
                 }
                 }
-                default:
+                break;
+            }
+            default:
+                if ((context instanceof AtomicActivity) && !((AtomicActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
                     Log.e(TAG, "error handling message, command is " + msg.arg1);
                     Log.e(TAG, "error handling message, command is " + msg.arg1);
+                }
             }
             }
         }
         }
     }
     }
 
 
     // Handler for the messages
     // Handler for the messages
+    // ATOMIC BEGIN
+    // Made static
     static Handler commandHandler = new SDLCommandHandler();
     static Handler commandHandler = new SDLCommandHandler();
+    // ATOMIC END
 
 
     // Send a message from the SDLMain thread
     // Send a message from the SDLMain thread
     public static boolean sendCommand(int command, Object data) {
     public static boolean sendCommand(int command, Object data) {
@@ -416,17 +560,14 @@ public class SDLActivity {
 
 
         @Override
         @Override
         public void run() {
         public void run() {
-            AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(
-                    w, h + HEIGHT_PADDING, x, y);
+            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING);
+            params.leftMargin = x;
+            params.topMargin = y;
 
 
             if (mTextEdit == null) {
             if (mTextEdit == null) {
-                ViewParent parent = mSurface.getParent();
-                if (parent instanceof ViewGroup){
-                    mTextEdit = new DummyEdit(getContext());
-                    ((ViewGroup)parent).addView(mTextEdit, params);
-                } else {
-                    return;
-                }
+                mTextEdit = new DummyEdit(getContext());
+
+                mLayout.addView(mTextEdit, params);
             } else {
             } else {
                 mTextEdit.setLayoutParams(params);
                 mTextEdit.setLayoutParams(params);
             }
             }
@@ -459,7 +600,7 @@ public class SDLActivity {
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      */
      */
-    public static int audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+    public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
         int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
         int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
         int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
         int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
         int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
         int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
@@ -538,13 +679,72 @@ public class SDLActivity {
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      */
      */
-    public static void audioQuit() {
+    public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+        int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
+        int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
+        int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
+
+        Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+        // Let the user pick a larger buffer if they really want -- but ye
+        // gods they probably shouldn't, the minimums are horrifyingly high
+        // latency already
+        desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+        if (mAudioRecord == null) {
+            mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
+                    channelConfig, audioFormat, desiredFrames * frameSize);
+
+            // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
+            if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
+                Log.e(TAG, "Failed during initialization of AudioRecord");
+                mAudioRecord.release();
+                mAudioRecord = null;
+                return -1;
+            }
+
+            mAudioRecord.startRecording();
+        }
+
+        Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+        return 0;
+    }
+
+    /** This method is called by SDL using JNI. */
+    public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
+        // !!! FIXME: this is available in API Level 23. Until then, we always block.  :(
+        //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+        return mAudioRecord.read(buffer, 0, buffer.length);
+    }
+
+    /** This method is called by SDL using JNI. */
+    public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
+        // !!! FIXME: this is available in API Level 23. Until then, we always block.  :(
+        //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+        return mAudioRecord.read(buffer, 0, buffer.length);
+    }
+
+
+    /** This method is called by SDL using JNI. */
+    public static void audioClose() {
         if (mAudioTrack != null) {
         if (mAudioTrack != null) {
             mAudioTrack.stop();
             mAudioTrack.stop();
+            mAudioTrack.release();
             mAudioTrack = null;
             mAudioTrack = null;
         }
         }
     }
     }
 
 
+    /** This method is called by SDL using JNI. */
+    public static void captureClose() {
+        if (mAudioRecord != null) {
+            mAudioRecord.stop();
+            mAudioRecord.release();
+            mAudioRecord = null;
+        }
+    }
+
+
     // Input
     // Input
 
 
     /**
     /**
@@ -579,29 +779,35 @@ public class SDLActivity {
         }
         }
     }
     }
 
 
+    // Check if a given device is considered a possible SDL joystick
+    public static boolean isDeviceSDLJoystick(int deviceId) {
+        InputDevice device = InputDevice.getDevice(deviceId);
+        // We cannot use InputDevice.isVirtual before API 16, so let's accept
+        // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
+        if ((device == null) || (deviceId < 0)) {
+            return false;
+        }
+        int sources = device.getSources();
+        return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
+                ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
+                ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
+        );
+    }
+
     // APK expansion files support
     // APK expansion files support
 
 
     /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
     /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
-    private static Object expansionFile;
+    private Object expansionFile;
 
 
     /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
     /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
-    private static Method expansionFileMethod;
-
-    /**
-     * This method was called by SDL using JNI.
-     * @deprecated because of an incorrect name
-     */
-    @Deprecated
-    public InputStream openAPKExtensionInputStream(String fileName) throws IOException {
-        return openAPKExpansionInputStream(fileName);
-    }
+    private Method expansionFileMethod;
 
 
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      * @return an InputStream on success or null if no expansion file was used.
      * @return an InputStream on success or null if no expansion file was used.
      * @throws IOException on errors. Message is set for the SDL error message.
      * @throws IOException on errors. Message is set for the SDL error message.
      */
      */
-    public static InputStream openAPKExpansionInputStream(String fileName) throws IOException {
+    public InputStream openAPKExpansionInputStream(String fileName) throws IOException {
         // Get a ZipResourceFile representing a merger of both the main and patch files
         // Get a ZipResourceFile representing a merger of both the main and patch files
         if (expansionFile == null) {
         if (expansionFile == null) {
             String mainHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION");
             String mainHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION");
@@ -627,11 +833,11 @@ public class SDLActivity {
                 // To avoid direct dependency on Google APK expansion library that is
                 // To avoid direct dependency on Google APK expansion library that is
                 // not a part of Android SDK we access it using reflection
                 // not a part of Android SDK we access it using reflection
                 expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
                 expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
-                        .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
-                        .invoke(null, mSingleton, mainVersion, patchVersion);
+                    .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
+                    .invoke(null, this, mainVersion, patchVersion);
 
 
                 expansionFileMethod = expansionFile.getClass()
                 expansionFileMethod = expansionFile.getClass()
-                        .getMethod("getInputStream", String.class);
+                    .getMethod("getInputStream", String.class);
             } catch (Exception ex) {
             } catch (Exception ex) {
                 ex.printStackTrace();
                 ex.printStackTrace();
                 expansionFile = null;
                 expansionFile = null;
@@ -661,7 +867,7 @@ public class SDLActivity {
     // Messagebox
     // Messagebox
 
 
     /** Result of current messagebox. Also used for blocking the calling thread. */
     /** Result of current messagebox. Also used for blocking the calling thread. */
-    protected final int[] messageboxSelection = new int[1];
+    static protected final int[] messageboxSelection = new int[1];
 
 
     /** Id of current dialog. */
     /** Id of current dialog. */
     protected int dialogs = 0;
     protected int dialogs = 0;
@@ -729,7 +935,7 @@ public class SDLActivity {
         return messageboxSelection[0];
         return messageboxSelection[0];
     }
     }
 
 
-    protected Dialog onCreateDialog(int ignore, Bundle args) {
+    public static Dialog onCreateDialog(int ignore, Bundle args) {
 
 
         // TODO set values from "flags" to messagebox dialog
         // TODO set values from "flags" to messagebox dialog
 
 
@@ -864,16 +1070,16 @@ public class SDLActivity {
 }
 }
 
 
 /**
 /**
- Simple nativeInit() runnable
- */
+    Simple nativeInit() runnable
+*/
 class SDLMain implements Runnable {
 class SDLMain implements Runnable {
     @Override
     @Override
     public void run() {
     public void run() {
         // Runs SDL_main()
         // Runs SDL_main()
         // Urho3D: pass filesDir
         // Urho3D: pass filesDir
-        String path = ((Activity)SDLActivity.getContext()).getFilesDir().getAbsolutePath();
-        Log.v("SDLMain", "Init with path: " + path);
-        SDLActivity.nativeInit(new String[]{"app_process"}, path);
+        SDLActivity.nativeInit(SDLActivity.getArguments(), ((Activity)SDLActivity.getContext()).getFilesDir().getAbsolutePath());
+
+        //Log.v("SDL", "SDL thread terminated");
     }
     }
 }
 }
 
 
@@ -917,7 +1123,7 @@ class DummyEdit extends View implements View.OnKeyListener {
         // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
         // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
         // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
         // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
         // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
         // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
-        // FIXME: A more effective solution would be to change our Layout from AbsoluteLayout to Relative or Linear
+        // FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
         // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
         // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
         // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
         // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
         if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
         if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
@@ -956,7 +1162,7 @@ class SDLInputConnection extends BaseInputConnection {
          */
          */
         int keyCode = event.getKeyCode();
         int keyCode = event.getKeyCode();
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            if (event.isPrintingKey()) {
+            if (event.isPrintingKey() || keyCode == KeyEvent.KEYCODE_SPACE) {
                 commitText(String.valueOf((char) event.getUnicodeChar()), 1);
                 commitText(String.valueOf((char) event.getUnicodeChar()), 1);
             }
             }
             SDLActivity.onNativeKeyDown(keyCode);
             SDLActivity.onNativeKeyDown(keyCode);
@@ -995,7 +1201,7 @@ class SDLInputConnection extends BaseInputConnection {
         if (beforeLength == 1 && afterLength == 0) {
         if (beforeLength == 1 && afterLength == 0) {
             // backspace
             // backspace
             return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
             return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
-                    && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
+                && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
         }
         }
 
 
         return super.deleteSurroundingText(beforeLength, afterLength);
         return super.deleteSurroundingText(beforeLength, afterLength);
@@ -1057,9 +1263,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
             if (joystick == null) {
             if (joystick == null) {
                 joystick = new SDLJoystick();
                 joystick = new SDLJoystick();
                 InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
                 InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
-
-                // Urho3D - revert back commit 34a0b0478654e8dfaf111aecc0e4535875c4ec87 as it does more harm than good
-                if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+                if (SDLActivity.isDeviceSDLJoystick(deviceIds[i])) {
                     joystick.device_id = deviceIds[i];
                     joystick.device_id = deviceIds[i];
                     joystick.name = joystickDevice.getName();
                     joystick.name = joystickDevice.getName();
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
@@ -1068,9 +1272,9 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     Collections.sort(ranges, new RangeComparator());
                     Collections.sort(ranges, new RangeComparator());
                     for (InputDevice.MotionRange range : ranges ) {
                     for (InputDevice.MotionRange range : ranges ) {
-                        if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) {
+                        if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
                             if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
                             if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
-                                    range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+                                range.getAxis() == MotionEvent.AXIS_HAT_Y) {
                                 joystick.hats.add(range);
                                 joystick.hats.add(range);
                             }
                             }
                             else {
                             else {
@@ -1081,7 +1285,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
 
 
                     mJoysticks.add(joystick);
                     mJoysticks.add(joystick);
                     SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1,
                     SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1,
-                            joystick.axes.size(), joystick.hats.size()/2, 0);
+                                                  joystick.axes.size(), joystick.hats.size()/2, 0);
                 }
                 }
             }
             }
         }
         }
@@ -1122,7 +1326,7 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler {
 
 
     @Override
     @Override
     public boolean handleMotionEvent(MotionEvent event) {
     public boolean handleMotionEvent(MotionEvent event) {
-        if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
+        if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
             int actionPointerIndex = event.getActionIndex();
             int actionPointerIndex = event.getActionIndex();
             int action = event.getActionMasked();
             int action = event.getActionMasked();
             switch(action) {
             switch(action) {
@@ -1161,8 +1365,7 @@ class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
             case InputDevice.SOURCE_JOYSTICK:
             case InputDevice.SOURCE_JOYSTICK:
             case InputDevice.SOURCE_GAMEPAD:
             case InputDevice.SOURCE_GAMEPAD:
             case InputDevice.SOURCE_DPAD:
             case InputDevice.SOURCE_DPAD:
-                SDLActivity.handleJoystickMotionEvent(event);
-                return true;
+                return SDLActivity.handleJoystickMotionEvent(event);
 
 
             case InputDevice.SOURCE_MOUSE:
             case InputDevice.SOURCE_MOUSE:
                 action = event.getActionMasked();
                 action = event.getActionMasked();

+ 87 - 74
Script/AtomicNET/Platform/Android/JavaSDL/src/main/java/org/libsdl/app/SDLSurface.java

@@ -20,13 +20,13 @@ import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager;
 
 
 /**
 /**
- SDLSurface. This is what we draw on, so we need to know when it's created
- in order to do anything useful.
+    SDLSurface. This is what we draw on, so we need to know when it's created
+    in order to do anything useful.
 
 
- Because of this, that's where we set up the SDL thread
- */
+    Because of this, that's where we set up the SDL thread
+*/
 public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
 public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
-        View.OnKeyListener, View.OnTouchListener, SensorEventListener {
+    View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
 
 
     // Sensors
     // Sensors
     protected static SensorManager mSensorManager;
     protected static SensorManager mSensorManager;
@@ -100,47 +100,47 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
 
 
         int sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565 by default
         int sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565 by default
         switch (format) {
         switch (format) {
-            case PixelFormat.A_8:
-                Log.v("SDL", "pixel format A_8");
-                break;
-            case PixelFormat.LA_88:
-                Log.v("SDL", "pixel format LA_88");
-                break;
-            case PixelFormat.L_8:
-                Log.v("SDL", "pixel format L_8");
-                break;
-            case PixelFormat.RGBA_4444:
-                Log.v("SDL", "pixel format RGBA_4444");
-                sdlFormat = 0x15421002; // SDL_PIXELFORMAT_RGBA4444
-                break;
-            case PixelFormat.RGBA_5551:
-                Log.v("SDL", "pixel format RGBA_5551");
-                sdlFormat = 0x15441002; // SDL_PIXELFORMAT_RGBA5551
-                break;
-            case PixelFormat.RGBA_8888:
-                Log.v("SDL", "pixel format RGBA_8888");
-                sdlFormat = 0x16462004; // SDL_PIXELFORMAT_RGBA8888
-                break;
-            case PixelFormat.RGBX_8888:
-                Log.v("SDL", "pixel format RGBX_8888");
-                sdlFormat = 0x16261804; // SDL_PIXELFORMAT_RGBX8888
-                break;
-            case PixelFormat.RGB_332:
-                Log.v("SDL", "pixel format RGB_332");
-                sdlFormat = 0x14110801; // SDL_PIXELFORMAT_RGB332
-                break;
-            case PixelFormat.RGB_565:
-                Log.v("SDL", "pixel format RGB_565");
-                sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565
-                break;
-            case PixelFormat.RGB_888:
-                Log.v("SDL", "pixel format RGB_888");
-                // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
-                sdlFormat = 0x16161804; // SDL_PIXELFORMAT_RGB888
-                break;
-            default:
-                Log.v("SDL", "pixel format unknown " + format);
-                break;
+        case PixelFormat.A_8:
+            Log.v("SDL", "pixel format A_8");
+            break;
+        case PixelFormat.LA_88:
+            Log.v("SDL", "pixel format LA_88");
+            break;
+        case PixelFormat.L_8:
+            Log.v("SDL", "pixel format L_8");
+            break;
+        case PixelFormat.RGBA_4444:
+            Log.v("SDL", "pixel format RGBA_4444");
+            sdlFormat = 0x15421002; // SDL_PIXELFORMAT_RGBA4444
+            break;
+        case PixelFormat.RGBA_5551:
+            Log.v("SDL", "pixel format RGBA_5551");
+            sdlFormat = 0x15441002; // SDL_PIXELFORMAT_RGBA5551
+            break;
+        case PixelFormat.RGBA_8888:
+            Log.v("SDL", "pixel format RGBA_8888");
+            sdlFormat = 0x16462004; // SDL_PIXELFORMAT_RGBA8888
+            break;
+        case PixelFormat.RGBX_8888:
+            Log.v("SDL", "pixel format RGBX_8888");
+            sdlFormat = 0x16261804; // SDL_PIXELFORMAT_RGBX8888
+            break;
+        case PixelFormat.RGB_332:
+            Log.v("SDL", "pixel format RGB_332");
+            sdlFormat = 0x14110801; // SDL_PIXELFORMAT_RGB332
+            break;
+        case PixelFormat.RGB_565:
+            Log.v("SDL", "pixel format RGB_565");
+            sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565
+            break;
+        case PixelFormat.RGB_888:
+            Log.v("SDL", "pixel format RGB_888");
+            // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
+            sdlFormat = 0x16161804; // SDL_PIXELFORMAT_RGB888
+            break;
+        default:
+            Log.v("SDL", "pixel format unknown " + format);
+            break;
         }
         }
 
 
         mWidth = width;
         mWidth = width;
@@ -159,28 +159,28 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
         else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
         {
         {
             if (mWidth > mHeight) {
             if (mWidth > mHeight) {
-                skip = true;
+               skip = true;
             }
             }
         } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
         } else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
             if (mWidth < mHeight) {
             if (mWidth < mHeight) {
-                skip = true;
+               skip = true;
             }
             }
         }
         }
 
 
         // Special Patch for Square Resolution: Black Berry Passport
         // Special Patch for Square Resolution: Black Berry Passport
         if (skip) {
         if (skip) {
-            double min = Math.min(mWidth, mHeight);
-            double max = Math.max(mWidth, mHeight);
+           double min = Math.min(mWidth, mHeight);
+           double max = Math.max(mWidth, mHeight);
 
 
-            if (max / min < 1.20) {
-                Log.v("SDL", "Don't skip on such aspect-ratio. Could be a square resolution.");
-                skip = false;
-            }
+           if (max / min < 1.20) {
+              Log.v("SDL", "Don't skip on such aspect-ratio. Could be a square resolution.");
+              skip = false;
+           }
         }
         }
 
 
         if (skip) {
         if (skip) {
-            Log.v("SDL", "Skip .. Surface is not ready.");
-            return;
+           Log.v("SDL", "Skip .. Surface is not ready.");
+           return;
         }
         }
 
 
 
 
@@ -208,11 +208,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                     finally{
                     finally{
                         // Native thread has finished
                         // Native thread has finished
                         if (! SDLActivity.mExitCalledFromJava) {
                         if (! SDLActivity.mExitCalledFromJava) {
-                            try {
-                                SDLActivity.handleNativeExit();
-                            } catch (Exception e) {
-                                e.printStackTrace();
-                            }
+                            SDLActivity.handleNativeExit();
                         }
                         }
                     }
                     }
                 }
                 }
@@ -229,11 +225,14 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     @Override
     @Override
     public boolean onKey(View  v, int keyCode, KeyEvent event) {
     public boolean onKey(View  v, int keyCode, KeyEvent event) {
         // Dispatch the different events depending on where they come from
         // Dispatch the different events depending on where they come from
-        // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
-        // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD
-
-        if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 ||
-                (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
+        // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
+        // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
+        //
+        // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
+        // SOURCE_JOYSTICK, while its key events arrive from the keyboard source
+        // So, retrieve the device itself and check all of its sources
+        if (SDLActivity.isDeviceSDLJoystick(event.getDeviceId())) {
+            // Note that we process events with specific key codes here
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
                 if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
                     return true;
                     return true;
@@ -245,7 +244,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
             }
         }
         }
 
 
-        if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
+        if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 //Log.v("SDL", "key down: " + keyCode);
                 //Log.v("SDL", "key down: " + keyCode);
                 SDLActivity.onNativeKeyDown(keyCode);
                 SDLActivity.onNativeKeyDown(keyCode);
@@ -258,6 +257,20 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
             }
         }
         }
 
 
+        if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) {
+            // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
+            // they are ignored here because sending them as mouse input to SDL is messy
+            if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
+                switch (event.getAction()) {
+                case KeyEvent.ACTION_DOWN:
+                case KeyEvent.ACTION_UP:
+                    // mark the event as handled or it will be handled by system
+                    // handling KEYCODE_BACK by system will call onBackPressed()
+                    return true;
+                }
+            }
+        }
+
         return false;
         return false;
     }
     }
 
 
@@ -276,7 +289,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
         // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14.
         if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) {
         if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) {
             if (Build.VERSION.SDK_INT < 14) {
             if (Build.VERSION.SDK_INT < 14) {
-                mouseButton = 1;    // For Android==12 all mouse buttons are the left button
+                mouseButton = 1; // all mouse buttons are the left button
             } else {
             } else {
                 try {
                 try {
                     mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
                     mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
@@ -346,18 +359,18 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         }
         }
 
 
         return true;
         return true;
-    }
+   }
 
 
     // Sensor events
     // Sensor events
     public void enableSensor(int sensortype, boolean enabled) {
     public void enableSensor(int sensortype, boolean enabled) {
         // TODO: This uses getDefaultSensor - what if we have >1 accels?
         // TODO: This uses getDefaultSensor - what if we have >1 accels?
         if (enabled) {
         if (enabled) {
             mSensorManager.registerListener(this,
             mSensorManager.registerListener(this,
-                    mSensorManager.getDefaultSensor(sensortype),
-                    SensorManager.SENSOR_DELAY_GAME, null);
+                            mSensorManager.getDefaultSensor(sensortype),
+                            SensorManager.SENSOR_DELAY_GAME, null);
         } else {
         } else {
             mSensorManager.unregisterListener(this,
             mSensorManager.unregisterListener(this,
-                    mSensorManager.getDefaultSensor(sensortype));
+                            mSensorManager.getDefaultSensor(sensortype));
         }
         }
     }
     }
 
 
@@ -390,8 +403,8 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                     break;
                     break;
             }
             }
             SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
             SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
-                    y / SensorManager.GRAVITY_EARTH,
-                    event.values[2] / SensorManager.GRAVITY_EARTH - 1);
+                                      y / SensorManager.GRAVITY_EARTH,
+                                      event.values[2] / SensorManager.GRAVITY_EARTH);
         }
         }
     }
     }
 }
 }

BIN
Script/AtomicNET/Platform/Android/JavaSDLBin/atomicjavasdl-release.aar


+ 3 - 1
Script/Packages/Atomic/Core.json

@@ -10,7 +10,9 @@
 			"SendEvent" : ["StringHash"]
 			"SendEvent" : ["StringHash"]
 		},
 		},
 		"Context" : {
 		"Context" : {
-			"GetTypeName" : ["StringHash"]
+			"GetTypeName" : ["StringHash"],
+			"RequireIK" : [],
+			"ReleaseIK" : []
 		},
 		},
 		"CSharp" : {
 		"CSharp" : {
 			"Object" : {
 			"Object" : {

+ 1 - 1
Script/Packages/Atomic/IO.json

@@ -2,7 +2,7 @@
 	"name" : "IO",
 	"name" : "IO",
 	"sources" : ["Source/Atomic/IO"],
 	"sources" : ["Source/Atomic/IO"],
 	"classes" : ["Log", "File", "FileSystem", "FileWatcher", "BufferQueue", "PackageFile"],
 	"classes" : ["Log", "File", "FileSystem", "FileWatcher", "BufferQueue", "PackageFile"],
-	"interfaces" : ["Serializer", "Deserializer"],
+	"interfaces" : ["Serializer", "Deserializer", "AbstractFile"],
 	"overloads" : {
 	"overloads" : {
 		"File" : {
 		"File" : {
 			"File" : ["Context", "String", "FileMode"]
 			"File" : ["Context", "String", "FileMode"]

+ 1 - 1
Script/Packages/Atomic/Scene.json

@@ -15,7 +15,7 @@
 	"overloads" : {
 	"overloads" : {
 
 
 		"Node" : {
 		"Node" : {
-			"CreateChild" : ["String", "CreateMode", "unsigned"],
+			"CreateChild" : ["String", "CreateMode", "unsigned", "bool"],
 			"GetChild" : ["String", "bool"],
 			"GetChild" : ["String", "bool"],
 			"SetScale" : ["Vector3"],
 			"SetScale" : ["Vector3"],
 			"SetPosition2D" : ["Vector2"],
 			"SetPosition2D" : ["Vector2"],

+ 3 - 8
Source/Atomic/Atomic2D/AnimatedSprite2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -59,7 +59,6 @@ AnimatedSprite2D::AnimatedSprite2D(Context* context) :
     animationStateData_(0),
     animationStateData_(0),
     animationState_(0),
     animationState_(0),
 #endif
 #endif
-    spriterInstance_(0),
     speed_(1.0f),
     speed_(1.0f),
     loopMode_(LM_DEFAULT)
     loopMode_(LM_DEFAULT)
 {
 {
@@ -452,7 +451,7 @@ void AnimatedSprite2D::UpdateSourceBatchesSpriter()
     Vertex2D vertex3;
     Vertex2D vertex3;
 
 
     const PODVector<Spriter::SpatialTimelineKey*>& timelineKeys = spriterInstance_->GetTimelineKeys();
     const PODVector<Spriter::SpatialTimelineKey*>& timelineKeys = spriterInstance_->GetTimelineKeys();
-    for (size_t i = 0; i < timelineKeys.Size(); ++i)
+    for (unsigned i = 0; i < timelineKeys.Size(); ++i)
     {
     {
         if (timelineKeys[i]->GetObjectType() != Spriter::SPRITE)
         if (timelineKeys[i]->GetObjectType() != Spriter::SPRITE)
             continue;
             continue;
@@ -527,11 +526,7 @@ void AnimatedSprite2D::Dispose()
         skeleton_ = 0;
         skeleton_ = 0;
     }
     }
 #endif
 #endif
-    if (spriterInstance_)
-    {
-        delete spriterInstance_;
-        spriterInstance_ = 0;
-    }
+    spriterInstance_.Reset();
 }
 }
 
 
 }
 }

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

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -143,7 +143,7 @@ protected:
 #endif
 #endif
     
     
     /// Spriter instance.
     /// Spriter instance.
-    Spriter::SpriterInstance* spriterInstance_;
+    UniquePtr<Spriter::SpriterInstance> spriterInstance_;
 };
 };
 
 
 }
 }

+ 7 - 12
Source/Atomic/Atomic2D/AnimationSet2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -110,7 +110,6 @@ AnimationSet2D::AnimationSet2D(Context* context) :
     skeletonData_(0),
     skeletonData_(0),
     atlas_(0),
     atlas_(0),
 #endif
 #endif
-    spriterData_(0),
     hasSpriteSheet_(false)
     hasSpriteSheet_(false)
 {
 {
 }
 }
@@ -194,11 +193,11 @@ bool AnimationSet2D::HasAnimation(const String& animationName) const
                 return true;
                 return true;
         }
         }
     }
     }
-#endif    
+#endif
     if (spriterData_ && !spriterData_->entities_.Empty())
     if (spriterData_ && !spriterData_->entities_.Empty())
     {
     {
         const PODVector<Spriter::Animation*>& animations = spriterData_->entities_[0]->animations_;
         const PODVector<Spriter::Animation*>& animations = spriterData_->entities_[0]->animations_;
-        for (size_t i = 0; i < animations.Size(); ++i)
+        for (unsigned i = 0; i < animations.Size(); ++i)
         {
         {
             if (animationName == animations[i]->name_)
             if (animationName == animations[i]->name_)
                 return true;
                 return true;
@@ -259,7 +258,7 @@ bool AnimationSet2D::EndLoadSpine()
 
 
     if (numAtlasPages > 1)
     if (numAtlasPages > 1)
     {
     {
-        ATOMIC_LOGERROR("Only one page is supported in Urho3D");
+        ATOMIC_LOGERROR("Only one page is supported in Atomic");
         return false;
         return false;
     }
     }
 
 
@@ -322,10 +321,10 @@ bool AnimationSet2D::BeginLoadSpriter(Deserializer& source)
             cache->BackgroundLoadResource<SpriteSheet2D>(spriteSheetFilePath_, true, this);
             cache->BackgroundLoadResource<SpriteSheet2D>(spriteSheetFilePath_, true, this);
         else
         else
         {
         {
-            for (size_t i = 0; i < spriterData_->folders_.Size(); ++i)
+            for (unsigned i = 0; i < spriterData_->folders_.Size(); ++i)
             {
             {
                 Spriter::Folder* folder = spriterData_->folders_[i];
                 Spriter::Folder* folder = spriterData_->folders_[i];
-                for (size_t j = 0; j < folder->files_.Size(); ++j)
+                for (unsigned j = 0; j < folder->files_.Size(); ++j)
                 {
                 {
                     Spriter::File* file = folder->files_[j];
                     Spriter::File* file = folder->files_[j];
                     String imagePath = parentPath + file->name_;
                     String imagePath = parentPath + file->name_;
@@ -525,11 +524,7 @@ void AnimationSet2D::Dispose()
     }
     }
 #endif
 #endif
 
 
-    if (spriterData_)
-    {
-        delete spriterData_;
-        spriterData_ = 0;
-    }
+    spriterData_.Reset();
 
 
     sprite_.Reset();
     sprite_.Reset();
     spriteSheet_.Reset();
     spriteSheet_.Reset();

+ 3 - 3
Source/Atomic/Atomic2D/AnimationSet2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -76,7 +76,7 @@ public:
 #endif
 #endif
 
 
     /// Return spriter data.
     /// Return spriter data.
-    Spriter::SpriterData* GetSpriterData() const { return spriterData_; }
+    Spriter::SpriterData* GetSpriterData() const { return spriterData_.Get(); }
     /// Return spriter file sprite.
     /// Return spriter file sprite.
     Sprite2D* GetSpriterFileSprite(int folderId, int fileId) const;
     Sprite2D* GetSpriterFileSprite(int folderId, int fileId) const;
 
 
@@ -109,7 +109,7 @@ private:
 #endif
 #endif
     
     
     /// Spriter data.
     /// Spriter data.
-    Spriter::SpriterData* spriterData_;
+    UniquePtr<Spriter::SpriterData> spriterData_;
     /// Has sprite sheet.
     /// Has sprite sheet.
     bool hasSpriteSheet_;
     bool hasSpriteSheet_;
     /// Sprite sheet file path.
     /// Sprite sheet file path.

+ 1 - 1
Source/Atomic/Atomic2D/Atomic2D.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/Atomic2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 44 - 0
Source/Atomic/Atomic2D/Atomic2DEvents.h

@@ -0,0 +1,44 @@
+//
+// Copyright (c) 2008-2017 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "../Core/Object.h"
+
+namespace Atomic
+{
+
+/// Emitting ParticleEmitter2D particles stopped.
+ATOMIC_EVENT(E_PARTICLESEND, ParticlesEnd)
+{
+    ATOMIC_PARAM(P_NODE, Node);                    // Node pointer
+    ATOMIC_PARAM(P_EFFECT, Effect);                // ParticleEffect2D pointer
+}
+
+/// All ParticleEmitter2D particles have been removed.
+ATOMIC_EVENT(E_PARTICLESDURATION, ParticlesDuration)
+{
+    ATOMIC_PARAM(P_NODE, Node);                    // Node pointer
+    ATOMIC_PARAM(P_EFFECT, Effect);                // ParticleEffect2D pointer
+}
+
+}

+ 1 - 1
Source/Atomic/Atomic2D/CollisionBox2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionBox2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionChain2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionChain2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionCircle2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionCircle2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionEdge2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionEdge2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionPolygon2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/CollisionPolygon2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 9 - 1
Source/Atomic/Atomic2D/CollisionShape2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -223,7 +223,11 @@ void CollisionShape2D::CreateFixture()
     // Chain shape must have atleast two vertices before creating fixture
     // Chain shape must have atleast two vertices before creating fixture
     if (fixtureDef_.shape->m_type != b2Shape::e_chain || static_cast<const b2ChainShape*>(fixtureDef_.shape)->m_count >= 2)
     if (fixtureDef_.shape->m_type != b2Shape::e_chain || static_cast<const b2ChainShape*>(fixtureDef_.shape)->m_count >= 2)
     {
     {
+        b2MassData massData;
+        body->GetMassData(&massData);
         fixture_ = body->CreateFixture(&fixtureDef_);
         fixture_ = body->CreateFixture(&fixtureDef_);
+        if (!rigidBody_->GetUseFixtureMass()) // Workaround for resetting mass in CreateFixture().
+            body->SetMassData(&massData);
         fixture_->SetUserData(this);
         fixture_->SetUserData(this);
     }
     }
 }
 }
@@ -240,7 +244,11 @@ void CollisionShape2D::ReleaseFixture()
     if (!body)
     if (!body)
         return;
         return;
 
 
+    b2MassData massData;
+    body->GetMassData(&massData);
     body->DestroyFixture(fixture_);
     body->DestroyFixture(fixture_);
+    if (!rigidBody_->GetUseFixtureMass()) // Workaround for resetting mass in DestroyFixture().
+        body->SetMassData(&massData);
     fixture_ = 0;
     fixture_ = 0;
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/CollisionShape2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 36 - 3
Source/Atomic/Atomic2D/Constraint2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,8 @@ extern const char* ATOMIC2D_CATEGORY;
 Constraint2D::Constraint2D(Context* context) :
 Constraint2D::Constraint2D(Context* context) :
     Component(context),
     Component(context),
     joint_(0),
     joint_(0),
-    collideConnected_(false)
+    collideConnected_(false),
+    otherBodyNodeIDDirty_(false)
 {
 {
 
 
 }
 }
@@ -54,6 +55,31 @@ Constraint2D::~Constraint2D()
 void Constraint2D::RegisterObject(Context* context)
 void Constraint2D::RegisterObject(Context* context)
 {
 {
     ATOMIC_ACCESSOR_ATTRIBUTE("Collide Connected", GetCollideConnected, SetCollideConnected, bool, false, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Collide Connected", GetCollideConnected, SetCollideConnected, bool, false, AM_DEFAULT);
+    ATOMIC_ATTRIBUTE("Other Body NodeID", unsigned, otherBodyNodeID_, 0, AM_DEFAULT | AM_NODEID);
+}
+
+void Constraint2D::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+
+    if (!attr.accessor_ && attr.offset_ == offsetof(Constraint2D, otherBodyNodeID_))
+        otherBodyNodeIDDirty_ = true;
+}
+
+void Constraint2D::ApplyAttributes()
+{
+    // If other body node ID dirty, try to find it now and apply
+    if (otherBodyNodeIDDirty_)
+    {
+        Scene* scene = GetScene();
+        if (scene)
+        {
+            Node* otherNode = scene->GetNode(otherBodyNodeID_);
+            if (otherNode)
+                SetOtherBody(otherNode->GetComponent<RigidBody2D>());
+        }
+        otherBodyNodeIDDirty_ = false;
+    }
 }
 }
 
 
 void Constraint2D::OnSetEnabled()
 void Constraint2D::OnSetEnabled()
@@ -107,6 +133,9 @@ void Constraint2D::SetOtherBody(RigidBody2D* body)
 
 
     otherBody_ = body;
     otherBody_ = body;
 
 
+    Node* otherNode = body ? body->GetNode() : (Node*)0;
+    otherBodyNodeID_ = otherNode ? otherNode->GetID() : 0;
+
     RecreateJoint();
     RecreateJoint();
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
@@ -145,7 +174,11 @@ void Constraint2D::OnNodeSet(Node* node)
 void Constraint2D::OnSceneSet(Scene* scene)
 void Constraint2D::OnSceneSet(Scene* scene)
 {
 {
     if (scene)
     if (scene)
-        physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld2D>();
+    {
+        physicsWorld_ = scene->GetDerivedComponent<PhysicsWorld2D>();
+        if (!physicsWorld_)
+            physicsWorld_ = scene->CreateComponent<PhysicsWorld2D>();
+    }
 }
 }
 
 
 void Constraint2D::InitializeJointDef(b2JointDef* jointDef)
 void Constraint2D::InitializeJointDef(b2JointDef* jointDef)

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

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -45,6 +45,10 @@ public:
     /// Register object factory.
     /// Register object factory.
     static void RegisterObject(Context* context);
     static void RegisterObject(Context* context);
 
 
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
+    /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
+    virtual void ApplyAttributes();
     /// Handle enabled/disabled state change.
     /// Handle enabled/disabled state change.
     virtual void OnSetEnabled();
     virtual void OnSetEnabled();
     /// Create joint.
     /// Create joint.
@@ -94,8 +98,12 @@ protected:
     WeakPtr<RigidBody2D> ownerBody_;
     WeakPtr<RigidBody2D> ownerBody_;
     /// Other body.
     /// Other body.
     WeakPtr<RigidBody2D> otherBody_;
     WeakPtr<RigidBody2D> otherBody_;
-    /// Collide connected.
+    /// Other body node ID for serialization.
+    unsigned otherBodyNodeID_;
+    /// Collide connected flag.
     bool collideConnected_;
     bool collideConnected_;
+    /// Other body node ID dirty flag.
+    bool otherBodyNodeIDDirty_;
     /// Attached constraint.
     /// Attached constraint.
     WeakPtr<Constraint2D> attachedConstraint_;
     WeakPtr<Constraint2D> attachedConstraint_;
 };
 };

+ 27 - 3
Source/Atomic/Atomic2D/ConstraintDistance2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -55,6 +55,7 @@ void ConstraintDistance2D::RegisterObject(Context* context)
     ATOMIC_ACCESSOR_ATTRIBUTE("Other Body Anchor", GetOtherBodyAnchor, SetOtherBodyAnchor, Vector2, Vector2::ZERO, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Other Body Anchor", GetOtherBodyAnchor, SetOtherBodyAnchor, Vector2, Vector2::ZERO, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Frequency Hz", GetFrequencyHz, SetFrequencyHz, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Frequency Hz", GetFrequencyHz, SetFrequencyHz, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Damping Ratio", GetDampingRatio, SetDampingRatio, float, 0.0f, AM_DEFAULT);
     ATOMIC_ACCESSOR_ATTRIBUTE("Damping Ratio", GetDampingRatio, SetDampingRatio, float, 0.0f, AM_DEFAULT);
+    ATOMIC_ACCESSOR_ATTRIBUTE("Length", GetLength, SetLength, float, 1.0f, AM_DEFAULT);
     ATOMIC_COPY_BASE_ATTRIBUTES(Constraint2D);
     ATOMIC_COPY_BASE_ATTRIBUTES(Constraint2D);
 }
 }
 
 
@@ -87,7 +88,11 @@ void ConstraintDistance2D::SetFrequencyHz(float frequencyHz)
 
 
     jointDef_.frequencyHz = frequencyHz;
     jointDef_.frequencyHz = frequencyHz;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2DistanceJoint*>(joint_)->SetFrequency(frequencyHz);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -98,7 +103,26 @@ void ConstraintDistance2D::SetDampingRatio(float dampingRatio)
 
 
     jointDef_.dampingRatio = dampingRatio;
     jointDef_.dampingRatio = dampingRatio;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2DistanceJoint*>(joint_)->SetDampingRatio(dampingRatio);
+    else
+        RecreateJoint();
+
+    MarkNetworkUpdate();
+}
+
+void ConstraintDistance2D::SetLength(float length)
+{
+    if (length == jointDef_.length)
+        return;
+
+    jointDef_.length = length;
+
+    if (joint_)
+        static_cast<b2DistanceJoint*>(joint_)->SetLength(length);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 6 - 1
Source/Atomic/Atomic2D/ConstraintDistance2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -48,6 +48,8 @@ public:
     void SetFrequencyHz(float frequencyHz);
     void SetFrequencyHz(float frequencyHz);
     /// Set damping ratio.
     /// Set damping ratio.
     void SetDampingRatio(float dampingRatio);
     void SetDampingRatio(float dampingRatio);
+    /// Set length.
+    void SetLength(float length);
 
 
     /// Return owner body anchor.
     /// Return owner body anchor.
     const Vector2& GetOwnerBodyAnchor() const { return ownerBodyAnchor_; }
     const Vector2& GetOwnerBodyAnchor() const { return ownerBodyAnchor_; }
@@ -61,6 +63,9 @@ public:
     /// Return damping ratio.
     /// Return damping ratio.
     float GetDampingRatio() const { return jointDef_.dampingRatio; }
     float GetDampingRatio() const { return jointDef_.dampingRatio; }
 
 
+    /// Return length.
+    float GetLength() const { return jointDef_.length; }
+
 private:
 private:
     /// Return joint def.
     /// Return joint def.
     virtual b2JointDef* GetJointDef();
     virtual b2JointDef* GetJointDef();

+ 11 - 3
Source/Atomic/Atomic2D/ConstraintFriction2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -74,7 +74,11 @@ void ConstraintFriction2D::SetMaxForce(float maxForce)
 
 
     jointDef_.maxForce = maxForce;
     jointDef_.maxForce = maxForce;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2FrictionJoint*>(joint_)->SetMaxForce(maxForce);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -86,7 +90,11 @@ void ConstraintFriction2D::SetMaxTorque(float maxTorque)
 
 
     jointDef_.maxTorque = maxTorque;
     jointDef_.maxTorque = maxTorque;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2FrictionJoint*>(joint_)->SetMaxTorque(maxTorque);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintFriction2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 6 - 2
Source/Atomic/Atomic2D/ConstraintGear2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -94,7 +94,11 @@ void ConstraintGear2D::SetRatio(float ratio)
 
 
     jointDef_.ratio = ratio;
     jointDef_.ratio = ratio;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2GearJoint*>(joint_)->SetRatio(ratio);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintGear2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 26 - 6
Source/Atomic/Atomic2D/ConstraintMotor2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -65,7 +65,11 @@ void ConstraintMotor2D::SetLinearOffset(const Vector2& linearOffset)
 
 
     linearOffset_ = linearOffset;
     linearOffset_ = linearOffset;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MotorJoint*>(joint_)->SetLinearOffset(ToB2Vec2(linearOffset));
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -76,7 +80,11 @@ void ConstraintMotor2D::SetAngularOffset(float angularOffset)
 
 
     jointDef_.angularOffset = angularOffset;
     jointDef_.angularOffset = angularOffset;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MotorJoint*>(joint_)->SetAngularOffset(angularOffset);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -87,7 +95,11 @@ void ConstraintMotor2D::SetMaxForce(float maxForce)
 
 
     jointDef_.maxForce = maxForce;
     jointDef_.maxForce = maxForce;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MotorJoint*>(joint_)->SetMaxForce(maxForce);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -98,7 +110,11 @@ void ConstraintMotor2D::SetMaxTorque(float maxTorque)
 
 
     jointDef_.maxTorque = maxTorque;
     jointDef_.maxTorque = maxTorque;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MotorJoint*>(joint_)->SetMaxTorque(maxTorque);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -109,7 +125,11 @@ void ConstraintMotor2D::SetCorrectionFactor(float correctionFactor)
 
 
     jointDef_.correctionFactor = correctionFactor;
     jointDef_.correctionFactor = correctionFactor;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MotorJoint*>(joint_)->SetCorrectionFactor(correctionFactor);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintMotor2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 21 - 16
Source/Atomic/Atomic2D/ConstraintMouse2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -36,8 +36,7 @@ extern const char* ATOMIC2D_CATEGORY;
 
 
 ConstraintMouse2D::ConstraintMouse2D(Context* context) :
 ConstraintMouse2D::ConstraintMouse2D(Context* context) :
     Constraint2D(context),
     Constraint2D(context),
-    target_(Vector2::ZERO),
-    targetSetted_(false)
+    target_(Vector2::ZERO)
 {
 {
 }
 }
 
 
@@ -63,18 +62,12 @@ void ConstraintMouse2D::SetTarget(const Vector2& target)
         return;
         return;
 
 
     target_ = target;
     target_ = target;
-    if (joint_ && targetSetted_)
-    {
-        b2MouseJoint* mouseJoint = (b2MouseJoint*)joint_;
-        mouseJoint->SetTarget(ToB2Vec2(target_));
 
 
-        MarkNetworkUpdate();
-        return;
-    }
-
-    targetSetted_ = true;
+    if (joint_)
+        static_cast<b2MouseJoint*>(joint_)->SetTarget(ToB2Vec2(target));
+    else
+        RecreateJoint();
 
 
-    RecreateJoint();
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -85,7 +78,11 @@ void ConstraintMouse2D::SetMaxForce(float maxForce)
 
 
     jointDef_.maxForce = maxForce;
     jointDef_.maxForce = maxForce;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MouseJoint*>(joint_)->SetMaxForce(maxForce);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -96,7 +93,11 @@ void ConstraintMouse2D::SetFrequencyHz(float frequencyHz)
 
 
     jointDef_.frequencyHz = frequencyHz;
     jointDef_.frequencyHz = frequencyHz;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MouseJoint*>(joint_)->SetFrequency(frequencyHz);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -107,7 +108,11 @@ void ConstraintMouse2D::SetDampingRatio(float dampingRatio)
 
 
     jointDef_.dampingRatio = dampingRatio;
     jointDef_.dampingRatio = dampingRatio;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2MouseJoint*>(joint_)->SetDampingRatio(dampingRatio);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 3
Source/Atomic/Atomic2D/ConstraintMouse2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -69,8 +69,6 @@ private:
     b2MouseJointDef jointDef_;
     b2MouseJointDef jointDef_;
     /// Target.
     /// Target.
     Vector2 target_;
     Vector2 target_;
-    /// Target setted.
-    bool targetSetted_;
 };
 };
 
 
 }
 }

+ 31 - 7
Source/Atomic/Atomic2D/ConstraintPrismatic2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -90,7 +90,11 @@ void ConstraintPrismatic2D::SetEnableLimit(bool enableLimit)
 
 
     jointDef_.enableLimit = enableLimit;
     jointDef_.enableLimit = enableLimit;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2PrismaticJoint*>(joint_)->EnableLimit(enableLimit);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -101,7 +105,11 @@ void ConstraintPrismatic2D::SetLowerTranslation(float lowerTranslation)
 
 
     jointDef_.lowerTranslation = lowerTranslation;
     jointDef_.lowerTranslation = lowerTranslation;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2PrismaticJoint*>(joint_)->SetLimits(lowerTranslation, jointDef_.upperTranslation);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -112,7 +120,11 @@ void ConstraintPrismatic2D::SetUpperTranslation(float upperTranslation)
 
 
     jointDef_.upperTranslation = upperTranslation;
     jointDef_.upperTranslation = upperTranslation;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2PrismaticJoint*>(joint_)->SetLimits(jointDef_.lowerTranslation, upperTranslation);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -123,7 +135,11 @@ void ConstraintPrismatic2D::SetEnableMotor(bool enableMotor)
 
 
     jointDef_.enableMotor = enableMotor;
     jointDef_.enableMotor = enableMotor;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2PrismaticJoint*>(joint_)->EnableMotor(enableMotor);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -134,7 +150,11 @@ void ConstraintPrismatic2D::SetMaxMotorForce(float maxMotorForce)
 
 
     jointDef_.maxMotorForce = maxMotorForce;
     jointDef_.maxMotorForce = maxMotorForce;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2PrismaticJoint*>(joint_)->SetMaxMotorForce(maxMotorForce);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -145,7 +165,11 @@ void ConstraintPrismatic2D::SetMotorSpeed(float motorSpeed)
 
 
     jointDef_.motorSpeed = motorSpeed;
     jointDef_.motorSpeed = motorSpeed;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2PrismaticJoint*>(joint_)->SetMotorSpeed(motorSpeed);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintPrismatic2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintPulley2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintPulley2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 31 - 7
Source/Atomic/Atomic2D/ConstraintRevolute2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -77,7 +77,11 @@ void ConstraintRevolute2D::SetEnableLimit(bool enableLimit)
 
 
     jointDef_.enableLimit = enableLimit;
     jointDef_.enableLimit = enableLimit;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RevoluteJoint*>(joint_)->EnableLimit(enableLimit);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -88,7 +92,11 @@ void ConstraintRevolute2D::SetLowerAngle(float lowerAngle)
 
 
     jointDef_.lowerAngle = lowerAngle;
     jointDef_.lowerAngle = lowerAngle;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RevoluteJoint*>(joint_)->SetLimits(lowerAngle, jointDef_.upperAngle);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -99,7 +107,11 @@ void ConstraintRevolute2D::SetUpperAngle(float upperAngle)
 
 
     jointDef_.upperAngle = upperAngle;
     jointDef_.upperAngle = upperAngle;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RevoluteJoint*>(joint_)->SetLimits(jointDef_.lowerAngle, upperAngle);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -110,7 +122,11 @@ void ConstraintRevolute2D::SetEnableMotor(bool enableMotor)
 
 
     jointDef_.enableMotor = enableMotor;
     jointDef_.enableMotor = enableMotor;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RevoluteJoint*>(joint_)->EnableMotor(enableMotor);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -121,7 +137,11 @@ void ConstraintRevolute2D::SetMotorSpeed(float motorSpeed)
 
 
     jointDef_.motorSpeed = motorSpeed;
     jointDef_.motorSpeed = motorSpeed;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RevoluteJoint*>(joint_)->SetMotorSpeed(motorSpeed);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -132,7 +152,11 @@ void ConstraintRevolute2D::SetMaxMotorTorque(float maxMotorTorque)
 
 
     jointDef_.maxMotorTorque = maxMotorTorque;
     jointDef_.maxMotorTorque = maxMotorTorque;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RevoluteJoint*>(joint_)->SetMaxMotorTorque(maxMotorTorque);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintRevolute2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 6 - 2
Source/Atomic/Atomic2D/ConstraintRope2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -87,7 +87,11 @@ void ConstraintRope2D::SetMaxLength(float maxLength)
 
 
     jointDef_.maxLength = maxLength;
     jointDef_.maxLength = maxLength;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2RopeJoint*>(joint_)->SetMaxLength(maxLength);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintRope2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

+ 11 - 3
Source/Atomic/Atomic2D/ConstraintWeld2D.cpp

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal
@@ -73,7 +73,11 @@ void ConstraintWeld2D::SetFrequencyHz(float frequencyHz)
 
 
     jointDef_.frequencyHz = frequencyHz;
     jointDef_.frequencyHz = frequencyHz;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2WeldJoint*>(joint_)->SetFrequency(frequencyHz);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
@@ -84,7 +88,11 @@ void ConstraintWeld2D::SetDampingRatio(float dampingRatio)
 
 
     jointDef_.dampingRatio = dampingRatio;
     jointDef_.dampingRatio = dampingRatio;
 
 
-    RecreateJoint();
+    if (joint_)
+        static_cast<b2WeldJoint*>(joint_)->SetDampingRatio(dampingRatio);
+    else
+        RecreateJoint();
+
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 

+ 1 - 1
Source/Atomic/Atomic2D/ConstraintWeld2D.h

@@ -1,5 +1,5 @@
 //
 //
-// Copyright (c) 2008-2016 the Urho3D project.
+// Copyright (c) 2008-2017 the Urho3D project.
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
 // of this software and associated documentation files (the "Software"), to deal

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