Browse Source

Initial Commit

Josh Engebretson 11 years ago
commit
21f6885fcc
100 changed files with 8194 additions and 0 deletions
  1. 27 0
      Android/AndroidManifest.xml
  2. 7 0
      Android/CopyData.bat
  3. 3 0
      Android/assets/.gitignore
  4. 83 0
      Android/build.xml
  5. BIN
      Android/res/drawable-hdpi/icon.png
  6. BIN
      Android/res/drawable-ldpi/icon.png
  7. BIN
      Android/res/drawable-mdpi/icon.png
  8. BIN
      Android/res/drawable/logo_large.png
  9. 25 0
      Android/res/layout/samples_list.xml
  10. 11 0
      Android/res/layout/samples_list_text_view.xml
  11. 4 0
      Android/res/values/strings.xml
  12. 94 0
      Android/src/com/github/atomic/Atomic.java
  13. 78 0
      Android/src/com/github/atomic/SampleLauncher.java
  14. 1112 0
      Android/src/org/libsdl/app/SDLActivity.java
  15. 115 0
      Bin/CoreData/AtomicModules/AtomicGame.js
  16. 5 0
      Bin/CoreData/Materials/DefaultGrey.xml
  17. 23 0
      Bin/CoreData/RenderPaths/Deferred.xml
  18. 22 0
      Bin/CoreData/RenderPaths/DeferredHWDepth.xml
  19. 11 0
      Bin/CoreData/RenderPaths/Forward.xml
  20. 14 0
      Bin/CoreData/RenderPaths/ForwardDepth.xml
  21. 14 0
      Bin/CoreData/RenderPaths/ForwardHWDepth.xml
  22. 24 0
      Bin/CoreData/RenderPaths/Prepass.xml
  23. 3 0
      Bin/CoreData/RenderPaths/PrepassHDR.xml
  24. 21 0
      Bin/CoreData/RenderPaths/PrepassHWDepth.xml
  25. 23 0
      Bin/CoreData/Shaders/GLSL/Atomic2D.glsl
  26. 73 0
      Bin/CoreData/Shaders/GLSL/AutoExposure.glsl
  27. 49 0
      Bin/CoreData/Shaders/GLSL/Basic.glsl
  28. 57 0
      Bin/CoreData/Shaders/GLSL/Bloom.glsl
  29. 73 0
      Bin/CoreData/Shaders/GLSL/BloomHDR.glsl
  30. 43 0
      Bin/CoreData/Shaders/GLSL/Blur.glsl
  31. 21 0
      Bin/CoreData/Shaders/GLSL/ColorCorrection.glsl
  32. 20 0
      Bin/CoreData/Shaders/GLSL/CopyFramebuffer.glsl
  33. 96 0
      Bin/CoreData/Shaders/GLSL/DeferredLight.glsl
  34. 24 0
      Bin/CoreData/Shaders/GLSL/Depth.glsl
  35. 88 0
      Bin/CoreData/Shaders/GLSL/FXAA2.glsl
  36. 734 0
      Bin/CoreData/Shaders/GLSL/FXAA3.glsl
  37. 24 0
      Bin/CoreData/Shaders/GLSL/Fog.glsl
  38. 21 0
      Bin/CoreData/Shaders/GLSL/GammaCorrection.glsl
  39. 22 0
      Bin/CoreData/Shaders/GLSL/GreyScale.glsl
  40. 22 0
      Bin/CoreData/Shaders/GLSL/Light2D.glsl
  41. 262 0
      Bin/CoreData/Shaders/GLSL/Lighting.glsl
  42. 120 0
      Bin/CoreData/Shaders/GLSL/LitParticle.glsl
  43. 232 0
      Bin/CoreData/Shaders/GLSL/LitSolid.glsl
  44. 87 0
      Bin/CoreData/Shaders/GLSL/PostProcess.glsl
  45. 94 0
      Bin/CoreData/Shaders/GLSL/PrepassLight.glsl
  46. 20 0
      Bin/CoreData/Shaders/GLSL/ProcSky.glsl
  47. 61 0
      Bin/CoreData/Shaders/GLSL/Samplers.glsl
  48. 51 0
      Bin/CoreData/Shaders/GLSL/ScreenPos.glsl
  49. 24 0
      Bin/CoreData/Shaders/GLSL/Shadow.glsl
  50. 26 0
      Bin/CoreData/Shaders/GLSL/Shadow2D.glsl
  51. 25 0
      Bin/CoreData/Shaders/GLSL/Skybox.glsl
  52. 15 0
      Bin/CoreData/Shaders/GLSL/Stencil.glsl
  53. 181 0
      Bin/CoreData/Shaders/GLSL/TerrainBlend.glsl
  54. 59 0
      Bin/CoreData/Shaders/GLSL/Text.glsl
  55. 40 0
      Bin/CoreData/Shaders/GLSL/Tonemap.glsl
  56. 124 0
      Bin/CoreData/Shaders/GLSL/Transform.glsl
  57. 67 0
      Bin/CoreData/Shaders/GLSL/Uniforms.glsl
  58. 62 0
      Bin/CoreData/Shaders/GLSL/Unlit.glsl
  59. 104 0
      Bin/CoreData/Shaders/GLSL/Vegetation.glsl
  60. 24 0
      Bin/CoreData/Shaders/GLSL/VegetationDepth.glsl
  61. 24 0
      Bin/CoreData/Shaders/GLSL/VegetationShadow.glsl
  62. 59 0
      Bin/CoreData/Shaders/GLSL/Water.glsl
  63. 27 0
      Bin/CoreData/Shaders/HLSL/Atomic2D.hlsl
  64. 95 0
      Bin/CoreData/Shaders/HLSL/AutoExposure.hlsl
  65. 70 0
      Bin/CoreData/Shaders/HLSL/Basic.hlsl
  66. 69 0
      Bin/CoreData/Shaders/HLSL/Bloom.hlsl
  67. 111 0
      Bin/CoreData/Shaders/HLSL/BloomHDR.hlsl
  68. 44 0
      Bin/CoreData/Shaders/HLSL/Blur.hlsl
  69. 22 0
      Bin/CoreData/Shaders/HLSL/ColorCorrection.hlsl
  70. 20 0
      Bin/CoreData/Shaders/HLSL/CopyFramebuffer.hlsl
  71. 102 0
      Bin/CoreData/Shaders/HLSL/DeferredLight.hlsl
  72. 34 0
      Bin/CoreData/Shaders/HLSL/Depth.hlsl
  73. 86 0
      Bin/CoreData/Shaders/HLSL/FXAA2.hlsl
  74. 715 0
      Bin/CoreData/Shaders/HLSL/FXAA3.hlsl
  75. 24 0
      Bin/CoreData/Shaders/HLSL/Fog.hlsl
  76. 22 0
      Bin/CoreData/Shaders/HLSL/GammaCorrection.hlsl
  77. 23 0
      Bin/CoreData/Shaders/HLSL/GreyScale.hlsl
  78. 287 0
      Bin/CoreData/Shaders/HLSL/Lighting.hlsl
  79. 151 0
      Bin/CoreData/Shaders/HLSL/LitParticle.hlsl
  80. 293 0
      Bin/CoreData/Shaders/HLSL/LitSolid.hlsl
  81. 86 0
      Bin/CoreData/Shaders/HLSL/PostProcess.hlsl
  82. 101 0
      Bin/CoreData/Shaders/HLSL/PrepassLight.hlsl
  83. 53 0
      Bin/CoreData/Shaders/HLSL/Samplers.hlsl
  84. 51 0
      Bin/CoreData/Shaders/HLSL/ScreenPos.hlsl
  85. 34 0
      Bin/CoreData/Shaders/HLSL/Shadow.hlsl
  86. 21 0
      Bin/CoreData/Shaders/HLSL/Skybox.hlsl
  87. 15 0
      Bin/CoreData/Shaders/HLSL/Stencil.hlsl
  88. 208 0
      Bin/CoreData/Shaders/HLSL/TerrainBlend.hlsl
  89. 62 0
      Bin/CoreData/Shaders/HLSL/Text.hlsl
  90. 38 0
      Bin/CoreData/Shaders/HLSL/Tonemap.hlsl
  91. 63 0
      Bin/CoreData/Shaders/HLSL/Transform.hlsl
  92. 60 0
      Bin/CoreData/Shaders/HLSL/Uniforms.hlsl
  93. 89 0
      Bin/CoreData/Shaders/HLSL/Unlit.hlsl
  94. 123 0
      Bin/CoreData/Shaders/HLSL/Vegetation.hlsl
  95. 32 0
      Bin/CoreData/Shaders/HLSL/VegetationDepth.hlsl
  96. 32 0
      Bin/CoreData/Shaders/HLSL/VegetationShadow.hlsl
  97. 60 0
      Bin/CoreData/Shaders/HLSL/Water.hlsl
  98. 10 0
      Bin/CoreData/Techniques/Diff.xml
  99. 9 0
      Bin/CoreData/Techniques/DiffAO.xml
  100. 5 0
      Bin/CoreData/Techniques/DiffAOAlpha.xml

+ 27 - 0
Android/AndroidManifest.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.github.urho3d"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-feature android:glEsVersion="0x00020000" />
+    <uses-sdk android:targetSdkVersion="12" android:minSdkVersion="10" />
+    <application android:label="@string/app_name" android:icon="@drawable/icon">
+        <activity
+            android:name=".SampleLauncher"
+            android:configChanges="keyboardHidden|orientation"
+            android:noHistory="true"
+            android:screenOrientation="portrait">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".Atomic"
+                  android:label="@string/app_name"
+                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+                  android:configChanges="keyboardHidden|orientation"
+                  android:screenOrientation="landscape">
+        </activity>
+    </application>
+</manifest>

+ 7 - 0
Android/CopyData.bat

@@ -0,0 +1,7 @@
+:: Only call this when using "Android" as build tree and the host system does not have the capability to create symbolic link
+
+md assets\Data
+xcopy ..\bin\Data\*.* assets\Data /S /E /C /Y
+md assets\CoreData
+xcopy ..\bin\CoreData\*.* assets\CoreData /S /E /C /Y
+rd /S /Q assets\CoreData\Shaders\HLSL

+ 3 - 0
Android/assets/.gitignore

@@ -0,0 +1,3 @@
+# Ignore everything as it just contains symlinks or copied of files (Windows platform without MKLINK)
+*
+!.gitignore

+ 83 - 0
Android/build.xml

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Atomic" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

BIN
Android/res/drawable-hdpi/icon.png


BIN
Android/res/drawable-ldpi/icon.png


BIN
Android/res/drawable-mdpi/icon.png


BIN
Android/res/drawable/logo_large.png


+ 25 - 0
Android/res/layout/samples_list.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ImageView
+        android:id="@+id/imageView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:src="@drawable/logo_large" />
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1" />
+
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="No activities" />
+
+</LinearLayout>

+ 11 - 0
Android/res/layout/samples_list_text_view.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:paddingBottom="14dp"
+    android:paddingTop="14dp"
+    android:paddingLeft="14dp"
+    android:paddingRight="14dp"
+    android:textSize="22sp" />

+ 4 - 0
Android/res/values/strings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Atomic</string>
+</resources>

+ 94 - 0
Android/src/com/github/atomic/Atomic.java

@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2008-2014 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.
+//
+
+package com.github.urho3d;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import org.libsdl.app.SDLActivity;
+
+import android.content.Intent;
+import android.content.res.AssetManager;
+
+public class Atomic extends SDLActivity {
+
+
+    private static AssetManager assetManager;
+    private static native void nativeSetAssetManager(AssetManager amanager);
+
+    @Override
+    protected boolean onLoadLibrary(ArrayList<String> libraryNames) {
+        // Ensure "Atomic" (in case of Atomic shared lib type is used) and "Urho3DPlayer" are being sorted to the top of the list 
+        Collections.sort(libraryNames, new Comparator<String>() {
+            private String sortName(String name) {
+                return name.startsWith("Atomic") ? "00_" + name : name;
+            }
+
+            @Override
+            public int compare(String lhs, String rhs) {
+                return sortName(lhs).compareTo(sortName(rhs));
+            }
+        });
+
+        // Atomic shared library must always be loaded if available, so exclude it from return result and all list operations below 
+        int startIndex = "Atomic".equals(libraryNames.get(0)) ? 1 : 0;
+
+        // Determine the intention
+        Intent intent = getIntent();
+        String pickedLibrary = intent.getStringExtra(SampleLauncher.PICKED_LIBRARY);
+        if (pickedLibrary == null) {
+            // Intention for obtaining library names
+            String[] array = libraryNames.subList(startIndex, libraryNames.size()).toArray(new String[libraryNames.size() - startIndex]);
+            if (array.length > 1) {
+                setResult(RESULT_OK, intent.putExtra(SampleLauncher.LIBRARY_NAMES, array));
+
+                // End Atomic activity lifecycle
+                finish();
+
+                // Return false to indicate no library is being loaded yet
+                return false;
+            } else {
+                // There is only one library available, so cancel the intention for obtaining the library name and by not returning any result
+                // However, since we have already started Atomic activity, let's the activity runs its whole lifecycle by falling through to call the super implementation 
+                setResult(RESULT_CANCELED);
+            }
+        } else {
+            // Intention for loading a picked library name (and remove all others)
+            libraryNames.subList(startIndex, libraryNames.size()).clear();
+            libraryNames.add(pickedLibrary);
+        }
+
+        boolean returnValue =  super.onLoadLibrary(libraryNames);
+
+        if (returnValue)
+        {
+            assetManager = getAssets();
+            nativeSetAssetManager(assetManager);
+
+        }
+
+        return returnValue;
+    }
+
+}

+ 78 - 0
Android/src/com/github/atomic/SampleLauncher.java

@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2008-2014 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.
+//
+
+package com.github.urho3d;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class SampleLauncher extends ListActivity {
+
+    public static final String LIBRARY_NAMES = "libraryNames";
+    public static final String PICKED_LIBRARY = "pickedLibrary";
+    private static final int OBTAINING_LIBNAMES = 1;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Start Atomic activity with the intention for obtaining the library name(s), except when a library is already being picked externally
+        startActivityForResult(new Intent(this, Atomic.class).putExtra(PICKED_LIBRARY, getIntent().getStringExtra(PICKED_LIBRARY)), OBTAINING_LIBNAMES);
+
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+
+        // Prepare a list view for picking the sample library names
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.samples_list_text_view);
+        setContentView(R.layout.samples_list);
+        setListAdapter(adapter);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        // The cancel result code means there are no multiple library names to choose from
+        if (OBTAINING_LIBNAMES != requestCode || RESULT_CANCELED == resultCode)
+            return;
+
+        // Populate the list view with library names as pickable items
+        String[] libraryNames = data.getStringArrayExtra(LIBRARY_NAMES);
+        @SuppressWarnings("unchecked")
+        ArrayAdapter<String> adapter = (ArrayAdapter<String>) getListAdapter();
+        for (final String name : libraryNames)
+            adapter.add(name);
+    }
+
+    @Override
+    protected void onListItemClick(ListView l, View v, int position, long id) {
+        // Start Atomic activity with the intention to load the picked library name
+        @SuppressWarnings("unchecked")
+        ArrayAdapter<String> adapter = (ArrayAdapter<String>) getListAdapter();
+        startActivity(new Intent(this, Atomic.class).putExtra(PICKED_LIBRARY, adapter.getItem(position)));
+    }
+
+}

+ 1112 - 0
Android/src/org/libsdl/app/SDLActivity.java

@@ -0,0 +1,1112 @@
+// Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
+
+package org.libsdl.app;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AbsoluteLayout;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.media.*;
+import android.hardware.*;
+
+
+/**
+    SDL Activity
+*/
+public class SDLActivity extends Activity {
+    private static final String TAG = "SDL";
+
+    // Keep track of the paused state
+    public static boolean mIsPaused, mIsSurfaceReady, mHasFocus;
+    public static boolean mExitCalledFromJava;
+
+    // Main components
+    protected static SDLActivity mSingleton;
+    protected static SDLSurface mSurface;
+    protected static View mTextEdit;
+    protected static ViewGroup mLayout;
+    protected static SDLJoystickHandler mJoystickHandler;
+
+    // This is what SDL runs in. It invokes SDL_main(), eventually
+    protected static Thread mSDLThread;
+    
+    // Audio
+    protected static AudioTrack mAudioTrack;
+
+    // Atomic: flag to load the .so and a new method load them
+    private static boolean mIsSharedLibraryLoaded = false;
+
+    protected boolean onLoadLibrary(ArrayList<String> libraryNames) {
+        for (final String name : libraryNames) {
+            System.loadLibrary(name);
+        }
+        return true;
+    }
+    
+    
+    public static void initialize() {
+        // 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
+        mSingleton = null;
+        mSurface = null;
+        mTextEdit = null;
+        mLayout = null;
+        mJoystickHandler = null;
+        mSDLThread = null;
+        mAudioTrack = null;
+        mExitCalledFromJava = false;
+        mIsPaused = false;
+        mIsSurfaceReady = false;
+        mHasFocus = true;
+    }
+
+    // Setup
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log.v("SDL", "onCreate():" + mSingleton);
+        super.onCreate(savedInstanceState);
+        
+        SDLActivity.initialize();
+        // So we can call stuff from static callbacks
+        mSingleton = this;
+        
+        // Atomic: auto load all the shared libraries available in the library path
+        String libraryPath = getApplicationInfo().nativeLibraryDir;
+        //Log.v(TAG, "library path: " + libraryPath);
+        if (!mIsSharedLibraryLoaded) {
+            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
+                    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");
+                //Log.v(TAG, "library name: " + name);
+                libraryNames.add(name);
+            }
+            if (onLoadLibrary(libraryNames))
+                mIsSharedLibraryLoaded = true;
+        }
+
+        // Set up the surface
+        mSurface = new SDLSurface(getApplication());
+        
+        if(Build.VERSION.SDK_INT >= 12) {
+            mJoystickHandler = new SDLJoystickHandler_API12();
+        }
+        else {
+            mJoystickHandler = new SDLJoystickHandler();
+        }
+
+        mLayout = new AbsoluteLayout(this);
+        mLayout.addView(mSurface);
+
+        setContentView(mLayout);
+    }
+
+    // Events
+    @Override
+    protected void onPause() {
+        Log.v("SDL", "onPause()");
+        super.onPause();
+        SDLActivity.handlePause();
+    }
+
+    @Override
+    protected void onResume() {
+        Log.v("SDL", "onResume()");
+        super.onResume();
+        SDLActivity.handleResume();
+    }
+
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        Log.v("SDL", "onWindowFocusChanged(): " + hasFocus);
+
+        SDLActivity.mHasFocus = hasFocus;
+        if (hasFocus) {
+            SDLActivity.handleResume();
+        }
+    }
+
+    @Override
+    public void onLowMemory() {
+        Log.v("SDL", "onLowMemory()");
+        super.onLowMemory();
+        SDLActivity.nativeLowMemory();
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.v("SDL", "onDestroy()");
+        // Send a quit message to the application
+        SDLActivity.mExitCalledFromJava = true;
+        // Atomic - Send a quit message to the application only when native library has been loaded
+        if (mIsSharedLibraryLoaded)
+            SDLActivity.nativeQuit();
+
+        // Now wait for the SDL thread to quit
+        if (SDLActivity.mSDLThread != null) {
+            try {
+                SDLActivity.mSDLThread.join();
+            } catch(Exception e) {
+                Log.v("SDL", "Problem stopping thread: " + e);
+            }
+            SDLActivity.mSDLThread = null;
+
+            //Log.v("SDL", "Finished waiting for SDL thread");
+        }
+            
+        super.onDestroy();
+        // Reset everything in case the user re opens the app
+        SDLActivity.initialize();
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        int keyCode = event.getKeyCode();
+        // Ignore certain special keys so they're handled by Android
+        // Atomic: also ignore the Home key
+        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 */
+            ) {
+            return false;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    /** Called by onPause or surfaceDestroyed. Even if surfaceDestroyed
+     *  is the first to be called, mIsSurfaceReady should still be set
+     *  to 'true' during the call to onPause (in a usual scenario).
+     */
+    public static void handlePause() {
+        if (!SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) {
+            SDLActivity.mIsPaused = true;
+            SDLActivity.nativePause();
+            mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false);
+        }
+    }
+
+    /** Called by onResume or surfaceCreated. An actual resume should be done only when the surface is ready.
+     * Note: Some Android variants may send multiple surfaceChanged events, so we don't need to resume
+     * every time we get one of those events, only if it comes after surfaceDestroyed
+     */
+    public static void handleResume() {
+        if (SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady && SDLActivity.mHasFocus) {
+            SDLActivity.mIsPaused = false;
+            SDLActivity.nativeResume();
+            mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+        }
+    }
+        
+    /* The native thread has finished */
+    public static void handleNativeExit() {
+        SDLActivity.mSDLThread = null;
+        mSingleton.finish();
+    }
+
+
+    // Messages from the SDLMain thread
+    static final int COMMAND_CHANGE_TITLE = 1;
+    static final int COMMAND_UNUSED = 2;
+    static final int COMMAND_TEXTEDIT_HIDE = 3;
+
+    protected static final int COMMAND_USER = 0x8000;
+
+    /**
+     * 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;
+    }
+
+    /**
+     * A Handler class for Messages from native SDL applications.
+     * It uses current Activities as target (e.g. for the title).
+     * static to prevent implicit references to enclosing object.
+     */
+    protected static class SDLCommandHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            Context context = getContext();
+            if (context == null) {
+                Log.e(TAG, "error handling message, getContext() returned null");
+                return;
+            }
+            switch (msg.arg1) {
+            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) {
+                    mTextEdit.setVisibility(View.GONE);
+
+                    InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
+                }
+                break;
+
+            default:
+                if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
+                    Log.e(TAG, "error handling message, command is " + msg.arg1);
+                }
+            }
+        }
+    }
+
+    // Handler for the messages
+    Handler commandHandler = new SDLCommandHandler();
+
+    // Send a message from the SDLMain thread
+    boolean sendCommand(int command, Object data) {
+        Message msg = commandHandler.obtainMessage();
+        msg.arg1 = command;
+        msg.obj = data;
+        return commandHandler.sendMessage(msg);
+    }
+
+    // C functions we call
+    // Atomic: added parameter
+    public static native void nativeInit(String filesDir);
+    public static native void nativeLowMemory();
+    public static native void nativeQuit();
+    public static native void nativePause();
+    public static native void nativeResume();
+    public static native void onNativeResize(int x, int y, int format);
+    public static native int onNativePadDown(int device_id, int keycode);
+    public static native int onNativePadUp(int device_id, int keycode);
+    public static native void onNativeJoy(int device_id, int axis,
+                                          float value);
+    public static native void onNativeHat(int device_id, int hat_id,
+                                          int x, int y);
+    public static native void onNativeKeyDown(int keycode);
+    public static native void onNativeKeyUp(int keycode);
+    public static native void onNativeKeyboardFocusLost();
+    public static native void onNativeTouch(int touchDevId, int pointerFingerId,
+                                            int action, float x, 
+                                            float y, float p);
+    public static native void onNativeAccel(float x, float y, float z);
+    public static native void onNativeSurfaceChanged();
+    public static native void onNativeSurfaceDestroyed();
+    public static native void nativeFlipBuffers();
+    public static native int nativeAddJoystick(int device_id, String name, 
+                                               int is_accelerometer, int nbuttons, 
+                                               int naxes, int nhats, int nballs);
+    public static native int nativeRemoveJoystick(int device_id);
+
+    public static void flipBuffers() {
+        SDLActivity.nativeFlipBuffers();
+    }
+
+    public static boolean setActivityTitle(String title) {
+        // Called from SDLMain() thread and can't directly affect the view
+        return mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+    }
+
+    public static boolean sendMessage(int command, int param) {
+        return mSingleton.sendCommand(command, Integer.valueOf(param));
+    }
+
+    public static Context getContext() {
+        return mSingleton;
+    }
+
+    /**
+     * @return result of getSystemService(name) but executed on UI thread.
+     */
+    public Object getSystemServiceFromUiThread(final String name) {
+        final Object lock = new Object();
+        final Object[] results = new Object[2]; // array for writable variables
+        synchronized (lock) {
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (lock) {
+                        results[0] = getSystemService(name);
+                        results[1] = Boolean.TRUE;
+                        lock.notify();
+                    }
+                }
+            });
+            if (results[1] == null) {
+                try {
+                    lock.wait();
+                } catch (InterruptedException ex) {
+                    ex.printStackTrace();
+                }
+            }
+        }
+        return results[0];
+    }
+
+    static class ShowTextInputTask implements Runnable {
+        /*
+         * This is used to regulate the pan&scan method to have some offset from
+         * the bottom edge of the input region and the top edge of an input
+         * method (soft keyboard)
+         */
+        static final int HEIGHT_PADDING = 15;
+
+        public int x, y, w, h;
+
+        public ShowTextInputTask(int x, int y, int w, int h) {
+            this.x = x;
+            this.y = y;
+            this.w = w;
+            this.h = h;
+        }
+
+        @Override
+        public void run() {
+            AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(
+                    w, h + HEIGHT_PADDING, x, y);
+
+            if (mTextEdit == null) {
+                mTextEdit = new DummyEdit(getContext());
+
+                mLayout.addView(mTextEdit, params);
+            } else {
+                mTextEdit.setLayoutParams(params);
+            }
+
+            mTextEdit.setVisibility(View.VISIBLE);
+            mTextEdit.requestFocus();
+
+            InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+            imm.showSoftInput(mTextEdit, 0);
+        }
+    }
+
+    public static boolean showTextInput(int x, int y, int w, int h) {
+        // Transfer the task to the main thread as a Runnable
+        return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
+    }
+            
+    public static Surface getNativeSurface() {
+        return SDLActivity.mSurface.getNativeSurface();
+    }
+
+    // Audio
+    public static int audioInit(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("SDL", "SDL audio: 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, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+        
+        if (mAudioTrack == null) {
+            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+                    channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+            
+            // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
+            // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
+            // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
+            
+            if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
+                Log.e("SDL", "Failed during initialization of Audio Track");
+                mAudioTrack = null;
+                return -1;
+            }
+            
+            mAudioTrack.play();
+        }
+       
+        Log.v("SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+        
+        return 0;
+    }
+    
+    public static void audioWriteShortBuffer(short[] buffer) {
+        for (int i = 0; i < buffer.length; ) {
+            int result = mAudioTrack.write(buffer, i, buffer.length - i);
+            if (result > 0) {
+                i += result;
+            } else if (result == 0) {
+                try {
+                    Thread.sleep(1);
+                } catch(InterruptedException e) {
+                    // Nom nom
+                }
+            } else {
+                Log.w("SDL", "SDL audio: error return from write(short)");
+                return;
+            }
+        }
+    }
+    
+    public static void audioWriteByteBuffer(byte[] buffer) {
+        for (int i = 0; i < buffer.length; ) {
+            int result = mAudioTrack.write(buffer, i, buffer.length - i);
+            if (result > 0) {
+                i += result;
+            } else if (result == 0) {
+                try {
+                    Thread.sleep(1);
+                } catch(InterruptedException e) {
+                    // Nom nom
+                }
+            } else {
+                Log.w("SDL", "SDL audio: error return from write(byte)");
+                return;
+            }
+        }
+    }
+
+    public static void audioQuit() {
+        if (mAudioTrack != null) {
+            mAudioTrack.stop();
+            mAudioTrack = null;
+        }
+    }
+
+    // Input
+
+    /**
+     * @return an array which may be empty but is never null.
+     */
+    public static int[] inputGetInputDeviceIds(int sources) {
+        int[] ids = InputDevice.getDeviceIds();
+        int[] filtered = new int[ids.length];
+        int used = 0;
+        for (int i = 0; i < ids.length; ++i) {
+            InputDevice device = InputDevice.getDevice(ids[i]);
+            if ((device != null) && ((device.getSources() & sources) != 0)) {
+                filtered[used++] = device.getId();
+            }
+        }
+        return Arrays.copyOf(filtered, used);
+    }
+
+    // Atomic: add handler null check
+    // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
+    public static boolean handleJoystickMotionEvent(MotionEvent event) {
+        return mJoystickHandler != null && mJoystickHandler.handleMotionEvent(event); 
+    }
+    
+    public static void pollInputDevices() {
+        if (SDLActivity.mSDLThread != null && mJoystickHandler != null) {
+            mJoystickHandler.pollInputDevices();
+        }
+    }
+    
+}
+
+/**
+    Simple nativeInit() runnable
+*/
+class SDLMain implements Runnable {
+    @Override
+    public void run() {
+        // Runs SDL_main()
+        // Atomic: pass filesDir
+        SDLActivity.nativeInit(((Activity)SDLActivity.getContext()).getFilesDir().getAbsolutePath());
+        //Log.v("SDL", "SDL thread terminated");
+    }
+}
+
+
+/**
+    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
+*/
+class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
+    View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
+
+    // Sensors
+    protected static SensorManager mSensorManager;
+    protected static Display mDisplay;
+
+    // Keep track of the surface size to normalize touch events
+    protected static float mWidth, mHeight;
+
+    // Startup    
+    public SDLSurface(Context context) {
+        super(context);
+        getHolder().addCallback(this); 
+    
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        requestFocus();
+        setOnKeyListener(this); 
+        setOnTouchListener(this);   
+
+        mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+        
+        if(Build.VERSION.SDK_INT >= 12) {
+            setOnGenericMotionListener(new SDLGenericMotionListener_API12());
+        }
+
+        // Some arbitrary defaults to avoid a potential division by zero
+        mWidth = 1.0f;
+        mHeight = 1.0f;
+    }
+    
+    public Surface getNativeSurface() {
+        return getHolder().getSurface();
+    }
+
+    // Called when we have a valid drawing surface
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        Log.v("SDL", "surfaceCreated()");
+        holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+    }
+
+    // Called when we lose the surface
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        Log.v("SDL", "surfaceDestroyed()");
+        // Call this *before* setting mIsSurfaceReady to 'false'
+        SDLActivity.handlePause();
+        SDLActivity.mIsSurfaceReady = false;
+        SDLActivity.onNativeSurfaceDestroyed();
+    }
+
+    // Called when the surface is resized
+    @Override
+    public void surfaceChanged(SurfaceHolder holder,
+                               int format, int width, int height) {
+        Log.v("SDL", "surfaceChanged()");
+
+        int sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565 by default
+        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;
+        }
+
+        mWidth = width;
+        mHeight = height;
+        SDLActivity.onNativeResize(width, height, sdlFormat);
+        Log.v("SDL", "Window size:" + width + "x"+height);
+
+        // Set mIsSurfaceReady to 'true' *before* making a call to handleResume
+        SDLActivity.mIsSurfaceReady = true;
+        SDLActivity.onNativeSurfaceChanged();
+
+
+        if (SDLActivity.mSDLThread == null) {
+            // This is the entry point to the C app.
+            // Start up the C app thread and enable sensor input for the first time
+
+            SDLActivity.mSDLThread = new Thread(new SDLMain(), "SDLThread");
+            enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+            SDLActivity.mSDLThread.start();
+            
+            // Set up a listener thread to catch when the native thread ends
+            new Thread(new Runnable(){
+                @Override
+                public void run(){
+                    try {
+                        SDLActivity.mSDLThread.join();
+                    }
+                    catch(Exception e){}
+                    finally{ 
+                        // Native thread has finished
+                        if (! SDLActivity.mExitCalledFromJava) {
+                            SDLActivity.handleNativeExit();
+                        }
+                    }
+                }
+            }).start();
+        }
+    }
+
+    // unused
+    @Override
+    public void onDraw(Canvas canvas) {}
+
+
+    // Key events
+    @Override
+    public boolean onKey(View  v, int keyCode, KeyEvent event) {
+        // 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() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */
+                   (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
+                    return true;
+                }
+            } else if (event.getAction() == KeyEvent.ACTION_UP) {
+                if (SDLActivity.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
+                    return true;
+                }
+            }
+        }
+        
+        if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                //Log.v("SDL", "key down: " + keyCode);
+                SDLActivity.onNativeKeyDown(keyCode);
+                return true;
+            }
+            else if (event.getAction() == KeyEvent.ACTION_UP) {
+                //Log.v("SDL", "key up: " + keyCode);
+                SDLActivity.onNativeKeyUp(keyCode);
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    // Touch events
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        /* Ref: http://developer.android.com/training/gestures/multi.html */
+        final int touchDevId = event.getDeviceId();
+        final int pointerCount = event.getPointerCount();
+        int action = event.getActionMasked();
+        int pointerFingerId;
+        int i = -1;
+        float x,y,p;
+        
+        switch(action) {
+            case MotionEvent.ACTION_MOVE:
+                for (i = 0; i < pointerCount; i++) {
+                    pointerFingerId = event.getPointerId(i);
+                    x = event.getX(i) / mWidth;
+                    y = event.getY(i) / mHeight;
+                    p = event.getPressure(i);
+                    SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+                }
+                break;
+            
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_DOWN:
+                // Primary pointer up/down, the index is always zero
+                i = 0;
+            case MotionEvent.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_DOWN:
+                // Non primary pointer up/down
+                if (i == -1) {
+                    i = event.getActionIndex();
+                }
+                
+                pointerFingerId = event.getPointerId(i);
+                x = event.getX(i) / mWidth;
+                y = event.getY(i) / mHeight;
+                p = event.getPressure(i);
+                SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+                break;
+            
+            default:
+                break;
+        }
+
+        return true;
+   } 
+
+    // Sensor events
+    public void enableSensor(int sensortype, boolean enabled) {
+        // TODO: This uses getDefaultSensor - what if we have >1 accels?
+        if (enabled) {
+            mSensorManager.registerListener(this, 
+                            mSensorManager.getDefaultSensor(sensortype), 
+                            SensorManager.SENSOR_DELAY_GAME, null);
+        } else {
+            mSensorManager.unregisterListener(this, 
+                            mSensorManager.getDefaultSensor(sensortype));
+        }
+    }
+    
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        // TODO
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+            float x, y;
+            switch (mDisplay.getRotation()) {
+                case Surface.ROTATION_90:
+                    x = -event.values[1];
+                    y = event.values[0];
+                    break;
+                case Surface.ROTATION_270:
+                    x = event.values[1];
+                    y = -event.values[0];
+                    break;
+                case Surface.ROTATION_180:
+                    // Atomic: fix SDL copy-paste error
+                    x = -event.values[0];
+                    y = -event.values[1];
+                    break;
+                default:
+                    x = event.values[0];
+                    y = event.values[1];
+                    break;
+            }
+            SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
+                                      y / SensorManager.GRAVITY_EARTH,
+                                      event.values[2] / SensorManager.GRAVITY_EARTH - 1);
+        }
+    }    
+}
+
+/* This is a fake invisible editor view that receives the input and defines the
+ * pan&scan region
+ */
+class DummyEdit extends View implements View.OnKeyListener {
+    InputConnection ic;
+
+    public DummyEdit(Context context) {
+        super(context);
+        setFocusableInTouchMode(true);
+        setFocusable(true);
+        setOnKeyListener(this);
+    }
+
+    @Override
+    public boolean onCheckIsTextEditor() {
+        return true;
+    }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+
+        // This handles the hardware keyboard input
+        if (event.isPrintingKey()) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
+            }
+            return true;
+        }
+
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            SDLActivity.onNativeKeyDown(keyCode);
+            return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            SDLActivity.onNativeKeyUp(keyCode);
+            return true;
+        }
+
+        return false;
+    }
+        
+    //
+    @Override
+    public boolean onKeyPreIme (int keyCode, KeyEvent 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: 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: 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 :)
+        if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
+            if (SDLActivity.mTextEdit != null && SDLActivity.mTextEdit.getVisibility() == View.VISIBLE) {
+                SDLActivity.onNativeKeyboardFocusLost();
+            }
+        }
+        return super.onKeyPreIme(keyCode, event);
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        ic = new SDLInputConnection(this, true);
+
+        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
+                | 33554432 /* API 11: EditorInfo.IME_FLAG_NO_FULLSCREEN */;
+
+        return ic;
+    }
+}
+
+class SDLInputConnection extends BaseInputConnection {
+
+    public SDLInputConnection(View targetView, boolean fullEditor) {
+        super(targetView, fullEditor);
+
+    }
+
+    @Override
+    public boolean sendKeyEvent(KeyEvent event) {
+
+        /*
+         * This handles the keycodes from soft keyboard (and IME-translated
+         * input from hardkeyboard)
+         */
+        int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            if (event.isPrintingKey()) {
+                commitText(String.valueOf((char) event.getUnicodeChar()), 1);
+            }
+            SDLActivity.onNativeKeyDown(keyCode);
+            return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+
+            SDLActivity.onNativeKeyUp(keyCode);
+            return true;
+        }
+        return super.sendKeyEvent(event);
+    }
+
+    @Override
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+
+        nativeCommitText(text.toString(), newCursorPosition);
+
+        return super.commitText(text, newCursorPosition);
+    }
+
+    @Override
+    public boolean setComposingText(CharSequence text, int newCursorPosition) {
+
+        nativeSetComposingText(text.toString(), newCursorPosition);
+
+        return super.setComposingText(text, newCursorPosition);
+    }
+
+    public native void nativeCommitText(String text, int newCursorPosition);
+
+    public native void nativeSetComposingText(String text, int newCursorPosition);
+
+    @Override
+    public boolean deleteSurroundingText(int beforeLength, int afterLength) {       
+        // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
+        if (beforeLength == 1 && afterLength == 0) {
+            // backspace
+            return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
+                && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
+        }
+
+        return super.deleteSurroundingText(beforeLength, afterLength);
+    }
+}
+
+/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
+class SDLJoystickHandler {
+    
+    public boolean handleMotionEvent(MotionEvent event) {
+        return false;
+    }
+    
+    public void pollInputDevices() {
+    }
+}
+
+/* Actual joystick functionality available for API >= 12 devices */
+class SDLJoystickHandler_API12 extends SDLJoystickHandler {
+  
+    class SDLJoystick {
+        public int device_id;
+        public String name;
+        public ArrayList<InputDevice.MotionRange> axes;
+        public ArrayList<InputDevice.MotionRange> hats;
+    }
+    class RangeComparator implements Comparator<InputDevice.MotionRange>
+    {
+        @Override
+        public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
+            return arg0.getAxis() - arg1.getAxis();
+        }
+    }
+    
+    private ArrayList<SDLJoystick> mJoysticks;
+    
+    public SDLJoystickHandler_API12() {
+       
+        mJoysticks = new ArrayList<SDLJoystick>();
+    }
+
+    @Override
+    public void pollInputDevices() {
+        int[] deviceIds = InputDevice.getDeviceIds();
+        // It helps processing the device ids in reverse order
+        // For example, in the case of the XBox 360 wireless dongle,
+        // so the first controller seen by SDL matches what the receiver
+        // considers to be the first controller
+        
+        for(int i=deviceIds.length-1; i>-1; i--) {
+            SDLJoystick joystick = getJoystick(deviceIds[i]);
+            if (joystick == null) {
+                joystick = new SDLJoystick();
+                InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
+                if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+                    joystick.device_id = deviceIds[i];
+                    joystick.name = joystickDevice.getName();
+                    joystick.axes = new ArrayList<InputDevice.MotionRange>();
+                    joystick.hats = new ArrayList<InputDevice.MotionRange>();
+                    
+                    List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
+                    Collections.sort(ranges, new RangeComparator());
+                    for (InputDevice.MotionRange range : ranges ) {
+                        if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) {
+                            if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
+                                range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+                                joystick.hats.add(range);
+                            }
+                            else {
+                                joystick.axes.add(range);
+                            }
+                        }
+                    }
+                    
+                    mJoysticks.add(joystick);
+                    SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1, 
+                                                  joystick.axes.size(), joystick.hats.size()/2, 0);
+                }
+            }
+        }
+        
+        /* Check removed devices */
+        ArrayList<Integer> removedDevices = new ArrayList<Integer>();
+        for(int i=0; i < mJoysticks.size(); i++) {
+            int device_id = mJoysticks.get(i).device_id;
+            int j;
+            for (j=0; j < deviceIds.length; j++) {
+                if (device_id == deviceIds[j]) break;
+            }
+            if (j == deviceIds.length) {
+                removedDevices.add(device_id);
+            }
+        }
+            
+        for(int i=0; i < removedDevices.size(); i++) {
+            int device_id = removedDevices.get(i);
+            SDLActivity.nativeRemoveJoystick(device_id);
+            for (int j=0; j < mJoysticks.size(); j++) {
+                if (mJoysticks.get(j).device_id == device_id) {
+                    mJoysticks.remove(j);
+                    break;
+                }
+            }
+        }        
+    }
+    
+    protected SDLJoystick getJoystick(int device_id) {
+        for(int i=0; i < mJoysticks.size(); i++) {
+            if (mJoysticks.get(i).device_id == device_id) {
+                return mJoysticks.get(i);
+            }
+        }
+        return null;
+    }   
+    
+    @Override        
+    public boolean handleMotionEvent(MotionEvent event) {
+        if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
+            int actionPointerIndex = event.getActionIndex();
+            int action = event.getActionMasked();
+            switch(action) {
+                case MotionEvent.ACTION_MOVE:
+                    SDLJoystick joystick = getJoystick(event.getDeviceId());
+                    if ( joystick != null ) {
+                        for (int i = 0; i < joystick.axes.size(); i++) {
+                            InputDevice.MotionRange range = joystick.axes.get(i);
+                            /* Normalize the value to -1...1 */
+                            float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
+                            SDLActivity.onNativeJoy(joystick.device_id, i, value );
+                        }          
+                        for (int i = 0; i < joystick.hats.size(); i+=2) {
+                            int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
+                            int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
+                            SDLActivity.onNativeHat(joystick.device_id, i/2, hatX, hatY );
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+        return true;
+    }            
+}
+
+class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
+    // Generic Motion (mouse hover, joystick...) events go here
+    // We only have joysticks yet
+    @Override
+    public boolean onGenericMotion(View v, MotionEvent event) {
+        return SDLActivity.handleJoystickMotionEvent(event);
+    }
+}

+ 115 - 0
Bin/CoreData/AtomicModules/AtomicGame.js

@@ -0,0 +1,115 @@
+
+Atomic.editor = null;
+
+function Game() {
+
+	this.engine = Atomic.GetEngine();
+	this.cache = Atomic.GetResourceCache();	
+	this.renderer = Atomic.GetRenderer();
+	this.graphics = Atomic.GetGraphics();
+	this.input = Atomic.GetInput();
+
+}
+
+Game.prototype.init = function(start, update) {
+
+	this.start = start;
+	this.update = update;
+
+	// register globals to get at quickly
+	__js_atomicgame_start = start;
+	__js_atomicgame_update = update;
+
+}
+
+Game.prototype.getSpriteSheet2D = function(xmlFile) {
+
+	return this.cache.getResource("SpriteSheet2D", xmlFile);
+
+}
+
+Game.prototype.getSpriteSheet = Game.prototype.getSpriteSheet2D;
+
+Game.prototype.getSound = function(soundFile) {
+
+    return this.cache.getResource("Sound", soundFile);
+
+}
+
+Game.prototype.getSprite2D = function(spriteFile) {
+
+    return this.cache.getResource("Sprite2D", spriteFile);
+
+}
+
+
+Game.prototype.showDebugHud = function() {
+
+	var uiStyle = this.cache.getResource("XMLFile", "UI/DefaultStyle.xml");
+    var debugHud = this.engine.createDebugHud();
+    debugHud.defaultStyle = uiStyle;
+    debugHud.toggleAll();
+
+}
+
+Game.prototype.createScene2D = function() {
+
+	var scene = new Atomic.Scene();
+    scene.createComponent("Octree");
+
+    var cameraNode = scene.createChild("Camera");
+    cameraNode.position = [0.0, 0.0, -10.0];
+
+    var camera = cameraNode.createComponent("Camera");    
+    camera.orthographic = true;
+    camera.orthoSize = this.graphics.height * Atomic.PIXEL_SIZE;
+
+    var viewport = new Atomic.Viewport(scene, camera);
+
+    if (Atomic.editor) {
+        var _viewport = Atomic.editor.viewport;
+        viewport.rect = [_viewport.left, _viewport.top, _viewport.right, _viewport.bottom];
+    }
+
+    this.renderer.setViewport(0, viewport);
+
+    this.scene = scene;
+    this.cameraNode = cameraNode;
+    this.camera = camera;
+    this.viewport = viewport;    
+
+    return scene;
+
+}
+
+Game.prototype.createScene3D = function() {
+
+    var scene = new Atomic.Scene();
+    scene.createComponent("Octree");
+
+    var cameraNode = scene.createChild("Camera");
+    cameraNode.position = [0.0, 0.0, -10.0];
+
+    var camera = cameraNode.createComponent("Camera");    
+
+    var viewport = new Atomic.Viewport(scene, camera);
+
+    if (Atomic.editor) {
+        var _viewport = Atomic.editor.viewport;
+        viewport.rect = [_viewport.left, _viewport.top, _viewport.right - 8, _viewport.bottom];
+    }
+
+    this.renderer.setViewport(0, viewport);
+
+    this.scene = scene;
+    this.cameraNode = cameraNode;
+    this.camera = camera;
+    this.viewport = viewport;    
+
+    return scene;
+
+}
+
+
+Atomic.game = exports.game = new Game();
+

+ 5 - 0
Bin/CoreData/Materials/DefaultGrey.xml

@@ -0,0 +1,5 @@
+<material>
+    <technique name="Techniques/NoTexture.xml" />
+    <parameter name="MatDiffColor" value="0.5 0.5 0.5 1" />
+    <parameter name="MatSpecColor" value="0.5 0.5 0.5 16" />
+</material>

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

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

+ 22 - 0
Bin/CoreData/RenderPaths/DeferredHWDepth.xml

@@ -0,0 +1,22 @@
+<renderpath>
+    <rendertarget name="albedo" sizedivisor="1 1" format="rgba" />
+    <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
+    <rendertarget name="depth" sizedivisor="1 1" format="readabledepth" />
+    <command type="clear" color="fog" depth="1.0" stencil="0" depthstencil="depth" />
+    <command type="scenepass" pass="deferred" marktostencil="true" vertexlights="true" metadata="gbuffer" depthstencil="depth">
+        <output index="0" name="viewport" />
+        <output index="1" name="albedo" />
+        <output index="2" name="normal" />
+    </command>
+    <command type="lightvolumes" vs="DeferredLight" ps="DeferredLight" psdefines="HWDEPTH" depthstencil="depth">
+        <texture unit="albedo" name="albedo" />
+        <texture unit="normal" name="normal" />
+        <texture unit="depth" name="depth" />
+    </command>
+    <command type="scenepass" pass="postopaque" depthstencil="depth" />
+    <command type="scenepass" pass="refract" depthstencil="depth">
+        <texture unit="environment" name="viewport" />
+    </command>
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
+</renderpath>

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

@@ -0,0 +1,11 @@
+<renderpath>
+    <command type="clear" color="fog" depth="1.0" stencil="0" />
+    <command type="scenepass" pass="base" vertexlights="true" metadata="base" />
+    <command type="forwardlights" pass="light" />
+    <command type="scenepass" pass="postopaque" />
+    <command type="scenepass" pass="refract">
+        <texture unit="environment" name="viewport" />
+    </command>
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" />
+</renderpath>

+ 14 - 0
Bin/CoreData/RenderPaths/ForwardDepth.xml

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

+ 14 - 0
Bin/CoreData/RenderPaths/ForwardHWDepth.xml

@@ -0,0 +1,14 @@
+<renderpath>
+    <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="scenepass" pass="base" vertexlights="true" metadata="base" depthstencil="depth" />
+    <command type="forwardlights" pass="light" depthstencil="depth" />
+    <command type="scenepass" pass="postopaque" depthstencil="depth" />
+    <command type="scenepass" pass="refract" depthstencil="depth">
+        <texture unit="environment" name="viewport" />
+    </command>
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth"  />
+    <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
+</renderpath>

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

@@ -0,0 +1,24 @@
+<renderpath>
+    <rendertarget name="light" sizedivisor="1 1"  format="rgba" />
+    <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
+    <rendertarget name="depth" sizedivisor="1 1"  format="lineardepth" />
+    <command type="clear" color="fog" depth="1.0" stencil="0" />
+    <command type="scenepass" pass="prepass" marktostencil="true" metadata="gbuffer">
+        <output index="0" name="normal" />
+        <output index="1" name="depth" />
+    </command>
+    <command type="clear" color="0 0 0 0" output="light" />
+    <command type="lightvolumes" vs="PrepassLight" ps="PrepassLight" output="light">
+        <texture unit="normal" name="normal" />
+        <texture unit="depth" name="depth" />
+    </command>
+    <command type="scenepass" pass="material" vertexlights="true">
+        <texture unit="light" name="light" />
+    </command>
+    <command type="scenepass" pass="postopaque" />
+    <command type="scenepass" pass="refract">
+        <texture unit="environment" name="viewport" />
+    </command>
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" />
+</renderpath>

+ 3 - 0
Bin/CoreData/RenderPaths/PrepassHDR.xml

@@ -0,0 +1,3 @@
+<renderpath inherit="RenderPaths/Prepass.xml">
+    <replace sel="/renderpath/rendertarget[@name='light']/@format">rgba16f</replace>
+</renderpath>

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

@@ -0,0 +1,21 @@
+<renderpath>
+    <rendertarget name="light" sizedivisor="1 1"  format="rgba" />
+    <rendertarget name="normal" sizedivisor="1 1" format="rgba" />
+    <rendertarget name="depth" sizedivisor="1 1"  format="readabledepth" />
+    <command type="clear" color="fog" depth="1.0" stencil="0" depthstencil="depth" />
+    <command type="scenepass" pass="prepass" marktostencil="true" metadata="gbuffer" output="normal" depthstencil="depth" />
+    <command type="clear" color="0 0 0 0" output="light" depthstencil="depth" />
+    <command type="lightvolumes" vs="PrepassLight" ps="PrepassLight" psdefines="HWDEPTH" output="light" depthstencil="depth" >
+        <texture unit="normal" name="normal" />
+        <texture unit="depth" name="depth" />
+    </command>
+    <command type="scenepass" pass="material" vertexlights="true" depthstencil="depth">
+        <texture unit="light" name="light" />
+    </command>
+    <command type="scenepass" pass="postopaque" depthstencil="depth" />
+    <command type="scenepass" pass="refract" depthstencil="depth">
+        <texture unit="environment" name="viewport" />
+    </command>
+    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" depthstencil="depth" />
+    <command type="scenepass" pass="postalpha" sort="backtofront" depthstencil="depth" />
+</renderpath>

+ 23 - 0
Bin/CoreData/Shaders/GLSL/Atomic2D.glsl

@@ -0,0 +1,23 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec2 vTexCoord;
+varying vec4 vColor;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    
+    vTexCoord = iTexCoord;
+    vColor = iColor;
+}
+
+void PS()
+{
+    vec4 diffColor = cMatDiffColor * vColor;
+    vec4 diffInput = texture2D(sDiffMap, vTexCoord);
+    gl_FragColor = diffColor * diffInput;
+}

+ 73 - 0
Bin/CoreData/Shaders/GLSL/AutoExposure.glsl

@@ -0,0 +1,73 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "PostProcess.glsl"
+
+varying vec2 vTexCoord;
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform float cAutoExposureAdaptRate;
+uniform vec2 cAutoExposureLumRange;
+uniform float cAutoExposureMiddleGrey;
+uniform vec2 cHDR128InvSize;
+uniform vec2 cLum64InvSize;
+uniform vec2 cLum16InvSize;
+uniform vec2 cLum4InvSize;
+
+float GatherAvgLum(sampler2D texSampler, vec2 texCoord, vec2 texelSize)
+{
+    float lumAvg = 0.0;
+    lumAvg += texture2D(texSampler, texCoord + vec2(1.0, -1.0) * texelSize).r;
+    lumAvg += texture2D(texSampler, texCoord + vec2(-1.0, 1.0) * texelSize).r;
+    lumAvg += texture2D(texSampler, texCoord + vec2(1.0, 1.0) * texelSize).r;
+    lumAvg += texture2D(texSampler, texCoord + vec2(1.0, -1.0) * texelSize).r;
+    return lumAvg / 4.0;
+}
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetQuadTexCoord(gl_Position);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    #ifdef LUMINANCE64
+    float logLumSum = 0.0;
+    logLumSum += log(dot(texture2D(sDiffMap, vTexCoord + vec2(-1.0, -1.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    logLumSum += log(dot(texture2D(sDiffMap, vTexCoord + vec2(-1.0, 1.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    logLumSum += log(dot(texture2D(sDiffMap, vTexCoord + vec2(1.0, 1.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    logLumSum += log(dot(texture2D(sDiffMap, vTexCoord + vec2(1.0, -1.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    gl_FragColor.r = logLumSum;
+    #endif
+
+    #ifdef LUMINANCE16
+    gl_FragColor.r = GatherAvgLum(sDiffMap, vTexCoord, cLum64InvSize);
+    #endif
+
+    #ifdef LUMINANCE4
+    gl_FragColor.r = GatherAvgLum(sDiffMap, vTexCoord, cLum16InvSize);
+    #endif
+
+    #ifdef LUMINANCE1
+    gl_FragColor.r = exp(GatherAvgLum(sDiffMap, vTexCoord, cLum4InvSize) / 16.0);
+    #endif
+
+    #ifdef ADAPTLUMINANCE
+    float adaptedLum = texture2D(sDiffMap, vTexCoord).r;
+    float lum = clamp(texture2D(sNormalMap, vTexCoord).r, cAutoExposureLumRange.x, cAutoExposureLumRange.y);
+    gl_FragColor.r = adaptedLum + (lum - adaptedLum) * (1.0 - exp(-cDeltaTimePS * cAutoExposureAdaptRate));
+    #endif
+
+    #ifdef EXPOSE
+    vec3 color = texture2D(sDiffMap, vScreenPos).rgb;
+    float adaptedLum = texture2D(sNormalMap, vTexCoord).r;
+    gl_FragColor = vec4(color * (cAutoExposureMiddleGrey / adaptedLum), 1.0);
+    #endif
+}

+ 49 - 0
Bin/CoreData/Shaders/GLSL/Basic.glsl

@@ -0,0 +1,49 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+#if defined(DIFFMAP) || defined(ALPHAMAP)
+    varying vec2 vTexCoord;
+#endif
+#ifdef VERTEXCOLOR
+    varying vec4 vColor;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    
+    #ifdef DIFFMAP
+        vTexCoord = iTexCoord;
+    #endif
+    #ifdef VERTEXCOLOR
+        vColor = iColor;
+    #endif
+}
+
+void PS()
+{
+    vec4 diffColor = cMatDiffColor;
+
+    #ifdef VERTEXCOLOR
+        diffColor *= vColor;
+    #endif
+
+    #if (!defined(DIFFMAP)) && (!defined(ALPHAMAP))
+        gl_FragColor = diffColor;
+    #endif
+    #ifdef DIFFMAP
+        vec4 diffInput = texture2D(sDiffMap, vTexCoord);
+        #ifdef ALPHAMASK
+            if (diffInput.a < 0.5)
+                discard;
+        #endif
+        gl_FragColor = diffColor * diffInput;
+    #endif
+    #ifdef ALPHAMAP
+        float alphaInput = texture2D(sDiffMap, vTexCoord).a;
+        gl_FragColor = vec4(diffColor.rgb, diffColor.a * alphaInput);
+    #endif
+}

+ 57 - 0
Bin/CoreData/Shaders/GLSL/Bloom.glsl

@@ -0,0 +1,57 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+
+varying vec2 vTexCoord;
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform float cBloomThreshold;
+uniform vec2 cBloomMix;
+uniform vec2 cHBlurInvSize;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetQuadTexCoord(gl_Position);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    #ifdef BRIGHT
+    vec3 rgb = texture2D(sDiffMap, vScreenPos).rgb;
+    gl_FragColor = vec4((rgb - vec3(cBloomThreshold, cBloomThreshold, cBloomThreshold)) / (1.0 - cBloomThreshold), 1.0);
+    #endif
+
+    #ifdef HBLUR
+    vec3 rgb = texture2D(sDiffMap, vTexCoord + vec2(-2.0, 0.0) * cHBlurInvSize).rgb * 0.1;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(-1.0, 0.0) * cHBlurInvSize).rgb * 0.25;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cHBlurInvSize).rgb * 0.3;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(1.0, 0.0) * cHBlurInvSize).rgb * 0.25;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(2.0, 0.0) * cHBlurInvSize).rgb * 0.1;
+    gl_FragColor = vec4(rgb, 1.0);
+    #endif
+
+    #ifdef VBLUR
+    vec3 rgb = texture2D(sDiffMap, vTexCoord + vec2(0.0, -2.0) * cHBlurInvSize).rgb * 0.1;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, -1.0) * cHBlurInvSize).rgb * 0.25;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cHBlurInvSize).rgb * 0.3;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, 1.0) * cHBlurInvSize).rgb * 0.25;
+    rgb += texture2D(sDiffMap, vTexCoord + vec2(0.0, 2.0) * cHBlurInvSize).rgb * 0.1;
+    gl_FragColor = vec4(rgb, 1.0);
+    #endif
+
+    #ifdef COMBINE
+    vec3 original = texture2D(sDiffMap, vScreenPos).rgb * cBloomMix.x;
+    vec3 bloom = texture2D(sNormalMap, vTexCoord).rgb  * cBloomMix.y;
+    // Prevent oversaturation
+    original *= max(vec3(1.0) - bloom, vec3(0.0));
+    gl_FragColor = vec4(original + bloom, 1.0);
+    #endif
+}
+

+ 73 - 0
Bin/CoreData/Shaders/GLSL/BloomHDR.glsl

@@ -0,0 +1,73 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "PostProcess.glsl"
+
+varying vec2 vTexCoord;
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform float cBloomHDRThreshold;
+uniform float cBloomHDRBlurSigma;
+uniform float cBloomHDRBlurRadius;
+uniform vec2 cBloomHDRBlurDir;
+uniform vec2 cBloomHDRMix;
+uniform vec2 cBright2InvSize;
+uniform vec2 cBright4InvSize;
+uniform vec2 cBright8InvSize;
+uniform vec2 cBright16InvSize;
+
+const int BlurKernelSize = 5;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetQuadTexCoord(gl_Position);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    #ifdef BRIGHT
+    vec3 color = texture2D(sDiffMap, vScreenPos).rgb;
+    gl_FragColor = vec4(max(color - cBloomHDRThreshold, 0.0), 1.0);
+    #endif
+
+    #ifdef BLUR16
+    gl_FragColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright16InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, vScreenPos);
+    #endif
+
+    #ifdef BLUR8
+    gl_FragColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright8InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, vScreenPos);
+    #endif
+
+    #ifdef BLUR4
+    gl_FragColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright4InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, vScreenPos);
+    #endif
+
+    #ifdef BLUR2
+    gl_FragColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright2InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, vScreenPos);
+    #endif
+
+    #ifdef COMBINE16
+    gl_FragColor = texture2D(sDiffMap, vScreenPos) + texture2D(sNormalMap, vTexCoord);
+    #endif
+
+    #ifdef COMBINE8
+    gl_FragColor = texture2D(sDiffMap, vScreenPos) + texture2D(sNormalMap, vTexCoord);
+    #endif
+
+    #ifdef COMBINE4
+    gl_FragColor = texture2D(sDiffMap, vScreenPos) + texture2D(sNormalMap, vTexCoord);
+    #endif
+
+    #ifdef COMBINE2
+    vec3 color = texture2D(sDiffMap, vScreenPos).rgb * cBloomHDRMix.x;
+    vec3 bloom = texture2D(sNormalMap, vTexCoord).rgb * cBloomHDRMix.y;
+    gl_FragColor = vec4(color + bloom, 1.0);
+    #endif
+}

+ 43 - 0
Bin/CoreData/Shaders/GLSL/Blur.glsl

@@ -0,0 +1,43 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "PostProcess.glsl"
+
+varying vec2 vTexCoord;
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform vec2 cBlurDir;
+uniform float cBlurRadius;
+uniform float cBlurSigma;
+uniform vec2 cBlurHInvSize;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetQuadTexCoord(gl_Position);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    #ifdef BLUR3
+        gl_FragColor = GaussianBlur(3, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, vTexCoord);
+    #endif
+
+    #ifdef BLUR5
+        gl_FragColor = GaussianBlur(5, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, vTexCoord);
+    #endif
+
+    #ifdef BLUR7
+        gl_FragColor = GaussianBlur(7, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, vTexCoord);
+    #endif
+
+    #ifdef BLUR9
+        gl_FragColor = GaussianBlur(9, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, vTexCoord);
+    #endif
+}

+ 21 - 0
Bin/CoreData/Shaders/GLSL/ColorCorrection.glsl

@@ -0,0 +1,21 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "PostProcess.glsl"
+
+varying vec2 vScreenPos;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    vec3 color = texture2D(sDiffMap, vScreenPos).rgb;
+    gl_FragColor = vec4(ColorCorrection(color, sVolumeMap), 1.0);
+}

+ 20 - 0
Bin/CoreData/Shaders/GLSL/CopyFramebuffer.glsl

@@ -0,0 +1,20 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+
+varying vec2 vScreenPos;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    gl_FragColor = texture2D(sDiffMap, vScreenPos);
+}
+

+ 96 - 0
Bin/CoreData/Shaders/GLSL/DeferredLight.glsl

@@ -0,0 +1,96 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Lighting.glsl"
+
+#ifdef DIRLIGHT
+    varying vec2 vScreenPos;
+#else
+    varying vec4 vScreenPos;
+#endif
+varying vec3 vFarRay;
+#ifdef ORTHO
+    varying vec3 vNearRay;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    #ifdef DIRLIGHT
+        vScreenPos = GetScreenPosPreDiv(gl_Position);
+        vFarRay = GetFarRay(gl_Position);
+        #ifdef ORTHO
+            vNearRay = GetNearRay(gl_Position);
+        #endif
+    #else
+        vScreenPos = GetScreenPos(gl_Position);
+        vFarRay = GetFarRay(gl_Position) * gl_Position.w;
+        #ifdef ORTHO
+            vNearRay = GetNearRay(gl_Position) * gl_Position.w;
+        #endif
+    #endif
+}
+
+
+void PS()
+{
+    // If rendering a directional light quad, optimize out the w divide
+    #ifdef DIRLIGHT
+        #ifdef HWDEPTH
+            float depth = ReconstructDepth(texture2D(sDepthBuffer, vScreenPos).r);
+        #else
+            float depth = DecodeDepth(texture2D(sDepthBuffer, vScreenPos).rgb);
+        #endif
+        #ifdef ORTHO
+            vec3 worldPos = mix(vNearRay, vFarRay, depth);
+        #else
+            vec3 worldPos = vFarRay * depth;
+        #endif
+        vec4 albedoInput = texture2D(sAlbedoBuffer, vScreenPos);
+        vec4 normalInput = texture2D(sNormalBuffer, vScreenPos);
+    #else
+        #ifdef HWDEPTH
+            float depth = ReconstructDepth(texture2DProj(sDepthBuffer, vScreenPos).r);
+        #else
+            float depth = DecodeDepth(texture2DProj(sDepthBuffer, vScreenPos).rgb);
+        #endif
+        #ifdef ORTHO
+            vec3 worldPos = mix(vNearRay, vFarRay, depth) / vScreenPos.w;
+        #else
+            vec3 worldPos = vFarRay * depth / vScreenPos.w;
+        #endif
+        vec4 albedoInput = texture2DProj(sAlbedoBuffer, vScreenPos);
+        vec4 normalInput = texture2DProj(sNormalBuffer, vScreenPos);
+    #endif
+
+    vec3 normal = normalize(normalInput.rgb * 2.0 - 1.0);
+    vec4 projWorldPos = vec4(worldPos, 1.0);
+    vec3 lightColor;
+    vec3 lightDir;
+    
+    float diff = GetDiffuse(normal, worldPos, lightDir);
+
+    #ifdef SHADOW
+        diff *= GetShadowDeferred(projWorldPos, depth);
+    #endif
+
+    #if defined(SPOTLIGHT)
+        vec4 spotPos = cLightMatricesPS[0] * projWorldPos;
+        lightColor = spotPos.w > 0.0 ? texture2DProj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : vec3(0.0);
+    #elif defined(CUBEMASK)
+        mat3 lightVecRot = mat3(cLightMatricesPS[0][0].xyz, cLightMatricesPS[0][1].xyz, cLightMatricesPS[0][2].xyz);
+        lightColor = textureCube(sLightCubeMap, lightVecRot * (worldPos - cLightPosPS.xyz)).rgb * cLightColor.rgb;
+    #else
+        lightColor = cLightColor.rgb;
+    #endif
+
+    #ifdef SPECULAR
+        float spec = GetSpecular(normal, -worldPos, lightDir, normalInput.a * 255.0);
+        gl_FragColor = diff * vec4(lightColor * (albedoInput.rgb + spec * cLightColor.a * albedoInput.aaa), 0.0);
+    #else
+        gl_FragColor = diff * vec4(lightColor * albedoInput.rgb, 0.0);
+    #endif
+}

+ 24 - 0
Bin/CoreData/Shaders/GLSL/Depth.glsl

@@ -0,0 +1,24 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec3 vTexCoord;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = vec3(GetTexCoord(iTexCoord), GetDepth(gl_Position));
+}
+
+void PS()
+{
+    #ifdef ALPHAMASK
+        float alpha = texture2D(sDiffMap, vTexCoord.xy).a;
+        if (alpha < 0.5)
+            discard;
+    #endif
+
+    gl_FragColor = vec4(EncodeDepth(vTexCoord.z), 1.0);
+}

+ 88 - 0
Bin/CoreData/Shaders/GLSL/FXAA2.glsl

@@ -0,0 +1,88 @@
+/*============================================================================
+
+                  FXAA v2 CONSOLE by TIMOTHY LOTTES @ NVIDIA
+
+============================================================================*/
+
+// Adapted for Urho3D from http://timothylottes.blogspot.com/2011/04/nvidia-fxaa-ii-for-console.html
+
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform vec3 cFXAAParams;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    float FXAA_SUBPIX_SHIFT = 1.0/4.0; // Not used
+    float FXAA_SPAN_MAX = 8.0;
+    float FXAA_REDUCE_MUL = 1.0/8.0;
+    float FXAA_REDUCE_MIN = 1.0/128.0;
+
+    vec2 posOffset = cGBufferInvSize.xy * cFXAAParams.x;
+
+    vec3 rgbNW = texture2D(sDiffMap, vScreenPos + vec2(-posOffset.x, -posOffset.y)).rgb;
+    vec3 rgbNE = texture2D(sDiffMap, vScreenPos + vec2(posOffset.x, -posOffset.y)).rgb;
+    vec3 rgbSW = texture2D(sDiffMap, vScreenPos + vec2(-posOffset.x, posOffset.y)).rgb;
+    vec3 rgbSE = texture2D(sDiffMap, vScreenPos + vec2(posOffset.x, posOffset.y)).rgb;
+    vec3 rgbM  = texture2D(sDiffMap, vScreenPos).rgb;
+
+    vec3 luma = vec3(0.299, 0.587, 0.114);
+    float lumaNW = dot(rgbNW, luma);
+    float lumaNE = dot(rgbNE, luma);
+    float lumaSW = dot(rgbSW, luma);
+    float lumaSE = dot(rgbSE, luma);
+    float lumaM  = dot(rgbM,  luma);
+
+    float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
+    float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
+
+    if (((lumaMax - lumaMin) / lumaMin) >= cFXAAParams.y)
+    {
+        vec2 dir;
+        dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
+        dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
+
+        float dirReduce = max(
+            (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
+            FXAA_REDUCE_MIN);
+        float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
+        dir = min(vec2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX),
+              max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
+              dir * rcpDirMin)) * cGBufferInvSize.xy;
+
+        dir *= cFXAAParams.z;
+
+        vec3 rgbA = (1.0/2.0) * (
+            texture2D(sDiffMap, vScreenPos + dir * (1.0/3.0 - 0.5)).xyz +
+            texture2D(sDiffMap, vScreenPos + dir * (2.0/3.0 - 0.5)).xyz);
+        vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
+            texture2D(sDiffMap, vScreenPos + dir * (0.0/3.0 - 0.5)).xyz +
+            texture2D(sDiffMap, vScreenPos + dir * (3.0/3.0 - 0.5)).xyz);
+        float lumaB = dot(rgbB, luma);
+
+        vec3 rgbOut;
+        if((lumaB < lumaMin) || (lumaB > lumaMax))
+            rgbOut = rgbA;
+        else
+            rgbOut = rgbB;
+    
+        gl_FragColor = vec4(rgbOut, 1.0);
+    }
+    else
+        gl_FragColor = vec4(rgbM, 1.0);
+}
+

+ 734 - 0
Bin/CoreData/Shaders/GLSL/FXAA3.glsl

@@ -0,0 +1,734 @@
+//----------------------------------------------------------------------------------
+//
+// Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//  * Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//  * Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//  * Neither the name of NVIDIA CORPORATION nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//----------------------------------------------------------------------------------
+/*============================================================================
+
+
+                    NVIDIA FXAA 3.11 by TIMOTHY LOTTES
+
+------------------------------------------------------------------------------
+
+                           Modified for Urho3D
+
+============================================================================*/
+
+/*==========================================================================*/
+//
+//                      Urho3D specific preparations
+//
+/*--------------------------------------------------------------------------*/
+
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+
+varying vec2 vScreenPos;
+
+/*==========================================================================*/
+//
+//                      Shader Requirements
+//
+/*--------------------------------------------------------------------------*/
+
+#define FXAA_FAST_PIXEL_OFFSET 0
+
+/*--------------------------------------------------------------------------*/
+
+#if (FXAA_FAST_PIXEL_OFFSET == 1)
+    #define Fxaa_vec2 ivec2
+#else
+    #define Fxaa_vec2 vec2
+#endif
+
+/*============================================================================
+                        FXAA QUALITY - TUNING KNOBS
+------------------------------------------------------------------------------
+NOTE the other tuning knobs are now in the shader function inputs!
+============================================================================*/
+#ifndef FXAA_QUALITY_PRESET
+    //
+    // Choose the quality preset.
+    // This needs to be compiled into the shader as it effects code.
+    // Best option to include multiple presets is to 
+    // in each shader define the preset, then include this file.
+    //
+    // OPTIONS
+    // -----------------------------------------------------------------------
+    // 10 to 15 - default medium dither (10=fastest, 15=highest quality)
+    // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality)
+    // 39       - no dither, very expensive 
+    //
+    // NOTES
+    // -----------------------------------------------------------------------
+    // 12 = slightly faster then FXAA 3.9 and higher edge quality (default)
+    // 13 = about same speed as FXAA 3.9 and better than 12
+    // 23 = closest to FXAA 3.9 visually and performance wise
+    //  _ = the lowest digit is directly related to performance
+    // _  = the highest digit is directly related to style
+    // 
+    #define FXAA_QUALITY_PRESET 12
+#endif
+
+
+/*============================================================================
+
+                           FXAA QUALITY - PRESETS
+
+============================================================================*/
+
+/*============================================================================
+                     FXAA QUALITY - MEDIUM DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY_PRESET == 10)
+    #define FXAA_QUALITY_PS 3
+    #define FXAA_QUALITY_P0 1.5
+    #define FXAA_QUALITY_P1 3.0
+    #define FXAA_QUALITY_P2 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 11)
+    #define FXAA_QUALITY_PS 4
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 3.0
+    #define FXAA_QUALITY_P3 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 12)
+    #define FXAA_QUALITY_PS 5
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 4.0
+    #define FXAA_QUALITY_P4 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 13)
+    #define FXAA_QUALITY_PS 6
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 4.0
+    #define FXAA_QUALITY_P5 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 14)
+    #define FXAA_QUALITY_PS 7
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 4.0
+    #define FXAA_QUALITY_P6 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 15)
+    #define FXAA_QUALITY_PS 8
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 4.0
+    #define FXAA_QUALITY_P7 12.0
+#endif
+
+/*============================================================================
+                     FXAA QUALITY - LOW DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY_PRESET == 20)
+    #define FXAA_QUALITY_PS 3
+    #define FXAA_QUALITY_P0 1.5
+    #define FXAA_QUALITY_P1 2.0
+    #define FXAA_QUALITY_P2 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 21)
+    #define FXAA_QUALITY_PS 4
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 22)
+    #define FXAA_QUALITY_PS 5
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 23)
+    #define FXAA_QUALITY_PS 6
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 24)
+    #define FXAA_QUALITY_PS 7
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 3.0
+    #define FXAA_QUALITY_P6 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 25)
+    #define FXAA_QUALITY_PS 8
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 4.0
+    #define FXAA_QUALITY_P7 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 26)
+    #define FXAA_QUALITY_PS 9
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 4.0
+    #define FXAA_QUALITY_P8 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 27)
+    #define FXAA_QUALITY_PS 10
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 4.0
+    #define FXAA_QUALITY_P9 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 28)
+    #define FXAA_QUALITY_PS 11
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 2.0
+    #define FXAA_QUALITY_P9 4.0
+    #define FXAA_QUALITY_P10 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 29)
+    #define FXAA_QUALITY_PS 12
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 2.0
+    #define FXAA_QUALITY_P9 2.0
+    #define FXAA_QUALITY_P10 4.0
+    #define FXAA_QUALITY_P11 8.0
+#endif
+
+/*============================================================================
+                     FXAA QUALITY - EXTREME QUALITY
+============================================================================*/
+#if (FXAA_QUALITY_PRESET == 39)
+    #define FXAA_QUALITY_PS 12
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.0
+    #define FXAA_QUALITY_P2 1.0
+    #define FXAA_QUALITY_P3 1.0
+    #define FXAA_QUALITY_P4 1.0
+    #define FXAA_QUALITY_P5 1.5
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 2.0
+    #define FXAA_QUALITY_P9 2.0
+    #define FXAA_QUALITY_P10 4.0
+    #define FXAA_QUALITY_P11 8.0
+#endif
+
+/*============================================================================
+
+                            Support Functions
+
+============================================================================*/
+
+float CalcLuma(vec3 rgb)
+{
+    vec3 luma = vec3(0.299, 0.587, 0.114);
+    return dot(rgb, luma);
+}
+
+/*--------------------------------------------------------------------------*/
+
+#define FxaaTexTop(t, p) vec4(texture2DLod(t, p, 0.0).rgb, 1.0)
+
+#define LumaTop(t, p) CalcLuma(texture2DLod(t, p, 0.0).rgb)
+#if (FXAA_FAST_PIXEL_OFFSET == 1)
+    #define LumaOff(t, p, o, r) CalcLuma(texture2DLodOffset(t, p, 0.0, o).rgb)
+#else
+    #define LumaOff(t, p, o, r) CalcLuma(texture2DLod(t, p + (o * r), 0.0).rgb)
+#endif
+
+/*============================================================================
+
+                             FXAA3 QUALITY - PC
+
+============================================================================*/
+vec4 FxaaPixelShader(
+    //
+    // Use noperspective interpolation here (turn off perspective interpolation).
+    // {xy} = center of pixel
+    vec2 pos,
+    //
+    // Input color texture.
+    // {rgb_} = color in linear or perceptual color space
+    // if (FXAA_GREEN_AS_LUMA == 0)
+    //     {__a} = luma in perceptual color space (not linear)
+    sampler2D tex,
+    //
+    // Only used on FXAA Quality.
+    // This must be from a constant/uniform.
+    // {x_} = 1.0/screenWidthInPixels
+    // {_y} = 1.0/screenHeightInPixels
+    vec2 fxaaQualityRcpFrame,
+    //
+    // Only used on FXAA Quality.
+    // This used to be the FXAA_QUALITY_SUBPIX define.
+    // It is here now to allow easier tuning.
+    // Choose the amount of sub-pixel aliasing removal.
+    // This can effect sharpness.
+    //   1.00 - upper limit (softer)
+    //   0.75 - default amount of filtering
+    //   0.50 - lower limit (sharper, less sub-pixel aliasing removal)
+    //   0.25 - almost off
+    //   0.00 - completely off
+    float fxaaQualitySubpix,
+    //
+    // Only used on FXAA Quality.
+    // This used to be the FXAA_QUALITY_EDGE_THRESHOLD define.
+    // It is here now to allow easier tuning.
+    // The minimum amount of local contrast required to apply algorithm.
+    //   0.333 - too little (faster)
+    //   0.250 - low quality
+    //   0.166 - default
+    //   0.125 - high quality 
+    //   0.063 - overkill (slower)
+    float fxaaQualityEdgeThreshold,
+    //
+    // Only used on FXAA Quality.
+    // This used to be the FXAA_QUALITY_EDGE_THRESHOLD_MIN define.
+    // It is here now to allow easier tuning.
+    // Trims the algorithm from processing darks.
+    //   0.0833 - upper limit (default, the start of visible unfiltered edges)
+    //   0.0625 - high quality (faster)
+    //   0.0312 - visible limit (slower)
+    // Special notes when using FXAA_GREEN_AS_LUMA,
+    //   Likely want to set this to zero.
+    //   As colors that are mostly not-green
+    //   will appear very dark in the green channel!
+    //   Tune by looking at mostly non-green content,
+    //   then start at zero and increase until aliasing is a problem.
+    float fxaaQualityEdgeThresholdMin
+) {
+/*--------------------------------------------------------------------------*/
+    vec2 posM;
+    posM.x = pos.x;
+    posM.y = pos.y;
+    
+    vec4 rgbyM = FxaaTexTop(tex, posM);
+    rgbyM.y = CalcLuma(rgbyM.rgb);
+    #define lumaM rgbyM.y
+    float lumaS = LumaOff(tex, posM, Fxaa_vec2( 0, 1), fxaaQualityRcpFrame.xy);
+    float lumaE = LumaOff(tex, posM, Fxaa_vec2( 1, 0), fxaaQualityRcpFrame.xy);
+    float lumaN = LumaOff(tex, posM, Fxaa_vec2( 0,-1), fxaaQualityRcpFrame.xy);
+    float lumaW = LumaOff(tex, posM, Fxaa_vec2(-1, 0), fxaaQualityRcpFrame.xy);
+/*--------------------------------------------------------------------------*/
+    float maxSM = max(lumaS, lumaM);
+    float minSM = min(lumaS, lumaM);
+    float maxESM = max(lumaE, maxSM);
+    float minESM = min(lumaE, minSM);
+    float maxWN = max(lumaN, lumaW);
+    float minWN = min(lumaN, lumaW);
+    float rangeMax = max(maxWN, maxESM);
+    float rangeMin = min(minWN, minESM);
+    float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;
+    float range = rangeMax - rangeMin;
+    float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);
+    bool earlyExit = range < rangeMaxClamped;
+/*--------------------------------------------------------------------------*/
+    if(earlyExit)
+        return FxaaTexTop(tex, pos);
+/*--------------------------------------------------------------------------*/
+    float lumaNW = LumaOff(tex, posM, Fxaa_vec2(-1,-1), fxaaQualityRcpFrame.xy);
+    float lumaSE = LumaOff(tex, posM, Fxaa_vec2( 1, 1), fxaaQualityRcpFrame.xy);
+    float lumaNE = LumaOff(tex, posM, Fxaa_vec2( 1,-1), fxaaQualityRcpFrame.xy);
+    float lumaSW = LumaOff(tex, posM, Fxaa_vec2(-1, 1), fxaaQualityRcpFrame.xy);
+/*--------------------------------------------------------------------------*/
+    float lumaNS = lumaN + lumaS;
+    float lumaWE = lumaW + lumaE;
+    float subpixRcpRange = 1.0/range;
+    float subpixNSWE = lumaNS + lumaWE;
+    float edgeHorz1 = (-2.0 * lumaM) + lumaNS;
+    float edgeVert1 = (-2.0 * lumaM) + lumaWE;
+/*--------------------------------------------------------------------------*/
+    float lumaNESE = lumaNE + lumaSE;
+    float lumaNWNE = lumaNW + lumaNE;
+    float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;
+    float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;
+/*--------------------------------------------------------------------------*/
+    float lumaNWSW = lumaNW + lumaSW;
+    float lumaSWSE = lumaSW + lumaSE;
+    float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);
+    float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);
+    float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;
+    float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;
+    float edgeHorz = abs(edgeHorz3) + edgeHorz4;
+    float edgeVert = abs(edgeVert3) + edgeVert4;
+/*--------------------------------------------------------------------------*/
+    float subpixNWSWNESE = lumaNWSW + lumaNESE;
+    float lengthSign = fxaaQualityRcpFrame.x;
+    bool horzSpan = edgeHorz >= edgeVert;
+    float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;
+/*--------------------------------------------------------------------------*/
+    if(!horzSpan) lumaN = lumaW;
+    if(!horzSpan) lumaS = lumaE;
+    if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;
+    float subpixB = (subpixA * (1.0/12.0)) - lumaM;
+/*--------------------------------------------------------------------------*/
+    float gradientN = lumaN - lumaM;
+    float gradientS = lumaS - lumaM;
+    float lumaNN = lumaN + lumaM;
+    float lumaSS = lumaS + lumaM;
+    bool pairN = abs(gradientN) >= abs(gradientS);
+    float gradient = max(abs(gradientN), abs(gradientS));
+    if(pairN) lengthSign = -lengthSign;
+    float subpixC = clamp((abs(subpixB) * subpixRcpRange), 0.0, 1.0);
+/*--------------------------------------------------------------------------*/
+    vec2 posB;
+    posB.x = posM.x;
+    posB.y = posM.y;
+    vec2 offNP;
+    offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
+    offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
+    if(!horzSpan) posB.x += lengthSign * 0.5;
+    if( horzSpan) posB.y += lengthSign * 0.5;
+/*--------------------------------------------------------------------------*/
+    vec2 posN;
+    posN.x = posB.x - offNP.x * FXAA_QUALITY_P0;
+    posN.y = posB.y - offNP.y * FXAA_QUALITY_P0;
+    vec2 posP;
+    posP.x = posB.x + offNP.x * FXAA_QUALITY_P0;
+    posP.y = posB.y + offNP.y * FXAA_QUALITY_P0;
+    float subpixD = ((-2.0)*subpixC) + 3.0;
+    float lumaEndN = LumaTop(tex, posN);
+    float subpixE = subpixC * subpixC;
+    float lumaEndP = LumaTop(tex, posP);
+/*--------------------------------------------------------------------------*/
+    if(!pairN) lumaNN = lumaSS;
+    float gradientScaled = gradient * 1.0/4.0;
+    float lumaMM = lumaM - lumaNN * 0.5;
+    float subpixF = subpixD * subpixE;
+    bool lumaMLTZero = lumaMM < 0.0;
+/*--------------------------------------------------------------------------*/
+    lumaEndN -= lumaNN * 0.5;
+    lumaEndP -= lumaNN * 0.5;
+    bool doneN = abs(lumaEndN) >= gradientScaled;
+    bool doneP = abs(lumaEndP) >= gradientScaled;
+    if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P1;
+    if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P1;
+    bool doneNP = (!doneN) || (!doneP);
+    if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P1;
+    if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P1;
+/*--------------------------------------------------------------------------*/
+    if(doneNP) {
+        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+        doneN = abs(lumaEndN) >= gradientScaled;
+        doneP = abs(lumaEndP) >= gradientScaled;
+        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P2;
+        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P2;
+        doneNP = (!doneN) || (!doneP);
+        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P2;
+        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P2;
+/*--------------------------------------------------------------------------*/
+        #if (FXAA_QUALITY_PS > 3)
+        if(doneNP) {
+            if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+            if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+            if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+            if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+            doneN = abs(lumaEndN) >= gradientScaled;
+            doneP = abs(lumaEndP) >= gradientScaled;
+            if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P3;
+            if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P3;
+            doneNP = (!doneN) || (!doneP);
+            if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P3;
+            if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P3;
+/*--------------------------------------------------------------------------*/
+            #if (FXAA_QUALITY_PS > 4)
+            if(doneNP) {
+                if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                doneN = abs(lumaEndN) >= gradientScaled;
+                doneP = abs(lumaEndP) >= gradientScaled;
+                if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P4;
+                if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P4;
+                doneNP = (!doneN) || (!doneP);
+                if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P4;
+                if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P4;
+/*--------------------------------------------------------------------------*/
+                #if (FXAA_QUALITY_PS > 5)
+                if(doneNP) {
+                    if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                    if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                    if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                    if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                    doneN = abs(lumaEndN) >= gradientScaled;
+                    doneP = abs(lumaEndP) >= gradientScaled;
+                    if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P5;
+                    if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P5;
+                    doneNP = (!doneN) || (!doneP);
+                    if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P5;
+                    if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P5;
+/*--------------------------------------------------------------------------*/
+                    #if (FXAA_QUALITY_PS > 6)
+                    if(doneNP) {
+                        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                        doneN = abs(lumaEndN) >= gradientScaled;
+                        doneP = abs(lumaEndP) >= gradientScaled;
+                        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P6;
+                        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P6;
+                        doneNP = (!doneN) || (!doneP);
+                        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P6;
+                        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P6;
+/*--------------------------------------------------------------------------*/
+                        #if (FXAA_QUALITY_PS > 7)
+                        if(doneNP) {
+                            if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                            if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                            if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                            if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                            doneN = abs(lumaEndN) >= gradientScaled;
+                            doneP = abs(lumaEndP) >= gradientScaled;
+                            if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P7;
+                            if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P7;
+                            doneNP = (!doneN) || (!doneP);
+                            if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P7;
+                            if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P7;
+/*--------------------------------------------------------------------------*/
+    #if (FXAA_QUALITY_PS > 8)
+    if(doneNP) {
+        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+        doneN = abs(lumaEndN) >= gradientScaled;
+        doneP = abs(lumaEndP) >= gradientScaled;
+        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P8;
+        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P8;
+        doneNP = (!doneN) || (!doneP);
+        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P8;
+        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P8;
+/*--------------------------------------------------------------------------*/
+        #if (FXAA_QUALITY_PS > 9)
+        if(doneNP) {
+            if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+            if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+            if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+            if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+            doneN = abs(lumaEndN) >= gradientScaled;
+            doneP = abs(lumaEndP) >= gradientScaled;
+            if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P9;
+            if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P9;
+            doneNP = (!doneN) || (!doneP);
+            if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P9;
+            if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P9;
+/*--------------------------------------------------------------------------*/
+            #if (FXAA_QUALITY_PS > 10)
+            if(doneNP) {
+                if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                doneN = abs(lumaEndN) >= gradientScaled;
+                doneP = abs(lumaEndP) >= gradientScaled;
+                if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P10;
+                if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P10;
+                doneNP = (!doneN) || (!doneP);
+                if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P10;
+                if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P10;
+/*--------------------------------------------------------------------------*/
+                #if (FXAA_QUALITY_PS > 11)
+                if(doneNP) {
+                    if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                    if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                    if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                    if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                    doneN = abs(lumaEndN) >= gradientScaled;
+                    doneP = abs(lumaEndP) >= gradientScaled;
+                    if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P11;
+                    if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P11;
+                    doneNP = (!doneN) || (!doneP);
+                    if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P11;
+                    if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P11;
+/*--------------------------------------------------------------------------*/
+                    #if (FXAA_QUALITY_PS > 12)
+                    if(doneNP) {
+                        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                        doneN = abs(lumaEndN) >= gradientScaled;
+                        doneP = abs(lumaEndP) >= gradientScaled;
+                        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P12;
+                        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P12;
+                        doneNP = (!doneN) || (!doneP);
+                        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P12;
+                        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P12;
+/*--------------------------------------------------------------------------*/
+                    }
+                    #endif
+/*--------------------------------------------------------------------------*/
+                }
+                #endif
+/*--------------------------------------------------------------------------*/
+            }
+            #endif
+/*--------------------------------------------------------------------------*/
+        }
+        #endif
+/*--------------------------------------------------------------------------*/
+    }
+    #endif
+/*--------------------------------------------------------------------------*/
+                        }
+                        #endif
+/*--------------------------------------------------------------------------*/
+                    }
+                    #endif
+/*--------------------------------------------------------------------------*/
+                }
+                #endif
+/*--------------------------------------------------------------------------*/
+            }
+            #endif
+/*--------------------------------------------------------------------------*/
+        }
+        #endif
+/*--------------------------------------------------------------------------*/
+    }
+/*--------------------------------------------------------------------------*/
+    float dstN = posM.x - posN.x;
+    float dstP = posP.x - posM.x;
+    if(!horzSpan) dstN = posM.y - posN.y;
+    if(!horzSpan) dstP = posP.y - posM.y;
+/*--------------------------------------------------------------------------*/
+    bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;
+    float spanLength = (dstP + dstN);
+    bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;
+    float spanLengthRcp = 1.0/spanLength;
+/*--------------------------------------------------------------------------*/
+    bool directionN = dstN < dstP;
+    float dst = min(dstN, dstP);
+    bool goodSpan = directionN ? goodSpanN : goodSpanP;
+    float subpixG = subpixF * subpixF;
+    float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;
+    float subpixH = subpixG * fxaaQualitySubpix;
+/*--------------------------------------------------------------------------*/
+    float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;
+    float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);
+    if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;
+    if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;
+    return FxaaTexTop(tex, posM);
+}
+/*==========================================================================*/
+
+/*============================================================================
+
+                      Urho3D Vertex- and Pixelshader
+                      
+============================================================================*/
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    vec2 rcpFrame = vec2(cGBufferInvSize.x, cGBufferInvSize.y);
+
+    gl_FragColor = FxaaPixelShader(
+        vScreenPos,                         // vec2 pos,
+        sDiffMap,                           // sampler2D tex,
+        rcpFrame,                           // vec2 fxaaQualityRcpFrame,
+        0.75,                               // float fxaaQualitySubpix,
+        0.166,                              // float fxaaQualityEdgeThreshold,
+        0.0833                              // float fxaaQualityEdgeThresholdMin
+    );
+}
+

+ 24 - 0
Bin/CoreData/Shaders/GLSL/Fog.glsl

@@ -0,0 +1,24 @@
+#ifdef COMPILEPS
+vec3 GetFog(vec3 color, float fogFactor)
+{
+    return mix(cFogColor, color, fogFactor);
+}
+
+vec3 GetLitFog(vec3 color, float fogFactor)
+{
+    return color * fogFactor;
+}
+
+float GetFogFactor(float depth)
+{
+    return clamp((cFogParams.x - depth) * cFogParams.y, 0.0, 1.0);
+}
+
+float GetHeightFogFactor(float depth, float height)
+{
+    float fogFactor = GetFogFactor(depth);
+    float heightFogFactor = (height - cFogParams.z) * cFogParams.w;
+    heightFogFactor = 1.0 - clamp(exp(-(heightFogFactor * heightFogFactor)), 0.0, 1.0);
+    return min(heightFogFactor, fogFactor);
+}
+#endif

+ 21 - 0
Bin/CoreData/Shaders/GLSL/GammaCorrection.glsl

@@ -0,0 +1,21 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "PostProcess.glsl"
+
+varying vec2 vScreenPos;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    vec3 color = texture2D(sDiffMap, vScreenPos).rgb;
+    gl_FragColor = vec4(ToInverseGamma(color), 1.0);
+}

+ 22 - 0
Bin/CoreData/Shaders/GLSL/GreyScale.glsl

@@ -0,0 +1,22 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Lighting.glsl"
+
+varying vec2 vScreenPos;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    vec3 rgb = texture2D(sDiffMap, vScreenPos).rgb;
+    float intensity = GetIntensity(rgb);
+    gl_FragColor = vec4(intensity, intensity, intensity, 1.0);
+}

+ 22 - 0
Bin/CoreData/Shaders/GLSL/Light2D.glsl

@@ -0,0 +1,22 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec2 vTexCoord;
+varying vec4 vColor;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    
+    vTexCoord = iTexCoord;
+    vColor = iColor * vTexCoord.x;
+}
+
+void PS()
+{
+	gl_FragColor.rgba = vColor;
+}
+

+ 262 - 0
Bin/CoreData/Shaders/GLSL/Lighting.glsl

@@ -0,0 +1,262 @@
+#ifdef COMPILEVS
+vec3 GetAmbient(float zonePos)
+{
+    return cAmbientStartColor + zonePos * cAmbientEndColor;
+}
+
+#ifdef NUMVERTEXLIGHTS
+float GetVertexLight(int index, vec3 worldPos, vec3 normal)
+{
+    vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
+    vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
+    float invRange = cVertexLights[index * 3].w;
+    float cutoff = cVertexLights[index * 3 + 1].w;
+    float invCutoff = cVertexLights[index * 3 + 2].w;
+
+    // Directional light
+    if (invRange == 0.0)
+    {
+        float NdotL = max(dot(normal, lightDir), 0.0);
+        return NdotL;
+    }
+    // Point/spot light
+    else
+    {
+        vec3 lightVec = (lightPos - worldPos) * invRange;
+        float lightDist = length(lightVec);
+        vec3 localDir = lightVec / lightDist;
+        float NdotL = max(dot(normal, localDir), 0.0);
+        float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
+        float spotEffect = dot(localDir, lightDir);
+        float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
+        return NdotL * atten * spotAtten;
+    }
+}
+
+float GetVertexLightVolumetric(int index, vec3 worldPos)
+{
+    vec3 lightDir = cVertexLights[index * 3 + 1].xyz;
+    vec3 lightPos = cVertexLights[index * 3 + 2].xyz;
+    float invRange = cVertexLights[index * 3].w;
+    float cutoff = cVertexLights[index * 3 + 1].w;
+    float invCutoff = cVertexLights[index * 3 + 2].w;
+
+    // Directional light
+    if (invRange == 0.0)
+        return 1.0;
+    // Point/spot light
+    else
+    {
+        vec3 lightVec = (lightPos - worldPos) * invRange;
+        float lightDist = length(lightVec);
+        vec3 localDir = lightVec / lightDist;
+        float atten = clamp(1.0 - lightDist * lightDist, 0.0, 1.0);
+        float spotEffect = dot(localDir, lightDir);
+        float spotAtten = clamp((spotEffect - cutoff) * invCutoff, 0.0, 1.0);
+        return atten * spotAtten;
+    }
+}
+#endif
+
+#ifdef SHADOW
+
+#if defined(DIRLIGHT) && !defined(GL_ES)
+    #define NUMCASCADES 4
+#else
+    #define NUMCASCADES 1
+#endif
+
+vec4 GetShadowPos(int index, vec4 projWorldPos)
+{
+    #if defined(DIRLIGHT)
+        return cLightMatrices[index] * projWorldPos;
+    #elif defined(SPOTLIGHT)
+        return cLightMatrices[1] * projWorldPos;
+    #else
+        return vec4(projWorldPos.xyz - cLightPos.xyz, 1.0);
+    #endif
+}
+
+#endif
+#endif
+
+#ifdef COMPILEPS
+float GetDiffuse(vec3 normal, vec3 worldPos, out vec3 lightDir)
+{
+    #ifdef DIRLIGHT
+        lightDir = cLightDirPS;
+        return max(dot(normal, lightDir), 0.0);
+    #else
+        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+        float lightDist = length(lightVec);
+        lightDir = lightVec / lightDist;
+        return max(dot(normal, lightDir), 0.0) * texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
+    #endif
+}
+
+float GetDiffuseVolumetric(vec3 worldPos)
+{
+    #ifdef DIRLIGHT
+        return 1.0;
+    #else
+        vec3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+        float lightDist = length(lightVec);
+        return texture2D(sLightRampMap, vec2(lightDist, 0.0)).r;
+    #endif
+}
+
+float GetSpecular(vec3 normal, vec3 eyeVec, vec3 lightDir, float specularPower)
+{
+    vec3 halfVec = normalize(normalize(eyeVec) + lightDir);
+    return pow(max(dot(normal, halfVec), 0.0), specularPower);
+}
+
+float GetIntensity(vec3 color)
+{
+    return dot(color, vec3(0.333));
+}
+
+#ifdef SHADOW
+
+#if defined(DIRLIGHT) && !defined(GL_ES)
+    #define NUMCASCADES 4
+#else
+    #define NUMCASCADES 1
+#endif
+
+float GetShadow(vec4 shadowPos)
+{
+    #ifndef GL_ES
+        #ifndef LQSHADOW
+            // Take four samples and average them
+            // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
+            #ifndef POINTLIGHT
+                vec2 offsets = cShadowMapInvSize * shadowPos.w;
+            #else
+                vec2 offsets = cShadowMapInvSize;
+            #endif
+            vec4 inLight = vec4(
+                shadow2DProj(sShadowMap, shadowPos).r,
+                shadow2DProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)).r,
+                shadow2DProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r,
+                shadow2DProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)).r
+            );
+            return cShadowIntensity.y + dot(inLight, vec4(cShadowIntensity.x));
+        #else
+            // Take one sample
+            float inLight = shadow2DProj(sShadowMap, shadowPos).r;
+            return cShadowIntensity.y + cShadowIntensity.x * inLight;
+        #endif
+    #else
+        #ifndef LQSHADOW
+            // Take four samples and average them
+            vec2 offsets = cShadowMapInvSize * shadowPos.w;
+            vec4 inLight = vec4(
+                texture2DProj(sShadowMap, shadowPos).r * shadowPos.w > shadowPos.z,
+                texture2DProj(sShadowMap, vec4(shadowPos.x + offsets.x, shadowPos.yzw)).r * shadowPos.w > shadowPos.z,
+                texture2DProj(sShadowMap, vec4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r * shadowPos.w > shadowPos.z,
+                texture2DProj(sShadowMap, vec4(shadowPos.xy + offsets.xy, shadowPos.zw)).r * shadowPos.w > shadowPos.z
+            );
+            return cShadowIntensity.y + dot(inLight, vec4(cShadowIntensity.x));
+        #else
+            // Take one sample
+            return cShadowIntensity.y + (texture2DProj(sShadowMap, shadowPos).r * shadowPos.w > shadowPos.z ? cShadowIntensity.x : 0.0);
+        #endif
+    #endif
+}
+
+#ifdef POINTLIGHT
+float GetPointShadow(vec3 lightVec)
+{
+    vec3 axis = textureCube(sFaceSelectCubeMap, lightVec).rgb;
+    float depth = abs(dot(lightVec, axis));
+
+    // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
+    // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
+    // case filtering across faces is wrong
+    const vec3 factor = vec3(1.0 / 256.0);
+    lightVec += factor * axis * lightVec;
+
+    // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
+    vec4 indirectPos = textureCube(sIndirectionCubeMap, lightVec);
+    indirectPos.xy *= cShadowCubeAdjust.xy;
+    indirectPos.xy += vec2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
+
+    vec4 shadowPos = vec4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
+    return GetShadow(shadowPos);
+}
+#endif
+
+#ifdef DIRLIGHT
+float GetDirShadowFade(float inLight, float depth)
+{
+    return min(inLight + max((depth - cShadowDepthFade.z) * cShadowDepthFade.w, 0.0), 1.0);
+}
+
+#ifndef GL_ES
+float GetDirShadow(const vec4 iShadowPos[NUMCASCADES], float depth)
+{
+    vec4 shadowPos;
+
+    if (depth < cShadowSplits.x)
+        shadowPos = iShadowPos[0];
+    else if (depth < cShadowSplits.y)
+        shadowPos = iShadowPos[1];
+    else if (depth < cShadowSplits.z)
+        shadowPos = iShadowPos[2];
+    else
+        shadowPos = iShadowPos[3];
+        
+    return GetDirShadowFade(GetShadow(shadowPos), depth);
+}
+
+float GetDirShadowDeferred(vec4 projWorldPos, float depth)
+{
+    vec4 shadowPos;
+
+    if (depth < cShadowSplits.x)
+        shadowPos = cLightMatricesPS[0] * projWorldPos;
+    else if (depth < cShadowSplits.y)
+        shadowPos = cLightMatricesPS[1] * projWorldPos;
+    else if (depth < cShadowSplits.z)
+        shadowPos = cLightMatricesPS[2] * projWorldPos;
+    else
+        shadowPos = cLightMatricesPS[3] * projWorldPos;
+
+    return GetDirShadowFade(GetShadow(shadowPos), depth);
+}
+#else
+float GetDirShadow(const vec4 iShadowPos[NUMCASCADES], float depth)
+{
+    return GetDirShadowFade(GetShadow(iShadowPos[0]), depth);
+}
+#endif
+#endif
+
+float GetShadow(vec4 iShadowPos[NUMCASCADES], float depth)
+{
+    #if defined(DIRLIGHT)
+        return GetDirShadow(iShadowPos, depth);
+    #elif defined(SPOTLIGHT)
+        return GetShadow(iShadowPos[0]);
+    #else
+        return GetPointShadow(iShadowPos[0].xyz);
+    #endif
+}
+
+#ifndef GL_ES
+float GetShadowDeferred(vec4 projWorldPos, float depth)
+{
+    #if defined(DIRLIGHT)
+        return GetDirShadowDeferred(projWorldPos, depth);
+    #elif defined(SPOTLIGHT)
+        vec4 shadowPos = cLightMatricesPS[1] * projWorldPos;
+        return GetShadow(shadowPos);
+    #else
+        vec3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
+        return GetPointShadow(shadowPos);
+    #endif
+}
+#endif
+#endif
+#endif

+ 120 - 0
Bin/CoreData/Shaders/GLSL/LitParticle.glsl

@@ -0,0 +1,120 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "Lighting.glsl"
+#include "Fog.glsl"
+
+varying vec2 vTexCoord;
+varying vec4 vWorldPos;
+#ifdef VERTEXCOLOR
+    varying vec4 vColor;
+#endif
+#ifdef PERPIXEL
+    #ifdef SHADOW
+        varying vec4 vShadowPos[NUMCASCADES];
+    #endif
+    #ifdef SPOTLIGHT
+        varying vec4 vSpotPos;
+    #endif
+    #ifdef POINTLIGHT
+        varying vec3 vCubeMaskVec;
+    #endif
+#else
+    varying vec3 vVertexLight;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetTexCoord(iTexCoord);
+    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
+
+    #ifdef VERTEXCOLOR
+        vColor = iColor;
+    #endif
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        vec4 projWorldPos = vec4(worldPos, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            for (int i = 0; i < NUMCASCADES; i++)
+                vShadowPos[i] = GetShadowPos(i, projWorldPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            vSpotPos = cLightMatrices[0] * projWorldPos;
+        #endif
+    
+        #ifdef POINTLIGHT
+            vCubeMaskVec = mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz) * (worldPos - cLightPos.xyz);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        vVertexLight = GetAmbient(GetZonePos(worldPos));
+
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                vVertexLight += GetVertexLightVolumetric(i, worldPos) * cVertexLights[i * 3].rgb;
+        #endif
+    #endif
+}
+
+void PS()
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        vec4 diffInput = texture2D(sDiffMap, vTexCoord);
+        #ifdef ALPHAMASK
+            if (diffInput.a < 0.5)
+                discard;
+        #endif
+        vec4 diffColor = cMatDiffColor * diffInput;
+    #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
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        vec3 lightColor;
+        vec3 lightDir;
+        vec3 finalColor;
+
+        float diff = GetDiffuseVolumetric(vWorldPos.xyz);
+
+        #ifdef SHADOW
+            diff *= GetShadow(vShadowPos, vWorldPos.w);
+        #endif
+    
+        #if defined(SPOTLIGHT)
+            lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
+        #elif defined(CUBEMASK)
+            lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;
+        #else
+            lightColor = cLightColor.rgb;
+        #endif
+
+        finalColor = diff * lightColor * diffColor.rgb;
+        gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);
+    #else
+        // Ambient & per-vertex lighting
+        vec3 finalColor = vVertexLight * diffColor.rgb;
+
+        gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
+    #endif
+}

+ 232 - 0
Bin/CoreData/Shaders/GLSL/LitSolid.glsl

@@ -0,0 +1,232 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Lighting.glsl"
+#include "Fog.glsl"
+
+#ifdef NORMALMAP
+    varying vec4 vTexCoord;
+    varying vec4 vTangent;
+#else
+    varying vec2 vTexCoord;
+#endif
+varying vec3 vNormal;
+varying vec4 vWorldPos;
+#ifdef PERPIXEL
+    #ifdef SHADOW
+        varying vec4 vShadowPos[NUMCASCADES];
+    #endif
+    #ifdef SPOTLIGHT
+        varying vec4 vSpotPos;
+    #endif
+    #ifdef POINTLIGHT
+        varying vec3 vCubeMaskVec;
+    #endif
+#else
+    varying vec3 vVertexLight;
+    varying vec4 vScreenPos;
+    #ifdef ENVCUBEMAP
+        varying vec3 vReflectionVec;
+    #endif
+    #if defined(LIGHTMAP) || defined(AO)
+        varying vec2 vTexCoord2;
+    #endif
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vNormal = GetWorldNormal(modelMatrix);
+    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
+
+    #ifdef NORMALMAP
+        vec3 tangent = GetWorldTangent(modelMatrix);
+        vec3 bitangent = cross(tangent, vNormal) * iTangent.w;
+        vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
+        vTangent = vec4(tangent, bitangent.z);
+    #else
+        vTexCoord = GetTexCoord(iTexCoord);
+    #endif
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        vec4 projWorldPos = vec4(worldPos, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            for (int i = 0; i < NUMCASCADES; i++)
+                vShadowPos[i] = GetShadowPos(i, projWorldPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            vSpotPos = cLightMatrices[0] * projWorldPos;
+        #endif
+    
+        #ifdef POINTLIGHT
+            vCubeMaskVec = mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz) * (worldPos - cLightPos.xyz);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        #if defined(LIGHTMAP) || defined(AO)
+            // If using lightmap, disregard zone ambient light
+            // If using AO, calculate ambient in the PS
+            vVertexLight = vec3(0.0, 0.0, 0.0);
+            vTexCoord2 = GetLightMapTexCoord(iTexCoord2);
+        #else
+            vVertexLight = GetAmbient(GetZonePos(worldPos));
+        #endif
+        
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
+        #endif
+        
+        vScreenPos = GetScreenPos(gl_Position);
+
+        #ifdef ENVCUBEMAP
+            vReflectionVec = worldPos - cCameraPos;
+        #endif
+    #endif
+}
+
+void PS()
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        vec4 diffInput = texture2D(sDiffMap, vTexCoord.xy);
+        #ifdef ALPHAMASK
+            if (diffInput.a < 0.5)
+                discard;
+        #endif
+        vec4 diffColor = cMatDiffColor * diffInput;
+    #else
+        vec4 diffColor = cMatDiffColor;
+    #endif
+    
+    // Get material specular albedo
+    #ifdef SPECMAP
+        vec3 specColor = cMatSpecColor.rgb * texture2D(sSpecMap, vTexCoord.xy).rgb;
+    #else
+        vec3 specColor = cMatSpecColor.rgb;
+    #endif
+
+    // Get normal
+    #ifdef NORMALMAP
+        mat3 tbn = mat3(vTangent.xyz, vec3(vTexCoord.zw, vTangent.w), vNormal);
+        vec3 normal = normalize(tbn * DecodeNormal(texture2D(sNormalMap, vTexCoord.xy)));
+    #else
+        vec3 normal = normalize(vNormal);
+    #endif
+
+    // Get fog factor
+    #ifdef HEIGHTFOG
+        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
+    #else
+        float fogFactor = GetFogFactor(vWorldPos.w);
+    #endif
+
+    #if defined(PERPIXEL)
+        // Per-pixel forward lighting
+        vec3 lightColor;
+        vec3 lightDir;
+        vec3 finalColor;
+
+        float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
+
+        #ifdef SHADOW
+            diff *= GetShadow(vShadowPos, vWorldPos.w);
+        #endif
+    
+        #if defined(SPOTLIGHT)
+            lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
+        #elif defined(CUBEMASK)
+            lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;
+        #else
+            lightColor = cLightColor.rgb;
+        #endif
+    
+        #ifdef SPECULAR
+            float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);
+            finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
+        #else
+            finalColor = diff * lightColor * diffColor.rgb;
+        #endif
+
+        #ifdef AMBIENT
+            finalColor += cAmbientColor * diffColor.rgb;
+            finalColor += cMatEmissiveColor;
+            gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
+        #else
+            gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);
+        #endif
+    #elif defined(PREPASS)
+        // Fill light pre-pass G-Buffer
+        float specPower = cMatSpecColor.a / 255.0;
+
+        gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);
+        gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
+    #elif defined(DEFERRED)
+        // Fill deferred G-buffer
+        float specIntensity = specColor.g;
+        float specPower = cMatSpecColor.a / 255.0;
+
+        vec3 finalColor = vVertexLight * diffColor.rgb;
+        #ifdef AO
+            // If using AO, the vertex light ambient is black, calculate occluded ambient here
+            finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * cAmbientColor * diffColor.rgb;
+        #endif
+
+        #ifdef ENVCUBEMAP
+            finalColor += cMatEnvMapColor * textureCube(sEnvCubeMap, reflect(vReflectionVec, normal)).rgb;
+        #endif
+        #ifdef LIGHTMAP
+            finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * diffColor.rgb;
+        #endif
+        #ifdef EMISSIVEMAP
+            finalColor += cMatEmissiveColor * texture2D(sEmissiveMap, vTexCoord.xy).rgb;
+        #else
+            finalColor += cMatEmissiveColor;
+        #endif
+
+        gl_FragData[0] = vec4(GetFog(finalColor, fogFactor), 1.0);
+        gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);
+        gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);
+        gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
+    #else
+        // Ambient & per-vertex lighting
+        vec3 finalColor = vVertexLight * diffColor.rgb;
+        #ifdef AO
+            // If using AO, the vertex light ambient is black, calculate occluded ambient here
+            finalColor += texture2D(sEmissiveMap, vTexCoord2).rgb * cAmbientColor * diffColor.rgb;
+        #endif
+        
+        #ifdef MATERIAL
+            // Add light pre-pass accumulation result
+            // Lights are accumulated at half intensity. Bring back to full intensity now
+            vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);
+            vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);
+
+            finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
+        #endif
+
+        #ifdef ENVCUBEMAP
+            finalColor += cMatEnvMapColor * textureCube(sEnvCubeMap, reflect(vReflectionVec, normal)).rgb;
+        #endif
+        #ifdef LIGHTMAP
+            // Lightmap with HDR encoded in alpha
+            vec4 lightMapColor = texture2D(sEmissiveMap, vTexCoord2);
+            finalColor += lightMapColor.rgb * lightMapColor.a * 8.0 * diffColor.rgb;
+        #endif
+        #ifdef EMISSIVEMAP
+            finalColor += cMatEmissiveColor * texture2D(sEmissiveMap, vTexCoord.xy).rgb;
+        #else
+            finalColor += cMatEmissiveColor;
+        #endif
+
+        gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
+    #endif
+}

+ 87 - 0
Bin/CoreData/Shaders/GLSL/PostProcess.glsl

@@ -0,0 +1,87 @@
+#ifdef COMPILEPS
+const float PI = 3.14159265;
+
+vec2 Noise(vec2 coord)
+{
+    float noiseX = clamp(fract(sin(dot(coord, vec2(12.9898, 78.233))) * 43758.5453), 0.0, 1.0);
+    float noiseY = clamp(fract(sin(dot(coord, vec2(12.9898, 78.233) * 2.0)) * 43758.5453), 0.0, 1.0);
+    return vec2(noiseX, noiseY);
+}
+
+// Adapted: http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
+vec4 GaussianBlur(int blurKernelSize, vec2 blurDir, vec2 blurRadius, float sigma, sampler2D texSampler, vec2 texCoord)
+{
+    int blurKernelSizeHalfSize = blurKernelSize / 2;
+
+    // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
+    vec3 gaussCoeff;
+    gaussCoeff.x = 1.0 / (sqrt(2.0 * PI) * sigma);
+    gaussCoeff.y = exp(-0.5 / (sigma * sigma));
+    gaussCoeff.z = gaussCoeff.y * gaussCoeff.y;
+
+    vec2 blurVec = blurRadius * blurDir;
+    vec4 avgValue = vec4(0.0);
+    float gaussCoeffSum = 0.0;
+
+    avgValue += texture2D(texSampler, texCoord) * gaussCoeff.x;
+    gaussCoeffSum += gaussCoeff.x;
+    gaussCoeff.xy *= gaussCoeff.yz;
+
+    for (int i = 1; i <= blurKernelSizeHalfSize; i++)
+    {
+        avgValue += texture2D(texSampler, texCoord - float(i) * blurVec) * gaussCoeff.x;
+        avgValue += texture2D(texSampler, texCoord + float(i) * blurVec) * gaussCoeff.x;
+
+        gaussCoeffSum += 2.0 * gaussCoeff.x;
+        gaussCoeff.xy *= gaussCoeff.yz;
+    }
+
+    return avgValue / gaussCoeffSum;
+}
+
+const vec3 LumWeights = vec3(0.2126, 0.7152, 0.0722);
+
+vec3 ReinhardEq3Tonemap(vec3 x)
+{
+    return x / (1.0 + x);
+}
+
+vec3 ReinhardEq4Tonemap(vec3 x, float white)
+{
+    return x * (1.0 + x / white) / (1.0 + x);
+}
+
+// Unchared2 tone mapping (See http://filmicgames.com)
+const float A = 0.15;
+const float B = 0.50;
+const float C = 0.10;
+const float D = 0.20;
+const float E = 0.02;
+const float F = 0.30;
+
+vec3 Uncharted2Tonemap(vec3 x)
+{
+   return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
+}
+
+vec3 ColorCorrection(vec3 color, sampler3D lut)
+{
+    float lutSize = 16.0;
+    float scale = (lutSize - 1.0) / lutSize;
+    float offset = 1.0 / (2.0 * lutSize);
+    return texture3D(lut, clamp(color, 0.0, 1.0) * scale + offset).rgb;
+}
+
+const float Gamma = 2.2;
+const float InverseGamma = 1.0 / 2.2;
+
+vec3 ToGamma(vec3 color)
+{
+    return vec3(pow(color.r, Gamma), pow(color.g, Gamma), pow(color.b, Gamma));
+}
+
+vec3 ToInverseGamma(vec3 color)
+{
+    return vec3(pow(color.r, InverseGamma), pow(color.g, InverseGamma), pow(color.b, InverseGamma));
+}
+#endif

+ 94 - 0
Bin/CoreData/Shaders/GLSL/PrepassLight.glsl

@@ -0,0 +1,94 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Lighting.glsl"
+
+#ifdef DIRLIGHT
+    varying vec2 vScreenPos;
+#else
+    varying vec4 vScreenPos;
+#endif
+varying vec3 vFarRay;
+#ifdef ORTHO
+    varying vec3 vNearRay;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    #ifdef DIRLIGHT
+        vScreenPos = GetScreenPosPreDiv(gl_Position);
+        vFarRay = GetFarRay(gl_Position);
+        #ifdef ORTHO
+            vNearRay = GetNearRay(gl_Position);
+        #endif
+    #else
+        vScreenPos = GetScreenPos(gl_Position);
+        vFarRay = GetFarRay(gl_Position) * gl_Position.w;
+        #ifdef ORTHO
+            vNearRay = GetNearRay(gl_Position) * gl_Position.w;
+        #endif
+    #endif
+}
+
+void PS()
+{
+    // If rendering a directional light quad, optimize out the w divide
+    #ifdef DIRLIGHT
+        #ifdef HWDEPTH
+            float depth = ReconstructDepth(texture2D(sDepthBuffer, vScreenPos).r);
+        #else
+            float depth = DecodeDepth(texture2D(sDepthBuffer, vScreenPos).rgb);
+        #endif
+        #ifdef ORTHO
+            vec3 worldPos = mix(vNearRay, vFarRay, depth);
+        #else
+            vec3 worldPos = vFarRay * depth;
+        #endif
+        vec4 normalInput = texture2D(sNormalBuffer, vScreenPos);
+    #else
+        #ifdef HWDEPTH
+            float depth = ReconstructDepth(texture2DProj(sDepthBuffer, vScreenPos).r);
+        #else
+            float depth = DecodeDepth(texture2DProj(sDepthBuffer, vScreenPos).rgb);
+        #endif
+        #ifdef ORTHO
+            vec3 worldPos = mix(vNearRay, vFarRay, depth) / vScreenPos.w;
+        #else
+            vec3 worldPos = vFarRay * depth / vScreenPos.w;
+        #endif
+        vec4 normalInput = texture2DProj(sNormalBuffer, vScreenPos);
+    #endif
+
+    vec3 normal = normalize(normalInput.rgb * 2.0 - 1.0);
+    vec4 projWorldPos = vec4(worldPos, 1.0);
+    vec3 lightColor;
+    vec3 lightDir;
+
+    // Accumulate light at half intensity to allow 2x "overburn"
+    float diff = 0.5 * GetDiffuse(normal, worldPos, lightDir);
+
+    #ifdef SHADOW
+        diff *= GetShadowDeferred(projWorldPos, depth);
+    #endif
+    
+    #if defined(SPOTLIGHT)
+        vec4 spotPos = cLightMatricesPS[0] * projWorldPos;
+        lightColor = spotPos.w > 0.0 ? texture2DProj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : vec3(0.0);
+    #elif defined(CUBEMASK)
+        mat3 lightVecRot = mat3(cLightMatricesPS[0][0].xyz, cLightMatricesPS[0][1].xyz, cLightMatricesPS[0][2].xyz);
+        lightColor = textureCube(sLightCubeMap, lightVecRot * (worldPos - cLightPosPS.xyz)).rgb * cLightColor.rgb;
+    #else
+        lightColor = cLightColor.rgb;
+    #endif
+
+    #ifdef SPECULAR
+        float spec = lightColor.g * GetSpecular(normal, -worldPos, lightDir, normalInput.a * 255.0);
+        gl_FragColor = diff * vec4(lightColor, spec * cLightColor.a);
+    #else
+        gl_FragColor = diff * vec4(lightColor, 0.0);
+    #endif
+}

+ 20 - 0
Bin/CoreData/Shaders/GLSL/ProcSky.glsl

@@ -0,0 +1,20 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec3 EyeV;
+
+void VS() 
+{
+    EyeV = iNormal;
+    gl_Position = iPos;
+}
+
+void PS()
+{
+    vec3 V = normalize( EyeV ) + vec3(0,.2,0);
+    vec2 lt = vec2( (1.0 + normalize( V.xz ).y) / 2.0, 1.0 - normalize( V ).y );
+    gl_FragColor = texture2D( sDiffMap, lt );
+
+}
+

+ 61 - 0
Bin/CoreData/Shaders/GLSL/Samplers.glsl

@@ -0,0 +1,61 @@
+#ifdef COMPILEPS
+uniform sampler2D sDiffMap;
+uniform samplerCube sDiffCubeMap;
+uniform sampler2D sNormalMap;
+uniform sampler2D sSpecMap;
+uniform sampler2D sEmissiveMap;
+uniform sampler2D sEnvMap;
+uniform samplerCube sEnvCubeMap;
+uniform sampler2D sLightRampMap;
+uniform sampler2D sLightSpotMap;
+uniform samplerCube sLightCubeMap;
+#ifndef GL_ES
+    uniform sampler3D sVolumeMap;
+    uniform sampler2D sAlbedoBuffer;
+    uniform sampler2D sNormalBuffer;
+    uniform sampler2D sDepthBuffer;
+    uniform sampler2D sLightBuffer;
+    uniform sampler2DShadow sShadowMap;
+    uniform samplerCube sFaceSelectCubeMap;
+    uniform samplerCube sIndirectionCubeMap;
+    uniform samplerCube sZoneCubeMap;
+    uniform sampler3D sZoneVolumeMap;
+#else
+    uniform sampler2D sShadowMap;
+#endif
+
+vec3 DecodeNormal(vec4 normalInput)
+{
+    #ifdef PACKEDNORMAL
+        vec3 normal;
+        normal.xy = normalInput.ag * 2.0 - 1.0;
+        normal.z = sqrt(max(1.0 - dot(normal.xy, normal.xy), 0.0));
+        return normal;
+    #else
+        return normalize(normalInput.rgb * 2.0 - 1.0);
+    #endif
+}
+
+vec3 EncodeDepth(float depth)
+{
+    vec3 ret;
+    depth *= 255.0;
+    ret.x = floor(depth);
+    depth = (depth - ret.x) * 255.0;
+    ret.y = floor(depth);
+    ret.z = (depth - ret.y);
+    ret.xy *= 1.0 / 255.0;
+    return ret;
+}
+
+float DecodeDepth(vec3 depth)
+{
+    const vec3 dotValues = vec3(1.0, 1.0 / 255.0, 1.0 / (255.0 * 255.0));
+    return dot(depth, dotValues);
+}
+
+float ReconstructDepth(float hwDepth)
+{
+    return dot(vec2(hwDepth, cDepthReconstruct.y / (hwDepth - cDepthReconstruct.x)), cDepthReconstruct.zw);
+}
+#endif

+ 51 - 0
Bin/CoreData/Shaders/GLSL/ScreenPos.glsl

@@ -0,0 +1,51 @@
+#ifdef COMPILEVS
+vec4 GetScreenPos(vec4 clipPos)
+{
+    return vec4(
+        clipPos.x * cGBufferOffsets.z + cGBufferOffsets.x * clipPos.w,
+        clipPos.y * cGBufferOffsets.w + cGBufferOffsets.y * clipPos.w,
+        0.0,
+        clipPos.w);
+}
+
+vec2 GetScreenPosPreDiv(vec4 clipPos)
+{
+    return vec2(
+        clipPos.x / clipPos.w * cGBufferOffsets.z + cGBufferOffsets.x,
+        clipPos.y / clipPos.w * cGBufferOffsets.w + cGBufferOffsets.y);
+}
+
+vec2 GetQuadTexCoord(vec4 clipPos)
+{
+    return vec2(
+        clipPos.x / clipPos.w * 0.5 + 0.5,
+        clipPos.y / clipPos.w * 0.5 + 0.5);
+}
+
+vec2 GetQuadTexCoordNoFlip(vec3 worldPos)
+{
+    return vec2(
+        worldPos.x * 0.5 + 0.5,
+        -worldPos.y * 0.5 + 0.5);
+}
+
+vec3 GetFarRay(vec4 clipPos)
+{
+    vec3 viewRay = vec3(
+        clipPos.x / clipPos.w * cFrustumSize.x,
+        clipPos.y / clipPos.w * cFrustumSize.y,
+        cFrustumSize.z);
+
+    return cCameraRot * viewRay;
+}
+
+vec3 GetNearRay(vec4 clipPos)
+{
+    vec3 viewRay = vec3(
+        clipPos.x / clipPos.w * cFrustumSize.x,
+        clipPos.y / clipPos.w * cFrustumSize.y,
+        0.0);
+    
+    return (cCameraRot * viewRay) * cDepthMode.x;
+}
+#endif

+ 24 - 0
Bin/CoreData/Shaders/GLSL/Shadow.glsl

@@ -0,0 +1,24 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec2 vTexCoord;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetTexCoord(iTexCoord);
+}
+
+void PS()
+{
+    #ifdef ALPHAMASK
+        float alpha = texture2D(sDiffMap, vTexCoord).a;
+        if (alpha < 0.5)
+            discard;
+    #endif
+
+    gl_FragColor = vec4(1.0);
+}

+ 26 - 0
Bin/CoreData/Shaders/GLSL/Shadow2D.glsl

@@ -0,0 +1,26 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform vec4 cShadowAmbient;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+	vec4 diffInput = texture2D(sDiffMap, vScreenPos);
+	vec4 lightInput = texture2D(sEmissiveMap, vScreenPos);
+	gl_FragColor.rgb =  (diffInput.rgb * (lightInput.rgb + cShadowAmbient.rgb) * (lightInput.a + cShadowAmbient.a));    
+}
+

+ 25 - 0
Bin/CoreData/Shaders/GLSL/Skybox.glsl

@@ -0,0 +1,25 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec3 vTexCoord;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+
+    #ifndef GL_ES
+    gl_Position.z = gl_Position.w;
+    #else
+    // On OpenGL ES force Z slightly in front of far plane to avoid clipping artifacts due to inaccuracy
+    gl_Position.z = 0.999 * gl_Position.w;
+    #endif
+    vTexCoord = iPos.xyz;
+}
+
+void PS()
+{
+    gl_FragColor = cMatDiffColor * textureCube(sDiffCubeMap, vTexCoord);
+}

+ 15 - 0
Bin/CoreData/Shaders/GLSL/Stencil.glsl

@@ -0,0 +1,15 @@
+#include "Uniforms.glsl"
+#include "Transform.glsl"
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+}
+
+void PS()
+{
+    gl_FragColor = vec4(1.0);
+}
+

+ 181 - 0
Bin/CoreData/Shaders/GLSL/TerrainBlend.glsl

@@ -0,0 +1,181 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Lighting.glsl"
+#include "Fog.glsl"
+
+varying vec2 vTexCoord;
+varying vec2 vDetailTexCoord;
+varying vec3 vNormal;
+varying vec4 vWorldPos;
+#ifdef PERPIXEL
+    #ifdef SHADOW
+        varying vec4 vShadowPos[NUMCASCADES];
+    #endif
+    #ifdef SPOTLIGHT
+        varying vec4 vSpotPos;
+    #endif
+    #ifdef POINTLIGHT
+        varying vec3 vCubeMaskVec;
+    #endif
+#else
+    varying vec3 vVertexLight;
+    varying vec4 vScreenPos;
+    #ifdef ENVCUBEMAP
+        varying vec3 vReflectionVec;
+    #endif
+    #if defined(LIGHTMAP) || defined(AO)
+        varying vec2 vTexCoord2;
+    #endif
+#endif
+
+uniform sampler2D sWeightMap0;
+uniform sampler2D sDetailMap1;
+uniform sampler2D sDetailMap2;
+uniform sampler2D sDetailMap3;
+
+uniform vec2 cDetailTiling;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vNormal = GetWorldNormal(modelMatrix);
+    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
+    vTexCoord = GetTexCoord(iTexCoord);
+    vDetailTexCoord = cDetailTiling * vTexCoord;
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        vec4 projWorldPos = vec4(worldPos, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            for (int i = 0; i < NUMCASCADES; i++)
+                vShadowPos[i] = GetShadowPos(i, projWorldPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            vSpotPos = cLightMatrices[0] * projWorldPos;
+        #endif
+    
+        #ifdef POINTLIGHT
+            vCubeMaskVec = mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz) * (worldPos - cLightPos.xyz);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        #if defined(LIGHTMAP) || defined(AO)
+            // If using lightmap, disregard zone ambient light
+            // If using AO, calculate ambient in the PS
+            vVertexLight = vec3(0.0, 0.0, 0.0);
+            vTexCoord2 = iTexCoord2;
+        #else
+            vVertexLight = GetAmbient(GetZonePos(worldPos));
+        #endif
+        
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
+        #endif
+        
+        vScreenPos = GetScreenPos(gl_Position);
+
+        #ifdef ENVCUBEMAP
+            vReflectionVec = worldPos - cCameraPos;
+        #endif
+    #endif
+}
+
+void PS()
+{
+    // Get material diffuse albedo
+    vec3 weights = texture2D(sWeightMap0, vTexCoord).rgb;
+    float sumWeights = weights.r + weights.g + weights.b;
+    weights /= sumWeights;
+    vec4 diffColor = cMatDiffColor * (
+        weights.r * texture2D(sDetailMap1, vDetailTexCoord) +
+        weights.g * texture2D(sDetailMap2, vDetailTexCoord) + 
+        weights.b * texture2D(sDetailMap3, vDetailTexCoord)
+    );
+
+    // Get material specular albedo
+    vec3 specColor = cMatSpecColor.rgb;
+
+    // Get normal
+    vec3 normal = normalize(vNormal);
+
+    // Get fog factor
+    #ifdef HEIGHTFOG
+        float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
+    #else
+        float fogFactor = GetFogFactor(vWorldPos.w);
+    #endif
+
+    #if defined(PERPIXEL)
+        // Per-pixel forward lighting
+        vec3 lightColor;
+        vec3 lightDir;
+        vec3 finalColor;
+        
+        float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
+
+        #ifdef SHADOW
+            diff *= GetShadow(vShadowPos, vWorldPos.w);
+        #endif
+    
+        #if defined(SPOTLIGHT)
+            lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
+        #elif defined(CUBEMASK)
+            lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;
+        #else
+            lightColor = cLightColor.rgb;
+        #endif
+    
+        #ifdef SPECULAR
+            float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);
+            finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
+        #else
+            finalColor = diff * lightColor * diffColor.rgb;
+        #endif
+
+        #ifdef AMBIENT
+            finalColor += cAmbientColor * diffColor.rgb;
+            finalColor += cMatEmissiveColor;
+            gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
+        #else
+            gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);
+        #endif
+    #elif defined(PREPASS)
+        // Fill light pre-pass G-Buffer
+        float specPower = cMatSpecColor.a / 255.0;
+
+        gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);
+        gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
+    #elif defined(DEFERRED)
+        // Fill deferred G-buffer
+        float specIntensity = specColor.g;
+        float specPower = cMatSpecColor.a / 255.0;
+
+        gl_FragData[0] = vec4(GetFog(vVertexLight * diffColor.rgb, fogFactor), 1.0);
+        gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);
+        gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);
+        gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
+    #else
+        // Ambient & per-vertex lighting
+        vec3 finalColor = vVertexLight * diffColor.rgb;
+
+        #ifdef MATERIAL
+            // Add light pre-pass accumulation result
+            // Lights are accumulated at half intensity. Bring back to full intensity now
+            vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);
+            vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);
+
+            finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
+        #endif
+
+        gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
+    #endif
+}

+ 59 - 0
Bin/CoreData/Shaders/GLSL/Text.glsl

@@ -0,0 +1,59 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+
+varying vec2 vTexCoord;
+varying vec4 vColor;
+
+#ifdef TEXT_EFFECT_SHADOW
+uniform vec2 cShadowOffset;
+uniform vec4 cShadowColor;
+#endif
+
+#ifdef TEXT_EFFECT_STROKE
+uniform vec4 cStrokeColor;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    
+    vTexCoord = iTexCoord;
+    vColor = iColor;
+}
+
+void PS()
+{
+    gl_FragColor.rgb = vColor.rgb;
+
+#ifdef SIGNED_DISTANCE_FIELD
+    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;
+    }
+    else
+    {
+    #ifdef TEXT_EFFECT_STROKE
+        if (distance < 0.525)
+            gl_FragColor.rgb = cStrokeColor.rgb;
+    #endif
+
+    #ifdef TEXT_EFFECT_SHADOW
+        if (texture2D(sDiffMap, vTexCoord + cShadowOffset).a < 0.5)
+            gl_FragColor.a = vColor.a;
+        else
+    #endif
+        gl_FragColor.a = vColor.a * smoothstep(0.5, 0.505, distance);
+    }
+#else
+    gl_FragColor.a = vColor.a * texture2D(sDiffMap, vTexCoord).a;
+#endif
+}

+ 40 - 0
Bin/CoreData/Shaders/GLSL/Tonemap.glsl

@@ -0,0 +1,40 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "PostProcess.glsl"
+
+varying vec2 vScreenPos;
+
+#ifdef COMPILEPS
+uniform float cTonemapExposureBias;
+uniform float cTonemapMaxWhite;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPosPreDiv(gl_Position);
+}
+
+void PS()
+{
+    #ifdef REINHARDEQ3
+    vec3 color = ReinhardEq3Tonemap(max(texture2D(sDiffMap, vScreenPos).rgb * cTonemapExposureBias, 0.0));
+    gl_FragColor = vec4(color, 1.0);
+    #endif
+
+    #ifdef REINHARDEQ4
+    vec3 color = ReinhardEq4Tonemap(max(texture2D(sDiffMap, vScreenPos).rgb * cTonemapExposureBias, 0.0), cTonemapMaxWhite);
+    gl_FragColor = vec4(color, 1.0);
+    #endif
+
+    #ifdef UNCHARTED2
+    vec3 color = Uncharted2Tonemap(max(texture2D(sDiffMap, vScreenPos).rgb * cTonemapExposureBias, 0.0)) / 
+        Uncharted2Tonemap(vec3(cTonemapMaxWhite, cTonemapMaxWhite, cTonemapMaxWhite));
+    gl_FragColor = vec4(color, 1.0);
+    #endif
+}
+

+ 124 - 0
Bin/CoreData/Shaders/GLSL/Transform.glsl

@@ -0,0 +1,124 @@
+#ifdef COMPILEVS
+attribute vec4 iPos;
+attribute vec3 iNormal;
+attribute vec4 iColor;
+attribute vec2 iTexCoord;
+attribute vec2 iTexCoord2;
+attribute vec4 iTangent;
+attribute vec4 iBlendWeights;
+attribute vec4 iBlendIndices;
+attribute vec3 iCubeTexCoord;
+attribute vec4 iCubeTexCoord2;
+#ifndef GL_ES
+    attribute vec4 iInstanceMatrix1;
+    attribute vec4 iInstanceMatrix2;
+    attribute vec4 iInstanceMatrix3;
+#endif
+
+#ifdef SKINNED
+mat4 GetSkinMatrix(vec4 blendWeights, vec4 blendIndices)
+{
+    ivec4 idx = ivec4(blendIndices) * 3;
+    const vec4 lastColumn = vec4(0.0, 0.0, 0.0, 1.0);
+    return mat4(cSkinMatrices[idx.x], cSkinMatrices[idx.x + 1], cSkinMatrices[idx.x + 2], lastColumn) * blendWeights.x +
+        mat4(cSkinMatrices[idx.y], cSkinMatrices[idx.y + 1], cSkinMatrices[idx.y + 2], lastColumn) * blendWeights.y +
+        mat4(cSkinMatrices[idx.z], cSkinMatrices[idx.z + 1], cSkinMatrices[idx.z + 2], lastColumn) * blendWeights.z +
+        mat4(cSkinMatrices[idx.w], cSkinMatrices[idx.w + 1], cSkinMatrices[idx.w + 2], lastColumn) * blendWeights.w;
+}
+#endif
+
+#ifdef INSTANCED
+mat4 GetInstanceMatrix()
+{
+    const vec4 lastColumn = vec4(0.0, 0.0, 0.0, 1.0);
+    return mat4(iInstanceMatrix1, iInstanceMatrix2, iInstanceMatrix3, lastColumn);
+}
+#endif
+
+mat3 GetNormalMatrix(mat4 modelMatrix)
+{
+    return mat3(modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz);
+}
+
+vec2 GetTexCoord(vec2 texCoord)
+{
+    return vec2(dot(texCoord, cUOffset.xy) + cUOffset.w, dot(texCoord, cVOffset.xy) + cVOffset.w);
+}
+
+vec2 GetLightMapTexCoord(vec2 texCoord)
+{
+    return vec2(texCoord.x * cLMOffset.x + cLMOffset.z, texCoord.y * cLMOffset.y + cLMOffset.w);
+}
+
+vec4 GetClipPos(vec3 worldPos)
+{
+    vec4 ret = cViewProj * vec4(worldPos, 1.0);
+    // While getting the clip coordinate, also automatically set gl_ClipVertex for user clip planes
+    #ifndef GL_ES
+    gl_ClipVertex = ret;
+    #endif
+    return ret;
+}
+
+float GetZonePos(vec3 worldPos)
+{
+    return clamp((cZone * vec4(worldPos, 1.0)).z, 0.0, 1.0);
+}
+
+float GetDepth(vec4 clipPos)
+{
+    return dot(clipPos.zw, cDepthMode.zw);
+}
+
+vec3 GetBillboardPos(vec4 iPos, vec2 iSize, mat4 modelMatrix)
+{
+    return (modelMatrix * iPos).xyz + cBillboardRot * vec3(iSize.x, iSize.y, 0.0);
+}
+
+vec3 GetBillboardNormal()
+{
+    return vec3(-cBillboardRot[2][0], -cBillboardRot[2][1], -cBillboardRot[2][2]);
+}
+
+// Note: the skinning/instancing model matrix is a transpose, so the matrix multiply order must be swapped
+// (see GetWorldPos(), GetWorldNormal() and GetWorldTangent() below)
+#if defined(SKINNED)
+    #define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices)
+#elif defined(INSTANCED)
+    #define iModelMatrix GetInstanceMatrix();
+#else
+    #define iModelMatrix cModel
+#endif
+
+vec3 GetWorldPos(mat4 modelMatrix)
+{
+    #if defined(SKINNED) || defined(INSTANCED)
+        return (iPos * modelMatrix).xyz;
+    #elif defined(BILLBOARD)
+        return GetBillboardPos(iPos, iTexCoord2, modelMatrix);
+    #else
+        return (modelMatrix * iPos).xyz;
+    #endif
+}
+
+vec3 GetWorldNormal(mat4 modelMatrix)
+{
+    #if defined(SKINNED) || defined(INSTANCED)
+        return normalize(iNormal * GetNormalMatrix(modelMatrix));
+    #elif defined(BILLBOARD)
+        return GetBillboardNormal();
+    #else
+        return normalize(GetNormalMatrix(modelMatrix) * iNormal);
+    #endif
+}
+
+vec3 GetWorldTangent(mat4 modelMatrix)
+{   
+    mat3 normalMatrix = GetNormalMatrix(modelMatrix);
+    #if defined(SKINNED) || defined(INSTANCED)
+        return normalize(iTangent.xyz * normalMatrix);
+    #else
+        return normalize(normalMatrix * iTangent.xyz);
+    #endif
+}
+#endif

+ 67 - 0
Bin/CoreData/Shaders/GLSL/Uniforms.glsl

@@ -0,0 +1,67 @@
+#ifdef COMPILEVS
+uniform vec3 cAmbientStartColor;
+uniform vec3 cAmbientEndColor;
+uniform mat3 cBillboardRot;
+uniform vec3 cCameraPos;
+uniform mat3 cCameraRot;
+uniform float cNearClip;
+uniform float cFarClip;
+uniform vec4 cDepthMode;
+uniform vec3 cFrustumSize;
+uniform float cDeltaTime;
+uniform float cElapsedTime;
+uniform vec4 cGBufferOffsets;
+uniform vec3 cLightDir;
+uniform vec4 cLightPos;
+uniform mat4 cModel;
+uniform mat4 cViewProj;
+uniform vec4 cUOffset;
+uniform vec4 cVOffset;
+uniform vec4 cLMOffset;
+uniform mat4 cZone;
+#ifndef GL_ES
+    uniform mat4 cLightMatrices[4];
+#else
+    uniform mat4 cLightMatrices[2];
+#endif
+#ifdef SKINNED
+    #ifdef RPI
+        uniform vec4 cSkinMatrices[32*3];
+    #else
+        uniform vec4 cSkinMatrices[64*3];
+    #endif
+#endif
+#ifdef NUMVERTEXLIGHTS
+    uniform vec4 cVertexLights[4*3];
+#endif
+#endif
+
+#ifdef COMPILEPS
+#ifdef GL_ES
+    precision mediump float;
+#endif
+
+uniform vec3 cAmbientColor;
+uniform vec3 cCameraPosPS;
+uniform float cDeltaTimePS;
+uniform vec4 cDepthReconstruct;
+uniform float cElapsedTimePS;
+uniform vec4 cFogParams;
+uniform vec3 cFogColor;
+uniform vec2 cGBufferInvSize;
+uniform vec4 cLightColor;
+uniform vec3 cLightDirPS;
+uniform vec4 cLightPosPS;
+uniform vec4 cMatDiffColor;
+uniform vec3 cMatEmissiveColor;
+uniform vec3 cMatEnvMapColor;
+uniform vec4 cMatSpecColor;
+uniform float cNearClipPS;
+uniform float cFarClipPS;
+uniform vec4 cShadowCubeAdjust;
+uniform vec4 cShadowDepthFade;
+uniform vec2 cShadowIntensity;
+uniform vec2 cShadowMapInvSize;
+uniform vec4 cShadowSplits;
+uniform mat4 cLightMatricesPS[4];
+#endif

+ 62 - 0
Bin/CoreData/Shaders/GLSL/Unlit.glsl

@@ -0,0 +1,62 @@
+#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
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetTexCoord(iTexCoord);
+    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
+
+    #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
+
+    #if defined(PREPASS)
+        // Fill light pre-pass G-Buffer
+        gl_FragData[0] = vec4(0.5, 0.5, 0.5, 1.0);
+        gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
+    #elif defined(DEFERRED)
+        gl_FragData[0] = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
+        gl_FragData[1] = vec4(0.0, 0.0, 0.0, 0.0);
+        gl_FragData[2] = vec4(0.5, 0.5, 0.5, 1.0);
+        gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
+    #else
+        gl_FragColor = vec4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
+    #endif
+}

+ 104 - 0
Bin/CoreData/Shaders/GLSL/Vegetation.glsl

@@ -0,0 +1,104 @@
+#include "Uniforms.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Lighting.glsl"
+
+uniform float cWindHeightFactor;
+uniform float cWindHeightPivot;
+uniform float cWindPeriod;
+uniform vec2 cWindWorldSpacing;
+
+#ifdef NORMALMAP
+    varying vec4 vTexCoord;
+    varying vec4 vTangent;
+#else
+    varying vec2 vTexCoord;
+#endif
+varying vec3 vNormal;
+varying vec4 vWorldPos;
+#ifdef PERPIXEL
+    #ifdef SHADOW
+        varying vec4 vShadowPos[NUMCASCADES];
+    #endif
+    #ifdef SPOTLIGHT
+        varying vec4 vSpotPos;
+    #endif
+    #ifdef POINTLIGHT
+        varying vec3 vCubeMaskVec;
+    #endif
+#else
+    varying vec3 vVertexLight;
+    varying vec4 vScreenPos;
+    #ifdef ENVCUBEMAP
+        varying vec3 vReflectionVec;
+    #endif
+    #if defined(LIGHTMAP) || defined(AO)
+        varying vec2 vTexCoord2;
+    #endif
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    float height = worldPos.y - cModel[3][1];
+
+    float windStrength = max(height - cWindHeightPivot, 0.0) * cWindHeightFactor;
+    float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
+    worldPos.x += windStrength * sin(windPeriod);
+    worldPos.z -= windStrength * cos(windPeriod);
+
+    gl_Position = GetClipPos(worldPos);
+    vNormal = GetWorldNormal(modelMatrix);
+    vWorldPos = vec4(worldPos, GetDepth(gl_Position));
+
+    #ifdef NORMALMAP
+        vec3 tangent = GetWorldTangent(modelMatrix);
+        vec3 bitangent = cross(tangent, vNormal) * iTangent.w;
+        vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
+        vTangent = vec4(tangent, bitangent.z);
+    #else
+        vTexCoord = GetTexCoord(iTexCoord);
+    #endif
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        vec4 projWorldPos = vec4(worldPos, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            for (int i = 0; i < NUMCASCADES; i++)
+                vShadowPos[i] = GetShadowPos(i, projWorldPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            vSpotPos = cLightMatrices[0] * projWorldPos;
+        #endif
+    
+        #ifdef POINTLIGHT
+            vCubeMaskVec = mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz) * (worldPos - cLightPos.xyz);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        #if defined(LIGHTMAP) || defined(AO)
+            // If using lightmap, disregard zone ambient light
+            // If using AO, calculate ambient in the PS
+            vVertexLight = vec3(0.0, 0.0, 0.0);
+            vTexCoord2 = iTexCoord2;
+        #else
+            vVertexLight = GetAmbient(GetZonePos(worldPos));
+        #endif
+        
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
+        #endif
+        
+        vScreenPos = GetScreenPos(gl_Position);
+
+        #ifdef ENVCUBEMAP
+            vReflectionVec = worldPos - cCameraPos;
+        #endif
+    #endif
+}

+ 24 - 0
Bin/CoreData/Shaders/GLSL/VegetationDepth.glsl

@@ -0,0 +1,24 @@
+#include "Uniforms.glsl"
+#include "Transform.glsl"
+
+uniform float cWindHeightFactor;
+uniform float cWindHeightPivot;
+uniform float cWindPeriod;
+uniform vec2 cWindWorldSpacing;
+
+varying vec3 vTexCoord;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    
+    float windStrength = max(iPos.y - cWindHeightPivot, 0.0) * cWindHeightFactor;
+    float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
+    worldPos.x += windStrength * sin(windPeriod);
+    worldPos.z -= windStrength * cos(windPeriod);
+
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = vec3(GetTexCoord(iTexCoord), GetDepth(gl_Position));
+}
+

+ 24 - 0
Bin/CoreData/Shaders/GLSL/VegetationShadow.glsl

@@ -0,0 +1,24 @@
+#include "Uniforms.glsl"
+#include "Transform.glsl"
+
+uniform float cWindHeightFactor;
+uniform float cWindHeightPivot;
+uniform float cWindPeriod;
+uniform vec2 cWindWorldSpacing;
+
+varying vec2 vTexCoord;
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    
+    float windStrength = max(iPos.y - cWindHeightPivot, 0.0) * cWindHeightFactor;
+    float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
+    worldPos.x += windStrength * sin(windPeriod);
+    worldPos.z -= windStrength * cos(windPeriod);
+
+    gl_Position = GetClipPos(worldPos);
+    vTexCoord = GetTexCoord(iTexCoord);
+}
+

+ 59 - 0
Bin/CoreData/Shaders/GLSL/Water.glsl

@@ -0,0 +1,59 @@
+#include "Uniforms.glsl"
+#include "Samplers.glsl"
+#include "Transform.glsl"
+#include "ScreenPos.glsl"
+#include "Fog.glsl"
+
+varying vec4 vScreenPos;
+varying vec2 vReflectUV;
+varying vec2 vWaterUV;
+varying vec3 vNormal;
+varying vec4 vEyeVec;
+
+#ifdef COMPILEVS
+uniform vec2 cNoiseSpeed;
+uniform float cNoiseTiling;
+#endif
+#ifdef COMPILEPS
+uniform float cNoiseStrength;
+uniform float cFresnelPower;
+uniform vec3 cWaterTint;
+#endif
+
+void VS()
+{
+    mat4 modelMatrix = iModelMatrix;
+    vec3 worldPos = GetWorldPos(modelMatrix);
+    gl_Position = GetClipPos(worldPos);
+    vScreenPos = GetScreenPos(gl_Position);
+    // GetQuadTexCoord() returns a vec2 that is OK for quad rendering; multiply it with output W
+    // coordinate to make it work with arbitrary meshes such as the water plane (perform divide in pixel shader)
+    // Also because the quadTexCoord is based on the clip position, and Y is flipped when rendering to a texture
+    // on OpenGL, must flip again to cancel it out
+    vReflectUV = GetQuadTexCoord(gl_Position);
+    vReflectUV.y = 1.0 - vReflectUV.y;
+    vReflectUV *= gl_Position.w;
+    vWaterUV = iTexCoord * cNoiseTiling + cElapsedTime * cNoiseSpeed;
+    vNormal = GetWorldNormal(modelMatrix);
+    vEyeVec = vec4(cCameraPos - worldPos, GetDepth(gl_Position));
+}
+
+void PS()
+{
+    vec2 refractUV = vScreenPos.xy / vScreenPos.w;
+    vec2 reflectUV = vReflectUV.xy / vScreenPos.w;
+
+    vec2 noise = (texture2D(sNormalMap, vWaterUV).rg - 0.5) * cNoiseStrength;
+    refractUV += noise;
+    // Do not shift reflect UV coordinate upward, because it will reveal the clipping of geometry below water
+    if (noise.y < 0.0)
+        noise.y = 0.0;
+    reflectUV += noise;
+
+    float fresnel = pow(1.0 - clamp(dot(normalize(vEyeVec.xyz), vNormal), 0.0, 1.0), cFresnelPower);
+    vec3 refractColor = texture2D(sEnvMap, refractUV).rgb * cWaterTint;
+    vec3 reflectColor = texture2D(sDiffMap, reflectUV).rgb;
+    vec3 finalColor = mix(refractColor, reflectColor, fresnel);
+
+    gl_FragColor = vec4(GetFog(finalColor, GetFogFactor(vEyeVec.w)), 1.0);
+}

+ 27 - 0
Bin/CoreData/Shaders/HLSL/Atomic2D.hlsl

@@ -0,0 +1,27 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+void VS(float4 iPos : POSITION,
+    float2 iTexCoord : TEXCOORD0,
+    float4 iColor : COLOR0,
+    out float4 oColor : COLOR0,
+    out float2 oTexCoord : TEXCOORD0,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+
+    oColor = iColor;
+    oTexCoord = iTexCoord;
+}
+
+void PS(float4 iColor : COLOR0,
+        float2 iTexCoord : TEXCOORD0,
+        out float4 oColor : COLOR0)
+{
+    float4 diffColor = cMatDiffColor * iColor;
+    float4 diffInput = tex2D(sDiffMap, iTexCoord);
+    oColor = diffColor * diffInput;
+}

+ 95 - 0
Bin/CoreData/Shaders/HLSL/AutoExposure.hlsl

@@ -0,0 +1,95 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+#include "PostProcess.hlsl"
+
+uniform float cAutoExposureAdaptRate;
+uniform float2 cAutoExposureLumRange;
+uniform float cAutoExposureMiddleGrey;
+uniform float2 cHDR128Offsets;
+uniform float2 cLum64Offsets;
+uniform float2 cLum16Offsets;
+uniform float2 cLum4Offsets;
+uniform float2 cHDR128InvSize;
+uniform float2 cLum64InvSize;
+uniform float2 cLum16InvSize;
+uniform float2 cLum4InvSize;
+
+float GatherAvgLum(sampler2D texSampler, float2 texCoord, float2 texelSize)
+{
+    float lumAvg = 0.0;
+    lumAvg += tex2D(texSampler, texCoord + float2(0.0, 0.0) * texelSize).r;
+    lumAvg += tex2D(texSampler, texCoord + float2(0.0, 2.0) * texelSize).r;
+    lumAvg += tex2D(texSampler, texCoord + float2(2.0, 2.0) * texelSize).r;
+    lumAvg += tex2D(texSampler, texCoord + float2(2.0, 0.0) * texelSize).r;
+    return lumAvg / 4.0;
+}
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oTexCoord : TEXCOORD0,
+    out float2 oScreenPos : TEXCOORD1)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+
+    oTexCoord = GetQuadTexCoord(oPos);
+
+    #ifdef LUMINANCE64
+    oTexCoord = GetQuadTexCoord(oPos) + cHDR128Offsets;
+    #endif
+
+    #ifdef LUMINANCE16
+    oTexCoord = GetQuadTexCoord(oPos) + cLum64Offsets;
+    #endif
+
+    #ifdef LUMINANCE4
+    oTexCoord = GetQuadTexCoord(oPos) + cLum16Offsets;
+    #endif
+
+    #ifdef LUMINANCE1
+    oTexCoord = GetQuadTexCoord(oPos) + cLum4Offsets;
+    #endif
+
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float2 iScreenPos : TEXCOORD1,
+    out float4 oColor : COLOR0)
+{
+    #ifdef LUMINANCE64
+    float logLumSum = 0.0;
+    logLumSum += log(dot(tex2D(sDiffMap, iTexCoord + float2(0.0, 0.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    logLumSum += log(dot(tex2D(sDiffMap, iTexCoord + float2(0.0, 2.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    logLumSum += log(dot(tex2D(sDiffMap, iTexCoord + float2(2.0, 2.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    logLumSum += log(dot(tex2D(sDiffMap, iTexCoord + float2(2.0, 0.0) * cHDR128InvSize).rgb, LumWeights) + 1e-5);
+    oColor = logLumSum;
+    #endif
+
+    #ifdef LUMINANCE16
+    oColor = GatherAvgLum(sDiffMap, iTexCoord, cLum64InvSize);
+    #endif
+
+    #ifdef LUMINANCE4
+    oColor = GatherAvgLum(sDiffMap, iTexCoord, cLum16InvSize);
+    #endif
+
+    #ifdef LUMINANCE1
+    oColor = exp(GatherAvgLum(sDiffMap, iTexCoord, cLum4InvSize) / 16.0);
+    #endif
+
+    #ifdef ADAPTLUMINANCE
+    float adaptedLum = tex2D(sDiffMap, iTexCoord).r;
+    float lum = clamp(tex2D(sNormalMap, iTexCoord).r, cAutoExposureLumRange.x, cAutoExposureLumRange.y);
+    oColor = adaptedLum + (lum - adaptedLum) * (1.0 - exp(-cDeltaTimePS * cAutoExposureAdaptRate));
+    #endif
+
+    #ifdef EXPOSE
+    float3 color = tex2D(sDiffMap, iScreenPos).rgb;
+    float adaptedLum = tex2D(sNormalMap, iTexCoord).r;
+    oColor = float4(color * (cAutoExposureMiddleGrey / adaptedLum), 1.0);
+    #endif
+}

+ 70 - 0
Bin/CoreData/Shaders/HLSL/Basic.hlsl

@@ -0,0 +1,70 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+void VS(float4 iPos : POSITION,
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    #ifdef BILLBOARD
+        float2 iSize : TEXCOORD1,
+    #endif
+    #ifdef DIFFMAP
+        float2 iTexCoord : TEXCOORD0,
+    #endif
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+        out float4 oColor : COLOR0,
+    #endif
+    #ifdef DIFFMAP
+        out float2 oTexCoord : TEXCOORD0,
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+
+    #ifdef VERTEXCOLOR
+        oColor = iColor;
+    #endif
+    #ifdef DIFFMAP
+        oTexCoord = iTexCoord;
+    #endif
+}
+
+void PS(
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    #if defined(DIFFMAP) || defined(ALPHAMAP)
+        float2 iTexCoord : TEXCOORD0,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    float4 diffColor = cMatDiffColor;
+
+    #ifdef VERTEXCOLOR
+        diffColor *= iColor;
+    #endif
+
+    #if (!defined(DIFFMAP)) && (!defined(ALPHAMAP))
+        oColor = diffColor;
+    #endif
+    #ifdef DIFFMAP
+        float4 diffInput = tex2D(sDiffMap, iTexCoord);
+        #ifdef ALPHAMASK
+            if (diffInput.a < 0.5)
+                discard;
+        #endif
+        oColor = diffColor * diffInput;
+    #endif
+    #ifdef ALPHAMAP
+        float alphaInput = tex2D(sDiffMap, iTexCoord).a;
+        oColor = float4(diffColor.rgb, diffColor.a * alphaInput);
+    #endif
+}

+ 69 - 0
Bin/CoreData/Shaders/HLSL/Bloom.hlsl

@@ -0,0 +1,69 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+
+uniform float cBloomThreshold;
+uniform float2 cBloomMix;
+uniform float2 cHBlurOffsets;
+uniform float2 cHBlurInvSize;
+
+static const float offsets[5] = {
+    2.0,
+    1.0,
+    0.0,
+    -1.0,
+    -2.0,
+};
+
+static const float weights[5] = {
+    0.1,
+    0.25,
+    0.3,
+    0.25,
+    0.1
+};
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oTexCoord : TEXCOORD0,
+    out float2 oScreenPos : TEXCOORD1)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetQuadTexCoord(oPos) + cHBlurOffsets;
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float2 iScreenPos : TEXCOORD1,
+    out float4 oColor : COLOR0)
+{
+    #ifdef BRIGHT
+    float3 rgb = tex2D(sDiffMap, iScreenPos).rgb;
+    oColor = float4((rgb - cBloomThreshold) / (1.0 - cBloomThreshold), 1.0);
+    #endif
+
+    #ifdef HBLUR
+    float3 rgb = 0.0;
+    for (int i = 0; i < 5; ++i)
+        rgb += tex2D(sDiffMap, iTexCoord + (float2(offsets[i], 0.0)) * cHBlurInvSize).rgb * weights[i];
+    oColor = float4(rgb, 1.0);
+    #endif
+
+    #ifdef VBLUR
+    float3 rgb = 0.0;
+    for (int i = 0; i < 5; ++i)
+        rgb += tex2D(sDiffMap, iTexCoord + (float2(0.0, offsets[i])) * cHBlurInvSize).rgb * weights[i];
+    oColor = float4(rgb, 1.0);
+    #endif
+
+    #ifdef COMBINE
+    float3 original = tex2D(sDiffMap, iScreenPos).rgb * cBloomMix.x;
+    float3 bloom = tex2D(sNormalMap, iTexCoord).rgb  * cBloomMix.y;
+    // Prevent oversaturation
+    original *= saturate(1.0 - bloom);
+    oColor = float4(original + bloom, 1.0);
+    #endif
+}

+ 111 - 0
Bin/CoreData/Shaders/HLSL/BloomHDR.hlsl

@@ -0,0 +1,111 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+#include "PostProcess.hlsl"
+
+uniform float cBloomHDRThreshold;
+uniform float2 cBloomHDRBlurDir;
+uniform float cBloomHDRBlurRadius;
+uniform float cBloomHDRBlurSigma;
+uniform float2 cBloomHDRMix;
+uniform float2 cBright2Offsets;
+uniform float2 cBright4Offsets;
+uniform float2 cBright8Offsets;
+uniform float2 cBright16Offsets;
+uniform float2 cBright2InvSize;
+uniform float2 cBright4InvSize;
+uniform float2 cBright8InvSize;
+uniform float2 cBright16InvSize;
+
+static const int BlurKernelSize = 5;
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oTexCoord : TEXCOORD0,
+    out float2 oScreenPos : TEXCOORD1)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+
+    oTexCoord = GetQuadTexCoord(oPos);
+
+    #ifdef BLUR2
+    oTexCoord = GetQuadTexCoord(oPos) + cBright2Offsets;
+    #endif
+
+    #ifdef BLUR4
+    oTexCoord = GetQuadTexCoord(oPos) + cBright4Offsets;
+    #endif
+
+    #ifdef BLUR8
+    oTexCoord = GetQuadTexCoord(oPos) + cBright8Offsets;
+    #endif
+
+    #ifdef BLUR16
+    oTexCoord = GetQuadTexCoord(oPos) + cBright16Offsets;
+    #endif
+
+    #ifdef COMBINE2
+    oTexCoord = GetQuadTexCoord(oPos) + cBright2Offsets;
+    #endif
+
+    #ifdef COMBINE4
+    oTexCoord = GetQuadTexCoord(oPos) + cBright4Offsets;
+    #endif
+
+    #ifdef COMBINE8
+    oTexCoord = GetQuadTexCoord(oPos) + cBright8Offsets;
+    #endif
+
+    #ifdef COMBINE16
+    oTexCoord = GetQuadTexCoord(oPos) + cBright16Offsets;
+    #endif
+
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float2 iScreenPos : TEXCOORD1,
+    out float4 oColor : COLOR0)
+{
+    #ifdef BRIGHT
+    float3 color = tex2D(sDiffMap, iScreenPos).rgb;
+    oColor = float4(max(color - cBloomHDRThreshold, 0.0), 1.0);
+    #endif
+
+    #ifdef BLUR16
+    oColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright16InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef BLUR8
+    oColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright8InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef BLUR4
+    oColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright4InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef BLUR2
+    oColor = GaussianBlur(BlurKernelSize, cBloomHDRBlurDir, cBright2InvSize * cBloomHDRBlurRadius, cBloomHDRBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef COMBINE16
+    oColor = tex2D(sDiffMap, iScreenPos) + tex2D(sNormalMap, iTexCoord);
+    #endif
+
+    #ifdef COMBINE8
+    oColor = tex2D(sDiffMap, iScreenPos) + tex2D(sNormalMap, iTexCoord);
+    #endif
+
+    #ifdef COMBINE4
+    oColor = tex2D(sDiffMap, iScreenPos) + tex2D(sNormalMap, iTexCoord);
+    #endif
+
+    #ifdef COMBINE2
+    float3 color = tex2D(sDiffMap, iScreenPos).rgb * cBloomHDRMix.x;
+    float3 bloom = tex2D(sNormalMap, iTexCoord).rgb * cBloomHDRMix.y;
+    oColor = float4(color + bloom, 1.0);
+    #endif
+}

+ 44 - 0
Bin/CoreData/Shaders/HLSL/Blur.hlsl

@@ -0,0 +1,44 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+#include "PostProcess.hlsl"
+
+uniform float2 cBlurDir;
+uniform float cBlurRadius;
+uniform float cBlurSigma;
+uniform float2 cBlurHOffsets;
+uniform float2 cBlurHInvSize;
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oTexCoord : TEXCOORD0,
+    out float2 oScreenPos : TEXCOORD1)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetQuadTexCoord(oPos) + cBlurHOffsets;
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float2 iScreenPos : TEXCOORD1,
+    out float4 oColor : COLOR0)
+{
+    #ifdef BLUR3
+        oColor = GaussianBlur(3, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef BLUR5
+        oColor = GaussianBlur(5, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef BLUR7
+        oColor = GaussianBlur(7, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, iTexCoord);
+    #endif
+
+    #ifdef BLUR9
+        oColor = GaussianBlur(9, cBlurDir, cBlurHInvSize * cBlurRadius, cBlurSigma, sDiffMap, iTexCoord);
+    #endif
+}

+ 22 - 0
Bin/CoreData/Shaders/HLSL/ColorCorrection.hlsl

@@ -0,0 +1,22 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+#include "PostProcess.hlsl"
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    float3 color = tex2D(sDiffMap, iScreenPos).rgb;
+    oColor = float4(ColorCorrection(color, sVolumeMap), 1.0);
+}

+ 20 - 0
Bin/CoreData/Shaders/HLSL/CopyFramebuffer.hlsl

@@ -0,0 +1,20 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+
+void VS(float4 iPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    oColor = tex2D(sDiffMap, iScreenPos);
+}

+ 102 - 0
Bin/CoreData/Shaders/HLSL/DeferredLight.hlsl

@@ -0,0 +1,102 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Lighting.hlsl"
+
+void VS(float4 iPos : POSITION,
+    #ifdef DIRLIGHT
+        out float2 oScreenPos : TEXCOORD0,
+    #else
+        out float4 oScreenPos : TEXCOORD0,
+    #endif
+    out float3 oFarRay : TEXCOORD1,
+    #ifdef ORTHO
+        out float3 oNearRay : TEXCOORD2,
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    #ifdef DIRLIGHT
+        oScreenPos = GetScreenPosPreDiv(oPos);
+        oFarRay = GetFarRay(oPos);
+        #ifdef ORTHO
+            oNearRay = GetNearRay(oPos);
+        #endif
+    #else
+        oScreenPos = GetScreenPos(oPos);
+        oFarRay = GetFarRay(oPos) * oPos.w;
+        #ifdef ORTHO
+            oNearRay = GetNearRay(oPos) * oPos.w;
+        #endif
+    #endif
+}
+
+void PS(
+    #ifdef DIRLIGHT
+        float2 iScreenPos : TEXCOORD0,
+    #else
+        float4 iScreenPos : TEXCOORD0,
+    #endif
+    float3 iFarRay : TEXCOORD1,
+    #ifdef ORTHO
+        float3 iNearRay : TEXCOORD2,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    // If rendering a directional light quad, optimize out the w divide
+    #ifdef DIRLIGHT
+        float depth = Sample(sDepthBuffer, iScreenPos).r;
+        #ifdef HWDEPTH
+            depth = ReconstructDepth(depth);
+        #endif
+        #ifdef ORTHO
+            float3 worldPos = lerp(iNearRay, iFarRay, depth);
+        #else
+            float3 worldPos = iFarRay * depth;
+        #endif
+        float4 albedoInput = Sample(sAlbedoBuffer, iScreenPos);
+        float4 normalInput = Sample(sNormalBuffer, iScreenPos);
+    #else
+        float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
+        #ifdef HWDEPTH
+            depth = ReconstructDepth(depth);
+        #endif
+        #ifdef ORTHO
+            float3 worldPos = lerp(iNearRay, iFarRay, depth) / iScreenPos.w;
+        #else
+            float3 worldPos = iFarRay * depth / iScreenPos.w;
+        #endif
+        float4 albedoInput = tex2Dproj(sAlbedoBuffer, iScreenPos);
+        float4 normalInput = tex2Dproj(sNormalBuffer, iScreenPos);
+    #endif
+    
+    float3 normal = normalize(normalInput.rgb * 2.0 - 1.0);
+    float4 projWorldPos = float4(worldPos, 1.0);
+    float3 lightColor;
+    float3 lightDir;
+
+    float diff = GetDiffuse(normal, worldPos, lightDir);
+
+    #ifdef SHADOW
+        diff *= GetShadowDeferred(projWorldPos, depth);
+    #endif
+
+    #if defined(SPOTLIGHT)
+        float4 spotPos = mul(projWorldPos, cLightMatricesPS[0]);
+        lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
+    #elif defined(CUBEMASK)
+        lightColor = texCUBE(sLightCubeMap, mul(worldPos - cLightPosPS.xyz, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
+    #else
+        lightColor = cLightColor.rgb;
+    #endif
+
+    #ifdef SPECULAR
+        float spec = GetSpecular(normal, -worldPos, lightDir, normalInput.a * 255.0);
+        oColor = diff * float4(lightColor * (albedoInput.rgb + spec * cLightColor.a * albedoInput.aaa), 0.0);
+    #else
+        oColor = diff * float4(lightColor * albedoInput.rgb, 0.0);
+    #endif
+}

+ 34 - 0
Bin/CoreData/Shaders/HLSL/Depth.hlsl

@@ -0,0 +1,34 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+void VS(float4 iPos : POSITION,
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    float2 iTexCoord : TEXCOORD0,
+    out float3 oTexCoord : TEXCOORD0,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = float3(GetTexCoord(iTexCoord), GetDepth(oPos));
+}
+
+void PS(
+    float3 iTexCoord : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    #ifdef ALPHAMASK
+        float alpha = tex2D(sDiffMap, iTexCoord.xy).a;
+        if (alpha < 0.5)
+            discard;
+    #endif
+
+    oColor = iTexCoord.z;
+}

+ 86 - 0
Bin/CoreData/Shaders/HLSL/FXAA2.hlsl

@@ -0,0 +1,86 @@
+/*============================================================================
+
+                  FXAA v2 CONSOLE by TIMOTHY LOTTES @ NVIDIA
+
+============================================================================*/
+
+// Adapted for Urho3D from http://timothylottes.blogspot.com/2011/04/nvidia-fxaa-ii-for-console.html
+
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+
+uniform float4 cFXAAParams;
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    float FXAA_SUBPIX_SHIFT = 1.0/4.0; // Not used
+    float FXAA_SPAN_MAX = 8.0;
+    float FXAA_REDUCE_MUL = 1.0/8.0;
+    float FXAA_REDUCE_MIN = 1.0/128.0;
+
+    float2 posOffset = cGBufferInvSize.xy * cFXAAParams.x;
+
+    float3 rgbNW = Sample(sDiffMap, iScreenPos + float2(-posOffset.x, -posOffset.y)).rgb;
+    float3 rgbNE = Sample(sDiffMap, iScreenPos + float2(posOffset.x, -posOffset.y)).rgb;
+    float3 rgbSW = Sample(sDiffMap, iScreenPos + float2(-posOffset.x, posOffset.y)).rgb;
+    float3 rgbSE = Sample(sDiffMap, iScreenPos + float2(posOffset.x, posOffset.y)).rgb;
+    float3 rgbM  = Sample(sDiffMap, iScreenPos).rgb;
+
+    float3 luma = float3(0.299, 0.587, 0.114);
+    float lumaNW = dot(rgbNW, luma);
+    float lumaNE = dot(rgbNE, luma);
+    float lumaSW = dot(rgbSW, luma);
+    float lumaSE = dot(rgbSE, luma);
+    float lumaM  = dot(rgbM,  luma);
+
+    float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
+    float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
+
+    if (((lumaMax - lumaMin) / lumaMin) >= cFXAAParams.y)
+    {
+        float2 dir;
+        dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
+        dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
+    
+        float dirReduce = max(
+            (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
+            FXAA_REDUCE_MIN);
+        float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
+        dir = min(float2( FXAA_SPAN_MAX,  FXAA_SPAN_MAX),
+              max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
+              dir * rcpDirMin)) * cGBufferInvSize.xy;
+    
+        dir *= cFXAAParams.z;
+    
+        float3 rgbA = (1.0/2.0) * (
+            Sample(sDiffMap, iScreenPos + dir * (1.0/3.0 - 0.5)).xyz +
+            Sample(sDiffMap, iScreenPos + dir * (2.0/3.0 - 0.5)).xyz);
+        float3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
+            Sample(sDiffMap, iScreenPos + dir * (0.0/3.0 - 0.5)).xyz +
+            Sample(sDiffMap, iScreenPos + dir * (3.0/3.0 - 0.5)).xyz);
+        float lumaB = dot(rgbB, luma);
+        
+        float3 rgbOut;
+        if((lumaB < lumaMin) || (lumaB > lumaMax))
+            rgbOut = rgbA;
+        else
+            rgbOut = rgbB;
+
+        oColor = float4(rgbOut, 1.0);
+    }
+    else
+        oColor = float4(rgbM, 1.0);
+}

+ 715 - 0
Bin/CoreData/Shaders/HLSL/FXAA3.hlsl

@@ -0,0 +1,715 @@
+//----------------------------------------------------------------------------------
+//
+// Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//  * Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//  * Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//  * Neither the name of NVIDIA CORPORATION nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//----------------------------------------------------------------------------------
+/*============================================================================
+
+
+                    NVIDIA FXAA 3.11 by TIMOTHY LOTTES
+
+------------------------------------------------------------------------------
+
+                           Modified for Urho3D
+
+============================================================================*/
+
+/*==========================================================================*/
+//
+//                      Urho3D specific preparations
+//
+/*--------------------------------------------------------------------------*/
+
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+
+/*============================================================================
+                        FXAA QUALITY - TUNING KNOBS
+------------------------------------------------------------------------------
+NOTE the other tuning knobs are now in the shader function inputs!
+============================================================================*/
+#ifndef FXAA_QUALITY_PRESET
+    //
+    // Choose the quality preset.
+    // This needs to be compiled into the shader as it effects code.
+    // Best option to include multiple presets is to 
+    // in each shader define the preset, then include this file.
+    // 
+    // OPTIONS
+    // -----------------------------------------------------------------------
+    // 10 to 15 - default medium dither (10=fastest, 15=highest quality)
+    // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality)
+    // 39       - no dither, very expensive 
+    //
+    // NOTES
+    // -----------------------------------------------------------------------
+    // 12 = slightly faster then FXAA 3.9 and higher edge quality (default)
+    // 13 = about same speed as FXAA 3.9 and better than 12
+    // 23 = closest to FXAA 3.9 visually and performance wise
+    //  _ = the lowest digit is directly related to performance
+    // _  = the highest digit is directly related to style
+    // 
+    #define FXAA_QUALITY_PRESET 12
+#endif
+
+
+/*============================================================================
+
+                           FXAA QUALITY - PRESETS
+
+============================================================================*/
+
+/*============================================================================
+                     FXAA QUALITY - MEDIUM DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY_PRESET == 10)
+    #define FXAA_QUALITY_PS 3
+    #define FXAA_QUALITY_P0 1.5
+    #define FXAA_QUALITY_P1 3.0
+    #define FXAA_QUALITY_P2 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 11)
+    #define FXAA_QUALITY_PS 4
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 3.0
+    #define FXAA_QUALITY_P3 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 12)
+    #define FXAA_QUALITY_PS 5
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 4.0
+    #define FXAA_QUALITY_P4 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 13)
+    #define FXAA_QUALITY_PS 6
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 4.0
+    #define FXAA_QUALITY_P5 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 14)
+    #define FXAA_QUALITY_PS 7
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 4.0
+    #define FXAA_QUALITY_P6 12.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 15)
+    #define FXAA_QUALITY_PS 8
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 4.0
+    #define FXAA_QUALITY_P7 12.0
+#endif
+
+/*============================================================================
+                     FXAA QUALITY - LOW DITHER PRESETS
+============================================================================*/
+#if (FXAA_QUALITY_PRESET == 20)
+    #define FXAA_QUALITY_PS 3
+    #define FXAA_QUALITY_P0 1.5
+    #define FXAA_QUALITY_P1 2.0
+    #define FXAA_QUALITY_P2 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 21)
+    #define FXAA_QUALITY_PS 4
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 22)
+    #define FXAA_QUALITY_PS 5
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 23)
+    #define FXAA_QUALITY_PS 6
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 24)
+    #define FXAA_QUALITY_PS 7
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 3.0
+    #define FXAA_QUALITY_P6 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 25)
+    #define FXAA_QUALITY_PS 8
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 4.0
+    #define FXAA_QUALITY_P7 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 26)
+    #define FXAA_QUALITY_PS 9
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 4.0
+    #define FXAA_QUALITY_P8 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 27)
+    #define FXAA_QUALITY_PS 10
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 4.0
+    #define FXAA_QUALITY_P9 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 28)
+    #define FXAA_QUALITY_PS 11
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 2.0
+    #define FXAA_QUALITY_P9 4.0
+    #define FXAA_QUALITY_P10 8.0
+#endif
+/*--------------------------------------------------------------------------*/
+#if (FXAA_QUALITY_PRESET == 29)
+    #define FXAA_QUALITY_PS 12
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.5
+    #define FXAA_QUALITY_P2 2.0
+    #define FXAA_QUALITY_P3 2.0
+    #define FXAA_QUALITY_P4 2.0
+    #define FXAA_QUALITY_P5 2.0
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 2.0
+    #define FXAA_QUALITY_P9 2.0
+    #define FXAA_QUALITY_P10 4.0
+    #define FXAA_QUALITY_P11 8.0
+#endif
+
+/*============================================================================
+                     FXAA QUALITY - EXTREME QUALITY
+============================================================================*/
+#if (FXAA_QUALITY_PRESET == 39)
+    #define FXAA_QUALITY_PS 12
+    #define FXAA_QUALITY_P0 1.0
+    #define FXAA_QUALITY_P1 1.0
+    #define FXAA_QUALITY_P2 1.0
+    #define FXAA_QUALITY_P3 1.0
+    #define FXAA_QUALITY_P4 1.0
+    #define FXAA_QUALITY_P5 1.5
+    #define FXAA_QUALITY_P6 2.0
+    #define FXAA_QUALITY_P7 2.0
+    #define FXAA_QUALITY_P8 2.0
+    #define FXAA_QUALITY_P9 2.0
+    #define FXAA_QUALITY_P10 4.0
+    #define FXAA_QUALITY_P11 8.0
+#endif
+
+/*============================================================================
+
+                            Support Functions
+
+============================================================================*/
+
+float CalcLuma(float3 rgb)
+{
+    float3 luma = float3(0.299, 0.587, 0.114);
+    return dot(rgb, luma);
+}
+
+/*--------------------------------------------------------------------------*/
+
+#define FxaaTexTop(t, p) float4(tex2Dlod(t, float4(p, 0.0, 0.0)).rgb, 1.0)
+
+#define LumaTop(t, p) CalcLuma(tex2Dlod(t, float4(p, 0.0, 0.0)).rgb)
+#define LumaOff(t, p, o, r) CalcLuma(tex2Dlod(t, float4(p + (o * r), 0, 0)).rgb)
+
+/*============================================================================
+
+                             FXAA3 QUALITY - PC
+
+============================================================================*/
+float4 FxaaPixelShader(
+    //
+    // Use noperspective interpolation here (turn off perspective interpolation).
+    // {xy} = center of pixel
+    float2 pos,
+    //
+    // Input color texture.
+    // {rgb_} = color in linear or perceptual color space
+    // if (FXAA_GREEN_AS_LUMA == 0)
+    //     {__a} = luma in perceptual color space (not linear)
+    sampler2D tex,
+    //
+    // Only used on FXAA Quality.
+    // This must be from a constant/uniform.
+    // {x_} = 1.0/screenWidthInPixels
+    // {_y} = 1.0/screenHeightInPixels
+    float2 fxaaQualityRcpFrame,
+    //
+    // Only used on FXAA Quality.
+    // This used to be the FXAA_QUALITY_SUBPIX define.
+    // It is here now to allow easier tuning.
+    // Choose the amount of sub-pixel aliasing removal.
+    // This can effect sharpness.
+    //   1.00 - upper limit (softer)
+    //   0.75 - default amount of filtering
+    //   0.50 - lower limit (sharper, less sub-pixel aliasing removal)
+    //   0.25 - almost off
+    //   0.00 - completely off
+    float fxaaQualitySubpix,
+    //
+    // Only used on FXAA Quality.
+    // This used to be the FXAA_QUALITY_EDGE_THRESHOLD define.
+    // It is here now to allow easier tuning.
+    // The minimum amount of local contrast required to apply algorithm.
+    //   0.333 - too little (faster)
+    //   0.250 - low quality
+    //   0.166 - default
+    //   0.125 - high quality 
+    //   0.063 - overkill (slower)
+    float fxaaQualityEdgeThreshold,
+    //
+    // Only used on FXAA Quality.
+    // This used to be the FXAA_QUALITY_EDGE_THRESHOLD_MIN define.
+    // It is here now to allow easier tuning.
+    // Trims the algorithm from processing darks.
+    //   0.0833 - upper limit (default, the start of visible unfiltered edges)
+    //   0.0625 - high quality (faster)
+    //   0.0312 - visible limit (slower)
+    // Special notes when using FXAA_GREEN_AS_LUMA,
+    //   Likely want to set this to zero.
+    //   As colors that are mostly not-green
+    //   will appear very dark in the green channel!
+    //   Tune by looking at mostly non-green content,
+    //   then start at zero and increase until aliasing is a problem.
+    float fxaaQualityEdgeThresholdMin
+) {
+/*--------------------------------------------------------------------------*/
+    float2 posM;
+    posM.x = pos.x;
+    posM.y = pos.y;
+    
+    float4 rgbyM = FxaaTexTop(tex, posM);
+    rgbyM.y = CalcLuma(rgbyM.rgb);
+    #define lumaM rgbyM.y
+    float lumaS = LumaOff(tex, posM, float2( 0, 1), fxaaQualityRcpFrame.xy);
+    float lumaE = LumaOff(tex, posM, float2( 1, 0), fxaaQualityRcpFrame.xy);
+    float lumaN = LumaOff(tex, posM, float2( 0,-1), fxaaQualityRcpFrame.xy);
+    float lumaW = LumaOff(tex, posM, float2(-1, 0), fxaaQualityRcpFrame.xy);
+/*--------------------------------------------------------------------------*/
+    float maxSM = max(lumaS, lumaM);
+    float minSM = min(lumaS, lumaM);
+    float maxESM = max(lumaE, maxSM);
+    float minESM = min(lumaE, minSM);
+    float maxWN = max(lumaN, lumaW);
+    float minWN = min(lumaN, lumaW);
+    float rangeMax = max(maxWN, maxESM);
+    float rangeMin = min(minWN, minESM);
+    float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;
+    float range = rangeMax - rangeMin;
+    float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);
+    bool earlyExit = range < rangeMaxClamped;
+/*--------------------------------------------------------------------------*/
+    if(earlyExit)
+        return FxaaTexTop(tex, pos);
+/*--------------------------------------------------------------------------*/
+    float lumaNW = LumaOff(tex, posM, float2(-1,-1), fxaaQualityRcpFrame.xy);
+    float lumaSE = LumaOff(tex, posM, float2( 1, 1), fxaaQualityRcpFrame.xy);
+    float lumaNE = LumaOff(tex, posM, float2( 1,-1), fxaaQualityRcpFrame.xy);
+    float lumaSW = LumaOff(tex, posM, float2(-1, 1), fxaaQualityRcpFrame.xy);
+/*--------------------------------------------------------------------------*/
+    float lumaNS = lumaN + lumaS;
+    float lumaWE = lumaW + lumaE;
+    float subpixRcpRange = 1.0/range;
+    float subpixNSWE = lumaNS + lumaWE;
+    float edgeHorz1 = (-2.0 * lumaM) + lumaNS;
+    float edgeVert1 = (-2.0 * lumaM) + lumaWE;
+/*--------------------------------------------------------------------------*/
+    float lumaNESE = lumaNE + lumaSE;
+    float lumaNWNE = lumaNW + lumaNE;
+    float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;
+    float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;
+/*--------------------------------------------------------------------------*/
+    float lumaNWSW = lumaNW + lumaSW;
+    float lumaSWSE = lumaSW + lumaSE;
+    float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);
+    float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);
+    float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;
+    float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;
+    float edgeHorz = abs(edgeHorz3) + edgeHorz4;
+    float edgeVert = abs(edgeVert3) + edgeVert4;
+/*--------------------------------------------------------------------------*/
+    float subpixNWSWNESE = lumaNWSW + lumaNESE;
+    float lengthSign = fxaaQualityRcpFrame.x;
+    bool horzSpan = edgeHorz >= edgeVert;
+    float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;
+/*--------------------------------------------------------------------------*/
+    if(!horzSpan) lumaN = lumaW;
+    if(!horzSpan) lumaS = lumaE;
+    if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;
+    float subpixB = (subpixA * (1.0/12.0)) - lumaM;
+/*--------------------------------------------------------------------------*/
+    float gradientN = lumaN - lumaM;
+    float gradientS = lumaS - lumaM;
+    float lumaNN = lumaN + lumaM;
+    float lumaSS = lumaS + lumaM;
+    bool pairN = abs(gradientN) >= abs(gradientS);
+    float gradient = max(abs(gradientN), abs(gradientS));
+    if(pairN) lengthSign = -lengthSign;
+    float subpixC = clamp((abs(subpixB) * subpixRcpRange), 0.0, 1.0);
+/*--------------------------------------------------------------------------*/
+    float2 posB;
+    posB.x = posM.x;
+    posB.y = posM.y;
+    float2 offNP;
+    offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;
+    offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;
+    if(!horzSpan) posB.x += lengthSign * 0.5;
+    if( horzSpan) posB.y += lengthSign * 0.5;
+/*--------------------------------------------------------------------------*/
+    float2 posN;
+    posN.x = posB.x - offNP.x * FXAA_QUALITY_P0;
+    posN.y = posB.y - offNP.y * FXAA_QUALITY_P0;
+    float2 posP;
+    posP.x = posB.x + offNP.x * FXAA_QUALITY_P0;
+    posP.y = posB.y + offNP.y * FXAA_QUALITY_P0;
+    float subpixD = ((-2.0)*subpixC) + 3.0;
+    float lumaEndN = LumaTop(tex, posN);
+    float subpixE = subpixC * subpixC;
+    float lumaEndP = LumaTop(tex, posP);
+/*--------------------------------------------------------------------------*/
+    if(!pairN) lumaNN = lumaSS;
+    float gradientScaled = gradient * 1.0/4.0;
+    float lumaMM = lumaM - lumaNN * 0.5;
+    float subpixF = subpixD * subpixE;
+    bool lumaMLTZero = lumaMM < 0.0;
+/*--------------------------------------------------------------------------*/
+    lumaEndN -= lumaNN * 0.5;
+    lumaEndP -= lumaNN * 0.5;
+    bool doneN = abs(lumaEndN) >= gradientScaled;
+    bool doneP = abs(lumaEndP) >= gradientScaled;
+    if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P1;
+    if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P1;
+    bool doneNP = (!doneN) || (!doneP);
+    if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P1;
+    if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P1;
+/*--------------------------------------------------------------------------*/
+    if(doneNP) {
+        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+        doneN = abs(lumaEndN) >= gradientScaled;
+        doneP = abs(lumaEndP) >= gradientScaled;
+        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P2;
+        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P2;
+        doneNP = (!doneN) || (!doneP);
+        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P2;
+        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P2;
+/*--------------------------------------------------------------------------*/
+        #if (FXAA_QUALITY_PS > 3)
+        if(doneNP) {
+            if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+            if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+            if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+            if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+            doneN = abs(lumaEndN) >= gradientScaled;
+            doneP = abs(lumaEndP) >= gradientScaled;
+            if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P3;
+            if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P3;
+            doneNP = (!doneN) || (!doneP);
+            if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P3;
+            if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P3;
+/*--------------------------------------------------------------------------*/
+            #if (FXAA_QUALITY_PS > 4)
+            if(doneNP) {
+                if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                doneN = abs(lumaEndN) >= gradientScaled;
+                doneP = abs(lumaEndP) >= gradientScaled;
+                if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P4;
+                if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P4;
+                doneNP = (!doneN) || (!doneP);
+                if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P4;
+                if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P4;
+/*--------------------------------------------------------------------------*/
+                #if (FXAA_QUALITY_PS > 5)
+                if(doneNP) {
+                    if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                    if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                    if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                    if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                    doneN = abs(lumaEndN) >= gradientScaled;
+                    doneP = abs(lumaEndP) >= gradientScaled;
+                    if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P5;
+                    if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P5;
+                    doneNP = (!doneN) || (!doneP);
+                    if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P5;
+                    if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P5;
+/*--------------------------------------------------------------------------*/
+                    #if (FXAA_QUALITY_PS > 6)
+                    if(doneNP) {
+                        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                        doneN = abs(lumaEndN) >= gradientScaled;
+                        doneP = abs(lumaEndP) >= gradientScaled;
+                        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P6;
+                        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P6;
+                        doneNP = (!doneN) || (!doneP);
+                        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P6;
+                        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P6;
+/*--------------------------------------------------------------------------*/
+                        #if (FXAA_QUALITY_PS > 7)
+                        if(doneNP) {
+                            if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                            if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                            if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                            if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                            doneN = abs(lumaEndN) >= gradientScaled;
+                            doneP = abs(lumaEndP) >= gradientScaled;
+                            if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P7;
+                            if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P7;
+                            doneNP = (!doneN) || (!doneP);
+                            if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P7;
+                            if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P7;
+/*--------------------------------------------------------------------------*/
+    #if (FXAA_QUALITY_PS > 8)
+    if(doneNP) {
+        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+        doneN = abs(lumaEndN) >= gradientScaled;
+        doneP = abs(lumaEndP) >= gradientScaled;
+        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P8;
+        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P8;
+        doneNP = (!doneN) || (!doneP);
+        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P8;
+        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P8;
+/*--------------------------------------------------------------------------*/
+        #if (FXAA_QUALITY_PS > 9)
+        if(doneNP) {
+            if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+            if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+            if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+            if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+            doneN = abs(lumaEndN) >= gradientScaled;
+            doneP = abs(lumaEndP) >= gradientScaled;
+            if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P9;
+            if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P9;
+            doneNP = (!doneN) || (!doneP);
+            if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P9;
+            if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P9;
+/*--------------------------------------------------------------------------*/
+            #if (FXAA_QUALITY_PS > 10)
+            if(doneNP) {
+                if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                doneN = abs(lumaEndN) >= gradientScaled;
+                doneP = abs(lumaEndP) >= gradientScaled;
+                if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P10;
+                if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P10;
+                doneNP = (!doneN) || (!doneP);
+                if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P10;
+                if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P10;
+/*--------------------------------------------------------------------------*/
+                #if (FXAA_QUALITY_PS > 11)
+                if(doneNP) {
+                    if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                    if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                    if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                    if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                    doneN = abs(lumaEndN) >= gradientScaled;
+                    doneP = abs(lumaEndP) >= gradientScaled;
+                    if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P11;
+                    if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P11;
+                    doneNP = (!doneN) || (!doneP);
+                    if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P11;
+                    if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P11;
+/*--------------------------------------------------------------------------*/
+                    #if (FXAA_QUALITY_PS > 12)
+                    if(doneNP) {
+                        if(!doneN) lumaEndN = LumaTop(tex, posN.xy);
+                        if(!doneP) lumaEndP = LumaTop(tex, posP.xy);
+                        if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;
+                        if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;
+                        doneN = abs(lumaEndN) >= gradientScaled;
+                        doneP = abs(lumaEndP) >= gradientScaled;
+                        if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P12;
+                        if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P12;
+                        doneNP = (!doneN) || (!doneP);
+                        if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P12;
+                        if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P12;
+/*--------------------------------------------------------------------------*/
+                    }
+                    #endif
+/*--------------------------------------------------------------------------*/
+                }
+                #endif
+/*--------------------------------------------------------------------------*/
+            }
+            #endif
+/*--------------------------------------------------------------------------*/
+        }
+        #endif
+/*--------------------------------------------------------------------------*/
+    }
+    #endif
+/*--------------------------------------------------------------------------*/
+                        }
+                        #endif
+/*--------------------------------------------------------------------------*/
+                    }
+                    #endif
+/*--------------------------------------------------------------------------*/
+                }
+                #endif
+/*--------------------------------------------------------------------------*/
+            }
+            #endif
+/*--------------------------------------------------------------------------*/
+        }
+        #endif
+/*--------------------------------------------------------------------------*/
+    }
+/*--------------------------------------------------------------------------*/
+    float dstN = posM.x - posN.x;
+    float dstP = posP.x - posM.x;
+    if(!horzSpan) dstN = posM.y - posN.y;
+    if(!horzSpan) dstP = posP.y - posM.y;
+/*--------------------------------------------------------------------------*/
+    bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;
+    float spanLength = (dstP + dstN);
+    bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;
+    float spanLengthRcp = 1.0/spanLength;
+/*--------------------------------------------------------------------------*/
+    bool directionN = dstN < dstP;
+    float dst = min(dstN, dstP);
+    bool goodSpan = directionN ? goodSpanN : goodSpanP;
+    float subpixG = subpixF * subpixF;
+    float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;
+    float subpixH = subpixG * fxaaQualitySubpix;
+/*--------------------------------------------------------------------------*/
+    float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;
+    float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);
+    if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;
+    if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;
+    return FxaaTexTop(tex, posM);
+}
+/*==========================================================================*/
+
+/*============================================================================
+
+                      Urho3D Vertex- and Pixelshader
+                      
+============================================================================*/
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    float2 rcpFrame = float2(cGBufferInvSize.x, cGBufferInvSize.y);
+
+    oColor = FxaaPixelShader(
+        iScreenPos,                         // float2 pos,
+        sDiffMap,                           // sampler2D tex,
+        rcpFrame,                           // float2 fxaaQualityRcpFrame,
+        0.75f,                              // float fxaaQualitySubpix,
+        0.166f,                             // float fxaaQualityEdgeThreshold,
+        0.0833f                             // float fxaaQualityEdgeThresholdMin
+    );
+}
+

+ 24 - 0
Bin/CoreData/Shaders/HLSL/Fog.hlsl

@@ -0,0 +1,24 @@
+#ifdef COMPILEPS
+float3 GetFog(float3 color, float fogFactor)
+{
+    return lerp(cFogColor, color, fogFactor);
+}
+
+float3 GetLitFog(float3 color, float fogFactor)
+{
+    return color * fogFactor;
+}
+
+float GetFogFactor(float depth)
+{
+    return saturate((cFogParams.x - depth) * cFogParams.y);
+}
+
+float GetHeightFogFactor(float depth, float height)
+{
+    float fogFactor = GetFogFactor(depth);
+    float heightFogFactor = (height - cFogParams.z) * cFogParams.w;
+    heightFogFactor = 1.0 - saturate(exp(-(heightFogFactor * heightFogFactor)));
+    return min(heightFogFactor, fogFactor);
+}
+#endif

+ 22 - 0
Bin/CoreData/Shaders/HLSL/GammaCorrection.hlsl

@@ -0,0 +1,22 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+#include "PostProcess.hlsl"
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    float3 color = tex2D(sDiffMap, iScreenPos).rgb;
+    oColor = float4(ToInverseGamma(color), 1.0);
+}

+ 23 - 0
Bin/CoreData/Shaders/HLSL/GreyScale.hlsl

@@ -0,0 +1,23 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Lighting.hlsl"
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    float3 rgb = tex2D(sDiffMap, iScreenPos).rgb;
+    float intensity = GetIntensity(rgb);
+    oColor = float4(intensity, intensity, intensity, 1.0);
+}

+ 287 - 0
Bin/CoreData/Shaders/HLSL/Lighting.hlsl

@@ -0,0 +1,287 @@
+#pragma warning(disable:3571)
+
+#ifdef COMPILEVS
+float3 GetAmbient(float zonePos)
+{
+    return cAmbientStartColor + zonePos * cAmbientEndColor;
+}
+
+#ifdef NUMVERTEXLIGHTS
+float GetVertexLight(int index, float3 worldPos, float3 normal)
+{
+    float3 lightDir = cVertexLights[index * 3 + 1].xyz;
+    float3 lightPos = cVertexLights[index * 3 + 2].xyz;
+    float invRange = cVertexLights[index * 3].w;
+    float cutoff = cVertexLights[index * 3 + 1].w;
+    float invCutoff = cVertexLights[index * 3 + 2].w;
+
+    // Directional light
+    if (invRange == 0.0)
+    {
+        float NdotL = max(dot(normal, lightDir), 0.0);
+        return NdotL;
+    }
+    // Point/spot light
+    else
+    {
+        float3 lightVec = (lightPos - worldPos) * invRange;
+        float lightDist = length(lightVec);
+        float3 localDir = lightVec / lightDist;
+        float NdotL = max(dot(normal, localDir), 0.0);
+        float atten = saturate(1.0 - lightDist * lightDist);
+        float spotEffect = dot(localDir, lightDir);
+        float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
+        return NdotL * atten * spotAtten;
+    }
+}
+
+float GetVertexLightVolumetric(int index, float3 worldPos)
+{
+    float3 lightDir = cVertexLights[index * 3 + 1].xyz;
+    float3 lightPos = cVertexLights[index * 3 + 2].xyz;
+    float invRange = cVertexLights[index * 3].w;
+    float cutoff = cVertexLights[index * 3 + 1].w;
+    float invCutoff = cVertexLights[index * 3 + 2].w;
+
+    // Directional light
+    if (invRange == 0.0)
+    {
+        return 1.0;
+    }
+    // Point/spot light
+    else
+    {
+        float3 lightVec = (lightPos - worldPos) * invRange;
+        float lightDist = length(lightVec);
+        float3 localDir = lightVec / lightDist;
+        float atten = saturate(1.0 - lightDist * lightDist);
+        float spotEffect = dot(localDir, lightDir);
+        float spotAtten = saturate((spotEffect - cutoff) * invCutoff);
+        return atten * spotAtten;
+    }
+}
+#endif
+
+#ifdef SHADOW
+
+#ifdef DIRLIGHT
+    #ifdef SM3
+        #define NUMCASCADES 4
+    #else
+        #define NUMCASCADES 3
+    #endif
+#else
+    #define NUMCASCADES 1
+#endif
+
+void GetShadowPos(float4 projWorldPos, out float4 shadowPos[NUMCASCADES])
+{
+    // Shadow projection: transform from world space to shadow space
+    #if defined(DIRLIGHT)
+        shadowPos[0] = mul(projWorldPos, cLightMatrices[0]);
+        shadowPos[1] = mul(projWorldPos, cLightMatrices[1]);
+        shadowPos[2] = mul(projWorldPos, cLightMatrices[2]);
+        #ifdef SM3
+            shadowPos[3] = mul(projWorldPos, cLightMatrices[3]);
+        #endif
+    #elif defined(SPOTLIGHT)
+        shadowPos[0] = mul(projWorldPos, cLightMatrices[1]);
+    #else
+        shadowPos[0] = float4(projWorldPos.xyz - cLightPos.xyz, 0.0);
+    #endif
+}
+#endif
+#endif
+
+#ifdef COMPILEPS
+float GetDiffuse(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);
+        lightDir = lightVec / lightDist;
+        return saturate(dot(normal, lightDir)) * tex1D(sLightRampMap, lightDist).r;
+    #endif
+}
+
+float GetDiffuseVolumetric(float3 worldPos)
+{
+    #ifdef DIRLIGHT
+        return 1.0;
+    #else
+        float3 lightVec = (cLightPosPS.xyz - worldPos) * cLightPosPS.w;
+        float lightDist = length(lightVec);
+        return tex1D(sLightRampMap, lightDist).r;
+    #endif
+}
+
+float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularPower)
+{
+    float3 halfVec = normalize(normalize(eyeVec) + lightDir);
+    return pow(dot(normal, halfVec), specularPower);
+}
+
+float GetIntensity(float3 color)
+{
+    return dot(color, float3(0.333, 0.333, 0.333));
+}
+
+#ifdef SHADOW
+
+#ifdef DIRLIGHT
+    #ifdef SM3
+        #define NUMCASCADES 4
+    #else
+        #define NUMCASCADES 3
+    #endif
+#else
+    #define NUMCASCADES 1
+#endif
+
+float GetShadow(float4 shadowPos)
+{
+    #ifndef LQSHADOW
+        // Take four samples and average them
+        // Note: in case of sampling a point light cube shadow, we optimize out the w divide as it has already been performed
+        #ifndef POINTLIGHT
+            float2 offsets = cShadowMapInvSize * shadowPos.w;
+        #else
+            float2 offsets = cShadowMapInvSize;
+        #endif
+        float4 inLight = float4(
+            tex2Dproj(sShadowMap, shadowPos).r,
+            tex2Dproj(sShadowMap, float4(shadowPos.x + offsets.x, shadowPos.yzw)).r,
+            tex2Dproj(sShadowMap, float4(shadowPos.x, shadowPos.y + offsets.y, shadowPos.zw)).r,
+            tex2Dproj(sShadowMap, float4(shadowPos.xy + offsets.xy, shadowPos.zw)).r
+        );
+        #ifndef SHADOWCMP
+            return cShadowIntensity.y + dot(inLight, cShadowIntensity.x);
+        #else
+            #ifndef POINTLIGHT
+                return cShadowIntensity.y + dot(inLight * shadowPos.w > shadowPos.z, cShadowIntensity.x);
+            #else
+                return cShadowIntensity.y + dot(inLight > shadowPos.z, cShadowIntensity.x);
+            #endif
+        #endif
+    #else
+        // Take one sample
+        float inLight = tex2Dproj(sShadowMap, shadowPos).r;
+        #ifndef SHADOWCMP
+            return cShadowIntensity.y + cShadowIntensity.x * inLight;
+        #else
+            #ifndef POINTLIGHT
+                return cShadowIntensity.y + cShadowIntensity.x * (inLight * shadowPos.w > shadowPos.z);
+            #else
+                return cShadowIntensity.y + cShadowIntensity.x * (inLight > shadowPos.z);
+            #endif
+        #endif
+    #endif
+}
+
+#ifdef POINTLIGHT
+float GetPointShadow(float3 lightVec)
+{
+    float3 axis = texCUBE(sFaceSelectCubeMap, lightVec).rgb;
+    float depth = abs(dot(lightVec, axis));
+
+    // Expand the maximum component of the light vector to get full 0.0 - 1.0 UV range from the cube map,
+    // and to avoid sampling across faces. Some GPU's filter across faces, while others do not, and in this
+    // case filtering across faces is wrong
+    const float factor = 1.0 / 256.0;
+    lightVec += factor * axis * lightVec;
+
+    // Read the 2D UV coordinates, adjust according to shadow map size and add face offset
+    float4 indirectPos = texCUBE(sIndirectionCubeMap, lightVec);
+    indirectPos.xy *= cShadowCubeAdjust.xy;
+    indirectPos.xy += float2(cShadowCubeAdjust.z + indirectPos.z * 0.5, cShadowCubeAdjust.w + indirectPos.w);
+
+    float4 shadowPos = float4(indirectPos.xy, cShadowDepthFade.x + cShadowDepthFade.y / depth, 1.0);
+    return GetShadow(shadowPos);
+}
+#endif
+
+#ifdef DIRLIGHT
+float GetDirShadowFade(float inLight, float depth)
+{
+    return saturate(inLight + saturate((depth - cShadowDepthFade.z) * cShadowDepthFade.w));
+}
+
+float GetDirShadow(const float4 iShadowPos[NUMCASCADES], float depth)
+{
+    float4 shadowPos;
+
+    #ifdef SM3
+        if (depth < cShadowSplits.x)
+            shadowPos = iShadowPos[0];
+        else if (depth < cShadowSplits.y)
+            shadowPos = iShadowPos[1];
+        else if (depth < cShadowSplits.z)
+            shadowPos = iShadowPos[2];
+        else
+            shadowPos = iShadowPos[3];
+    #else
+        if (depth < cShadowSplits.x)
+            shadowPos = iShadowPos[0];
+        else if (depth < cShadowSplits.y)
+            shadowPos = iShadowPos[1];
+        else
+            shadowPos = iShadowPos[2];
+    #endif
+
+    return GetDirShadowFade(GetShadow(shadowPos), depth);
+}
+
+float GetDirShadowDeferred(float4 projWorldPos, float depth)
+{
+    float4 shadowPos;
+
+    #ifdef SM3
+        if (depth < cShadowSplits.x)
+            shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
+        else if (depth < cShadowSplits.y)
+            shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
+        else if (depth < cShadowSplits.z)
+            shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
+        else
+            shadowPos = mul(projWorldPos, cLightMatricesPS[3]);
+    #else
+        if (depth < cShadowSplits.x)
+            shadowPos = mul(projWorldPos, cLightMatricesPS[0]);
+        else if (depth < cShadowSplits.y)
+            shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
+        else if (depth < cShadowSplits.z)
+            shadowPos = mul(projWorldPos, cLightMatricesPS[2]);
+    #endif
+
+    return GetDirShadowFade(GetShadow(shadowPos), depth);
+}
+#endif
+
+float GetShadow(float4 iShadowPos[NUMCASCADES], float depth)
+{
+    #if defined(DIRLIGHT)
+        return GetDirShadow(iShadowPos, depth);
+    #elif defined(SPOTLIGHT)
+        return GetShadow(iShadowPos[0]);
+    #else
+        return GetPointShadow(iShadowPos[0].xyz);
+    #endif
+}
+
+float GetShadowDeferred(float4 projWorldPos, float depth)
+{
+    #if defined(DIRLIGHT)
+        return GetDirShadowDeferred(projWorldPos, depth);
+    #elif defined(SPOTLIGHT)
+        float4 shadowPos = mul(projWorldPos, cLightMatricesPS[1]);
+        return GetShadow(shadowPos);
+    #else
+        float3 shadowPos = projWorldPos.xyz - cLightPosPS.xyz;
+        return GetPointShadow(shadowPos);
+    #endif
+}
+#endif
+#endif

+ 151 - 0
Bin/CoreData/Shaders/HLSL/LitParticle.hlsl

@@ -0,0 +1,151 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "Lighting.hlsl"
+#include "Fog.hlsl"
+
+void VS(float4 iPos : POSITION,
+    float3 iNormal : NORMAL,
+    float2 iTexCoord : TEXCOORD0,
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    #ifdef BILLBOARD
+        float2 iSize : TEXCOORD1,
+    #endif
+    out float2 oTexCoord : TEXCOORD0,
+    out float4 oWorldPos : TEXCOORD3,
+    #if PERPIXEL
+        #ifdef SHADOW
+            out float4 oShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            out float4 oSpotPos : TEXCOORD5,
+        #endif
+        #ifdef POINTLIGHT
+            out float3 oCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        out float3 oVertexLight : TEXCOORD4,
+    #endif
+    #ifdef VERTEXCOLOR
+        out float4 oColor : COLOR0,
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetTexCoord(iTexCoord);
+    oWorldPos = float4(worldPos, GetDepth(oPos));
+
+    #ifdef VERTEXCOLOR
+        oColor = iColor;
+    #endif
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        float4 projWorldPos = float4(worldPos.xyz, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            GetShadowPos(projWorldPos, oShadowPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            oSpotPos = mul(projWorldPos, cLightMatrices[0]);
+        #endif
+
+        #ifdef POINTLIGHT
+            oCubeMaskVec = mul(worldPos - cLightPos.xyz, (float3x3)cLightMatrices[0]);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        oVertexLight = GetAmbient(GetZonePos(worldPos));
+
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                oVertexLight += GetVertexLightVolumetric(i, worldPos) * cVertexLights[i * 3].rgb;
+        #endif
+    #endif
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float4 iWorldPos : TEXCOORD3,
+    #ifdef PERPIXEL
+        #ifdef SHADOW
+            float4 iShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            float4 iSpotPos : TEXCOORD5,
+        #endif
+        #ifdef CUBEMASK
+            float3 iCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        float3 iVertexLight : TEXCOORD4,
+    #endif
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        float4 diffInput = tex2D(sDiffMap, iTexCoord);
+        #ifdef ALPHAMASK
+            if (diffInput.a < 0.5)
+                discard;
+        #endif
+        float4 diffColor = cMatDiffColor * diffInput;
+    #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
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        float3 lightColor;
+        float3 finalColor;
+        
+        float diff = GetDiffuseVolumetric(iWorldPos.xyz);
+
+        #ifdef SHADOW
+            diff *= GetShadow(iShadowPos, iWorldPos.w);
+        #endif
+
+        #if defined(SPOTLIGHT)
+            lightColor = iSpotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, iSpotPos).rgb * cLightColor.rgb : 0.0;
+        #elif defined(CUBEMASK)
+            lightColor = texCUBE(sLightCubeMap, iCubeMaskVec).rgb * cLightColor.rgb;
+        #else
+            lightColor = cLightColor.rgb;
+        #endif
+
+        finalColor = diff * lightColor * diffColor.rgb;
+        oColor = float4(GetLitFog(finalColor, fogFactor), diffColor.a);
+    #else
+        // Ambient & per-vertex lighting
+        float3 finalColor = iVertexLight * diffColor.rgb;
+
+        oColor = float4(GetFog(finalColor, fogFactor), diffColor.a);
+    #endif
+}

+ 293 - 0
Bin/CoreData/Shaders/HLSL/LitSolid.hlsl

@@ -0,0 +1,293 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Lighting.hlsl"
+#include "Fog.hlsl"
+
+// When rendering a shadowed point light, disable specular calculations on Shader Model 2 to avoid exceeding the instruction limit
+#if !defined(SM3) && defined(SHADOW) && defined(POINTLIGHT)
+    #undef SPECULAR
+#endif
+
+void VS(float4 iPos : POSITION,
+    float3 iNormal : NORMAL,
+    float2 iTexCoord : TEXCOORD0,
+    #if defined(LIGHTMAP) || defined(AO)
+        float2 iTexCoord2 : TEXCOORD1,
+    #endif
+    #ifdef NORMALMAP
+        float4 iTangent : TANGENT,
+    #endif
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    #ifdef BILLBOARD
+        float2 iSize : TEXCOORD1,
+    #endif
+    #ifndef NORMALMAP
+        out float2 oTexCoord : TEXCOORD0,
+    #else
+        out float4 oTexCoord : TEXCOORD0,
+        out float4 oTangent : TEXCOORD3,
+    #endif
+    out float3 oNormal : TEXCOORD1,
+    out float4 oWorldPos : TEXCOORD2,
+    #ifdef PERPIXEL
+        #ifdef SHADOW
+            out float4 oShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            out float4 oSpotPos : TEXCOORD5,
+        #endif
+        #ifdef POINTLIGHT
+            out float3 oCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        out float3 oVertexLight : TEXCOORD4,
+        out float4 oScreenPos : TEXCOORD5,
+        #ifdef ENVCUBEMAP
+            out float3 oReflectionVec : TEXCOORD6,
+        #endif
+        #if defined(LIGHTMAP) || defined(AO)
+            out float2 oTexCoord2 : TEXCOORD7,
+        #endif
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oNormal = GetWorldNormal(modelMatrix);
+    oWorldPos = float4(worldPos, GetDepth(oPos));
+
+    #ifdef NORMALMAP
+        float3 tangent = GetWorldTangent(modelMatrix);
+        float3 bitangent = cross(tangent, oNormal) * iTangent.w;
+        oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
+        oTangent = float4(tangent, bitangent.z);
+    #else
+        oTexCoord = GetTexCoord(iTexCoord);
+    #endif
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        float4 projWorldPos = float4(worldPos.xyz, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            GetShadowPos(projWorldPos, oShadowPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            oSpotPos = mul(projWorldPos, cLightMatrices[0]);
+        #endif
+
+        #ifdef POINTLIGHT
+            oCubeMaskVec = mul(worldPos - cLightPos.xyz, (float3x3)cLightMatrices[0]);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        #if defined(LIGHTMAP) || defined(AO)
+            // If using lightmap, disregard zone ambient light
+            // If using AO, calculate ambient in the PS
+            oVertexLight = float3(0.0, 0.0, 0.0);
+            oTexCoord2 = iTexCoord2;
+        #else
+            oVertexLight = GetAmbient(GetZonePos(worldPos));
+        #endif
+
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                oVertexLight += GetVertexLight(i, worldPos, oNormal) * cVertexLights[i * 3].rgb;
+        #endif
+        
+        oScreenPos = GetScreenPos(oPos);
+
+        #ifdef ENVCUBEMAP
+            oReflectionVec = worldPos - cCameraPos;
+        #endif
+    #endif
+}
+
+void PS(
+    #ifndef NORMALMAP
+        float2 iTexCoord : TEXCOORD0,
+    #else
+        float4 iTexCoord : TEXCOORD0,
+        float4 iTangent : TEXCOORD3,
+    #endif
+    float3 iNormal : TEXCOORD1,
+    float4 iWorldPos : TEXCOORD2,
+    #ifdef PERPIXEL
+        #ifdef SHADOW
+            float4 iShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            float4 iSpotPos : TEXCOORD5,
+        #endif
+        #ifdef CUBEMASK
+            float3 iCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        float3 iVertexLight : TEXCOORD4,
+        float4 iScreenPos : TEXCOORD5,
+        #ifdef ENVCUBEMAP
+            float3 iReflectionVec : TEXCOORD6,
+        #endif
+        #if defined(LIGHTMAP) || defined(AO)
+            float2 iTexCoord2 : TEXCOORD7,
+        #endif
+    #endif
+    #ifdef PREPASS
+        out float4 oDepth : COLOR1,
+    #endif
+    #ifdef DEFERRED
+        out float4 oAlbedo : COLOR1,
+        out float4 oNormal : COLOR2,
+        out float4 oDepth : COLOR3,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        float4 diffInput = tex2D(sDiffMap, iTexCoord.xy);
+        #ifdef ALPHAMASK
+            if (diffInput.a < 0.5)
+                discard;
+        #endif
+        float4 diffColor = cMatDiffColor * diffInput;
+    #else
+        float4 diffColor = cMatDiffColor;
+    #endif
+
+    // Get material specular albedo
+    #ifdef SPECMAP
+        float3 specColor = cMatSpecColor.rgb * tex2D(sSpecMap, iTexCoord.xy).rgb;
+    #else
+        float3 specColor = cMatSpecColor.rgb;
+    #endif
+
+    // Get normal
+    #ifdef NORMALMAP
+        float3x3 tbn = float3x3(iTangent.xyz, float3(iTexCoord.zw, iTangent.w), iNormal);
+        // We may be running low on instructions on Shader Model 2, so skip normalize if necessary
+        #if defined(SM3) || !defined(SHADOW) || !defined(SPECULAR)
+            float3 normal = normalize(mul(DecodeNormal(tex2D(sNormalMap, iTexCoord.xy)), tbn));
+        #else
+            float3 normal = mul(DecodeNormal(tex2D(sNormalMap, iTexCoord.xy)), tbn);
+        #endif
+    #else
+        float3 normal = normalize(iNormal);
+    #endif
+
+    // Get fog factor
+    #ifdef HEIGHTFOG
+        float fogFactor = GetHeightFogFactor(iWorldPos.w, iWorldPos.y);
+    #else
+        float fogFactor = GetFogFactor(iWorldPos.w);
+    #endif
+
+    #if defined(PERPIXEL)
+        // Per-pixel forward lighting
+        float3 lightDir;
+        float3 lightColor;
+        float3 finalColor;
+
+        float diff = GetDiffuse(normal, iWorldPos.xyz, lightDir);
+
+        #ifdef SHADOW
+            diff *= GetShadow(iShadowPos, iWorldPos.w);
+        #endif
+
+        #if defined(SPOTLIGHT)
+            lightColor = iSpotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, iSpotPos).rgb * cLightColor.rgb : 0.0;
+        #elif defined(CUBEMASK)
+            lightColor = texCUBE(sLightCubeMap, iCubeMaskVec).rgb * cLightColor.rgb;
+        #else
+            lightColor = cLightColor.rgb;
+        #endif
+    
+        #ifdef SPECULAR
+            float spec = GetSpecular(normal, cCameraPosPS - iWorldPos.xyz, lightDir, cMatSpecColor.a);
+            finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
+        #else
+            finalColor = diff * lightColor * diffColor.rgb;
+        #endif
+
+        #ifdef AMBIENT
+            finalColor += cAmbientColor * diffColor.rgb;
+            finalColor += cMatEmissiveColor;
+            oColor = float4(GetFog(finalColor, fogFactor), diffColor.a);
+        #else
+            oColor = float4(GetLitFog(finalColor, fogFactor), diffColor.a);
+        #endif
+    #elif defined(PREPASS)
+        // Fill light pre-pass G-Buffer
+        float specPower = cMatSpecColor.a / 255.0;
+
+        oColor = float4(normal * 0.5 + 0.5, specPower);
+        oDepth = iWorldPos.w;
+    #elif defined(DEFERRED)
+        // Fill deferred G-buffer
+        float specIntensity = specColor.g;
+        float specPower = cMatSpecColor.a / 255.0;
+
+        float3 finalColor = iVertexLight * diffColor.rgb;
+        #ifdef AO
+            // If using AO, the vertex light ambient is black, calculate occluded ambient here
+            finalColor += tex2D(sEmissiveMap, iTexCoord2).rgb * cAmbientColor * diffColor.rgb;
+        #endif
+        #ifdef ENVCUBEMAP
+            finalColor += cMatEnvMapColor * texCUBE(sEnvCubeMap, reflect(iReflectionVec, normal)).rgb;
+        #endif
+        #ifdef LIGHTMAP
+            finalColor += tex2D(sEmissiveMap, iTexCoord2).rgb * diffColor.rgb;
+        #endif
+        #ifdef EMISSIVEMAP
+            finalColor += cMatEmissiveColor * tex2D(sEmissiveMap, iTexCoord.xy).rgb;
+        #else
+            finalColor += cMatEmissiveColor;
+        #endif
+
+        oColor = float4(GetFog(finalColor, fogFactor), 1.0);
+        oAlbedo = fogFactor * float4(diffColor.rgb, specIntensity);
+        oNormal = float4(normal * 0.5 + 0.5, specPower);
+        oDepth = iWorldPos.w;
+    #else
+        // Ambient & per-vertex lighting
+        float3 finalColor = iVertexLight * diffColor.rgb;
+        #ifdef AO
+            // If using AO, the vertex light ambient is black, calculate occluded ambient here
+            finalColor += tex2D(sEmissiveMap, iTexCoord2).rgb * cAmbientColor * diffColor.rgb;
+        #endif
+
+        #ifdef MATERIAL
+            // Add light pre-pass accumulation result
+            // Lights are accumulated at half intensity. Bring back to full intensity now
+            float4 lightInput = 2.0 * tex2Dproj(sLightBuffer, iScreenPos);
+            float3 lightSpecColor = lightInput.a * (lightInput.rgb / GetIntensity(lightInput.rgb));
+
+            finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
+        #endif
+
+        #ifdef ENVCUBEMAP
+            finalColor += cMatEnvMapColor * texCUBE(sEnvCubeMap, reflect(iReflectionVec, normal)).rgb;
+        #endif
+        #ifdef LIGHTMAP
+            finalColor += tex2D(sEmissiveMap, iTexCoord2).rgb * diffColor.rgb;
+        #endif
+        #ifdef EMISSIVEMAP
+            finalColor += cMatEmissiveColor * tex2D(sEmissiveMap, iTexCoord.xy).rgb;
+        #else
+            finalColor += cMatEmissiveColor;
+        #endif
+
+        oColor = float4(GetFog(finalColor, fogFactor), diffColor.a);
+    #endif
+}

+ 86 - 0
Bin/CoreData/Shaders/HLSL/PostProcess.hlsl

@@ -0,0 +1,86 @@
+
+static const float PI = 3.14159265;
+
+float2 Noise(float2 coord)
+{
+    float noiseX = clamp(frac(sin(dot(coord, float2(12.9898, 78.233))) * 43758.5453), 0.0, 1.0);
+    float noiseY = clamp(frac(sin(dot(coord, float2(12.9898, 78.233) * 2.0)) * 43758.5453), 0.0, 1.0);
+    return float2(noiseX, noiseY);
+}
+
+// Adapted: http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html
+float4 GaussianBlur(int blurKernelSize, float2 blurDir, float2 blurRadius, float sigma, sampler2D texSampler, float2 texCoord)
+{
+    const int blurKernelHalfSize = blurKernelSize / 2;
+
+    // Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
+    float3 gaussCoeff;
+    gaussCoeff.x = 1.0 / (sqrt(2.0 * PI) * sigma);
+    gaussCoeff.y = exp(-0.5 / (sigma * sigma));
+    gaussCoeff.z = gaussCoeff.y * gaussCoeff.y;
+
+    float2 blurVec = blurRadius * blurDir;
+    float4 avgValue = float4(0.0, 0.0, 0.0, 0.0);
+    float gaussCoeffSum = 0.0;
+
+    avgValue += tex2D(texSampler, texCoord) * gaussCoeff.x;
+    gaussCoeffSum += gaussCoeff.x;
+    gaussCoeff.xy *= gaussCoeff.yz;
+
+    for (int i = 1; i <= blurKernelHalfSize; i++)
+    {
+        avgValue += tex2D(texSampler, texCoord - i * blurVec) * gaussCoeff.x;
+        avgValue += tex2D(texSampler, texCoord + i * blurVec) * gaussCoeff.x;
+
+        gaussCoeffSum += 2.0 * gaussCoeff.x;
+        gaussCoeff.xy *= gaussCoeff.yz;
+    }
+
+    return avgValue / gaussCoeffSum;
+}
+
+static const float3 LumWeights = float3(0.2126, 0.7152, 0.0722);
+
+float3 ReinhardEq3Tonemap(float3 x)
+{
+    return x / (x + 1.0);
+}
+
+float3 ReinhardEq4Tonemap(float3 x, float white)
+{
+    return x * (1.0 + x / white) / (1.0 + x);
+}
+
+// Unchared2 tone mapping (See http://filmicgames.com)
+static const float A = 0.15;
+static const float B = 0.50;
+static const float C = 0.10;
+static const float D = 0.20;
+static const float E = 0.02;
+static const float F = 0.30;
+
+float3 Uncharted2Tonemap(float3 x)
+{
+   return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
+}
+
+float3 ColorCorrection(float3 color, sampler3D lut)
+{
+    float lutSize = 16.0;
+    float scale = (lutSize - 1.0) / lutSize;
+    float offset = 1.0 / (2.0 * lutSize);
+    return tex3D(lut, clamp(color, 0.0, 1.0) * scale + offset).rgb;
+}
+
+static const float Gamma = 2.2;
+static const float InverseGamma = 1.0 / 2.2;
+
+float3 ToGamma(float3 color)
+{
+    return float3(pow(color, Gamma));
+}
+
+float3 ToInverseGamma(float3 color)
+{
+    return float3(pow(color, InverseGamma));
+}

+ 101 - 0
Bin/CoreData/Shaders/HLSL/PrepassLight.hlsl

@@ -0,0 +1,101 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Lighting.hlsl"
+
+void VS(float4 iPos : POSITION,
+    #ifdef DIRLIGHT
+        out float2 oScreenPos : TEXCOORD0,
+    #else
+        out float4 oScreenPos : TEXCOORD0,
+    #endif
+    out float3 oFarRay : TEXCOORD1,
+    #ifdef ORTHO
+        out float3 oNearRay : TEXCOORD2,
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    #ifdef DIRLIGHT
+        oScreenPos = GetScreenPosPreDiv(oPos);
+        oFarRay = GetFarRay(oPos);
+        #ifdef ORTHO
+            oNearRay = GetNearRay(oPos);
+        #endif
+    #else
+        oScreenPos = GetScreenPos(oPos);
+        oFarRay = GetFarRay(oPos) * oPos.w;
+        #ifdef ORTHO
+            oNearRay = GetNearRay(oPos) * oPos.w;
+        #endif
+    #endif
+}
+
+void PS(
+    #ifdef DIRLIGHT
+        float2 iScreenPos : TEXCOORD0,
+    #else
+        float4 iScreenPos : TEXCOORD0,
+    #endif
+    float3 iFarRay : TEXCOORD1,
+    #ifdef ORTHO
+        float3 iNearRay : TEXCOORD2,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    // If rendering a directional light quad, optimize out the w divide
+    #ifdef DIRLIGHT
+        float depth = Sample(sDepthBuffer, iScreenPos).r;
+        #ifdef HWDEPTH
+            depth = ReconstructDepth(depth);
+        #endif
+        #ifdef ORTHO
+            float3 worldPos = lerp(iNearRay, iFarRay, depth);
+        #else
+            float3 worldPos = iFarRay * depth;
+        #endif
+        float4 normalInput = Sample(sNormalBuffer, iScreenPos);
+    #else
+        float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
+        #ifdef HWDEPTH
+            depth = ReconstructDepth(depth);
+        #endif
+        #ifdef ORTHO
+            float3 worldPos = lerp(iNearRay, iFarRay, depth) / iScreenPos.w;
+        #else
+            float3 worldPos = iFarRay * depth / iScreenPos.w;
+        #endif
+        float4 normalInput = tex2Dproj(sNormalBuffer, iScreenPos);
+    #endif
+
+    float3 normal = normalize(normalInput.rgb * 2.0 - 1.0);
+    float4 projWorldPos = float4(worldPos, 1.0);
+    float3 lightColor;
+    float3 lightDir;
+
+    // Accumulate light at half intensity to allow 2x "overburn"
+    float diff = 0.5 * GetDiffuse(normal, worldPos, lightDir);
+
+    #ifdef SHADOW
+        diff *= GetShadowDeferred(projWorldPos, depth);
+    #endif
+
+    #if defined(SPOTLIGHT)
+        float4 spotPos = mul(projWorldPos, cLightMatricesPS[0]);
+        lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
+    #elif defined(CUBEMASK)
+        lightColor = texCUBE(sLightCubeMap, mul(worldPos - cLightPosPS.xyz, (float3x3)cLightMatricesPS[0])).rgb * cLightColor.rgb;
+    #else
+        lightColor = cLightColor.rgb;
+    #endif
+
+    #ifdef SPECULAR
+        float spec = lightColor.g * GetSpecular(normal, -worldPos, lightDir, normalInput.a * 255.0);
+        oColor = diff * float4(lightColor, spec * cLightColor.a);
+    #else
+        oColor = diff * float4(lightColor, 0.0);
+    #endif
+}

+ 53 - 0
Bin/CoreData/Shaders/HLSL/Samplers.hlsl

@@ -0,0 +1,53 @@
+#ifdef COMPILEPS
+sampler2D sDiffMap : register(S0);
+samplerCUBE sDiffCubeMap : register(S0);
+sampler2D sAlbedoBuffer : register(S0);
+sampler2D sNormalMap : register(S1);
+sampler2D sNormalBuffer : register(S1);
+sampler2D sSpecMap : register(S2);
+sampler2D sEmissiveMap : register(S3);
+sampler2D sEnvMap : register(S4);
+samplerCUBE sEnvCubeMap : register(S4);
+sampler1D sLightRampMap : register(S5);
+sampler2D sLightSpotMap : register(S6);
+samplerCUBE sLightCubeMap : register(S6);
+sampler2D sShadowMap : register(S7);
+samplerCUBE sFaceSelectCubeMap : register(S8);
+samplerCUBE sIndirectionCubeMap : register(S9);
+sampler2D sDepthBuffer : register(S10);
+sampler2D sLightBuffer : register(S11);
+sampler3D sVolumeMap : register(S12);
+samplerCUBE sZoneCubeMap : register(S13);
+sampler3D sZoneVolumeMap : register(S13);
+
+float4 Sample(sampler2D map, float2 texCoord)
+{
+    // Use tex2Dlod if available to avoid divergence and allow branching
+    #ifdef SM3
+        return tex2Dlod(map, float4(texCoord, 0.0, 0.0));
+    #else
+        return tex2D(map, texCoord);
+    #endif
+}
+
+float3 DecodeNormal(float4 normalInput)
+{
+    #ifdef PACKEDNORMAL
+        float3 normal;
+        normal.xy = normalInput.ag * 2.0 - 1.0;
+        #ifdef SM3
+            normal.z = sqrt(max(1.0 - dot(normal.xy, normal.xy), 0.0));
+        #else
+            normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+        #endif
+        return normal;
+    #else
+        return normalInput.rgb * 2.0 - 1.0;
+    #endif
+}
+
+float ReconstructDepth(float hwDepth)
+{
+    return dot(float2(hwDepth, cDepthReconstruct.y / (hwDepth - cDepthReconstruct.x)), cDepthReconstruct.zw);
+}
+#endif

+ 51 - 0
Bin/CoreData/Shaders/HLSL/ScreenPos.hlsl

@@ -0,0 +1,51 @@
+#ifdef COMPILEVS
+float4 GetScreenPos(float4 clipPos)
+{
+    return float4(
+        clipPos.x * cGBufferOffsets.z + cGBufferOffsets.x * clipPos.w,
+        -clipPos.y * cGBufferOffsets.w + cGBufferOffsets.y * clipPos.w,
+        0.0,
+        clipPos.w);
+}
+
+float2 GetScreenPosPreDiv(float4 clipPos)
+{
+    return float2(
+        clipPos.x / clipPos.w * cGBufferOffsets.z + cGBufferOffsets.x,
+        -clipPos.y / clipPos.w * cGBufferOffsets.w + cGBufferOffsets.y);
+}
+
+float2 GetQuadTexCoord(float4 clipPos)
+{
+    return float2(
+        clipPos.x / clipPos.w * 0.5 + 0.5,
+        -clipPos.y / clipPos.w * 0.5 + 0.5);
+}
+
+float2 GetQuadTexCoordNoFlip(float3 worldPos)
+{
+    return float2(
+        worldPos.x * 0.5 + 0.5,
+        -worldPos.y * 0.5 + 0.5);
+}
+
+float3 GetFarRay(float4 clipPos)
+{
+    float3 viewRay = float3(
+        clipPos.x / clipPos.w * cFrustumSize.x,
+        clipPos.y / clipPos.w * cFrustumSize.y,
+        cFrustumSize.z);
+
+    return mul(viewRay, cCameraRot);
+}
+
+float3 GetNearRay(float4 clipPos)
+{
+    float3 viewRay = float3(
+        clipPos.x / clipPos.w * cFrustumSize.x,
+        clipPos.y / clipPos.w * cFrustumSize.y,
+        0.0);
+
+    return mul(viewRay, cCameraRot) * cDepthMode.z;
+}
+#endif

+ 34 - 0
Bin/CoreData/Shaders/HLSL/Shadow.hlsl

@@ -0,0 +1,34 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+void VS(float4 iPos : POSITION,
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    float2 iTexCoord : TEXCOORD0,
+    out float2 oTexCoord : TEXCOORD0,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetTexCoord(iTexCoord);
+}
+
+void PS(
+    float2 iTexCoord : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    #ifdef ALPHAMASK
+        float alpha = tex2D(sDiffMap, iTexCoord).a;
+        if (alpha < 0.5)
+            discard;
+    #endif
+
+    oColor = 1.0;
+}

+ 21 - 0
Bin/CoreData/Shaders/HLSL/Skybox.hlsl

@@ -0,0 +1,21 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float3 oTexCoord : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    
+    oPos.z = oPos.w;
+    oTexCoord = iPos.xyz;
+}
+
+void PS(float3 iTexCoord : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    oColor = cMatDiffColor * texCUBE(sDiffCubeMap, iTexCoord);
+}

+ 15 - 0
Bin/CoreData/Shaders/HLSL/Stencil.hlsl

@@ -0,0 +1,15 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+}
+
+void PS(out float4 oColor : COLOR0)
+{
+    oColor = 1.0;
+}

+ 208 - 0
Bin/CoreData/Shaders/HLSL/TerrainBlend.hlsl

@@ -0,0 +1,208 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Lighting.hlsl"
+#include "Fog.hlsl"
+
+// When rendering a shadowed point light, disable specular calculations on Shader Model 2 to avoid exceeding the instruction limit
+#if !defined(SM3) && defined(SHADOW) && defined(POINTLIGHT)
+    #undef SPECULAR
+#endif
+
+sampler2D sWeightMap0 : register(S0);
+sampler2D sDetailMap1 : register(S1);
+sampler2D sDetailMap2 : register(S2);
+sampler2D sDetailMap3 : register(S3);
+
+uniform float2 cDetailTiling;
+
+void VS(float4 iPos : POSITION,
+    float3 iNormal : NORMAL,
+    float2 iTexCoord : TEXCOORD0,
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    #ifdef BILLBOARD
+        float2 iSize : TEXCOORD1,
+    #endif
+    out float2 oTexCoord : TEXCOORD0,
+    out float3 oNormal : TEXCOORD1,
+    out float4 oWorldPos : TEXCOORD2,
+    out float2 oDetailTexCoord : TEXCOORD3,
+    #ifdef PERPIXEL
+        #ifdef SHADOW
+            out float4 oShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            out float4 oSpotPos : TEXCOORD5,
+        #endif
+        #ifdef POINTLIGHT
+            out float3 oCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        out float3 oVertexLight : TEXCOORD4,
+        out float4 oScreenPos : TEXCOORD5,
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oNormal = GetWorldNormal(modelMatrix);
+    oWorldPos = float4(worldPos, GetDepth(oPos));
+    oTexCoord = GetTexCoord(iTexCoord);
+    oDetailTexCoord = cDetailTiling * oTexCoord;
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        float4 projWorldPos = float4(worldPos.xyz, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            GetShadowPos(projWorldPos, oShadowPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            oSpotPos = mul(projWorldPos, cLightMatrices[0]);
+        #endif
+
+        #ifdef POINTLIGHT
+            oCubeMaskVec = mul(worldPos - cLightPos.xyz, (float3x3)cLightMatrices[0]);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        oVertexLight = GetAmbient(GetZonePos(worldPos));
+
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                oVertexLight += GetVertexLight(i, worldPos, oNormal) * cVertexLights[i * 3].rgb;
+        #endif
+        
+        oScreenPos = GetScreenPos(oPos);
+    #endif
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float3 iNormal : TEXCOORD1,
+    float4 iWorldPos : TEXCOORD2,
+    float2 iDetailTexCoord : TEXCOORD3,
+    #ifdef PERPIXEL
+        #ifdef SHADOW
+            float4 iShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            float4 iSpotPos : TEXCOORD5,
+        #endif
+        #ifdef CUBEMASK
+            float3 iCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        float3 iVertexLight : TEXCOORD4,
+        float4 iScreenPos : TEXCOORD5,
+    #endif
+    #ifdef PREPASS
+        out float4 oDepth : COLOR1,
+    #endif
+    #ifdef DEFERRED
+        out float4 oAlbedo : COLOR1,
+        out float4 oNormal : COLOR2,
+        out float4 oDepth : COLOR3,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    // Get material diffuse albedo
+    float3 weights = tex2D(sWeightMap0, iTexCoord).rgb;
+    float sumWeights = weights.r + weights.g + weights.b;
+    weights /= sumWeights;
+    float4 diffColor = cMatDiffColor * (
+        weights.r * tex2D(sDetailMap1, iDetailTexCoord) +
+        weights.g * tex2D(sDetailMap2, iDetailTexCoord) +
+        weights.b * tex2D(sDetailMap3, iDetailTexCoord)
+    );
+
+    // Get material specular albedo
+    float3 specColor = cMatSpecColor.rgb;
+
+    // Get normal
+    float3 normal = normalize(iNormal);
+
+    // Get fog factor
+    #ifdef HEIGHTFOG
+        float fogFactor = GetHeightFogFactor(iWorldPos.w, iWorldPos.y);
+    #else
+        float fogFactor = GetFogFactor(iWorldPos.w);
+    #endif
+
+    #if defined(PERPIXEL)
+        // Per-pixel forward lighting
+        float3 lightDir;
+        float3 lightColor;
+        float3 finalColor;
+        
+        float diff = GetDiffuse(normal, iWorldPos.xyz, lightDir);
+
+        #ifdef SHADOW
+            diff *= GetShadow(iShadowPos, iWorldPos.w);
+        #endif
+    
+        #if defined(SPOTLIGHT)
+            lightColor = iSpotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, iSpotPos).rgb * cLightColor.rgb : 0.0;
+        #elif defined(CUBEMASK)
+            lightColor = texCUBE(sLightCubeMap, iCubeMaskVec).rgb * cLightColor.rgb;
+        #else
+            lightColor = cLightColor.rgb;
+        #endif
+    
+        #ifdef SPECULAR
+            float spec = GetSpecular(normal, cCameraPosPS - iWorldPos.xyz, lightDir, cMatSpecColor.a);
+            finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
+        #else
+            finalColor = diff * lightColor * diffColor.rgb;
+        #endif
+
+        #ifdef AMBIENT
+            finalColor += cAmbientColor * diffColor.rgb;
+            finalColor += cMatEmissiveColor;
+            oColor = float4(GetFog(finalColor, fogFactor), diffColor.a);
+        #else
+            oColor = float4(GetLitFog(finalColor, fogFactor), diffColor.a);
+        #endif
+    #elif defined(PREPASS)
+        // Fill light pre-pass G-Buffer
+        float specPower = cMatSpecColor.a / 255.0;
+
+        oColor = float4(normal * 0.5 + 0.5, specPower);
+        oDepth = iWorldPos.w;
+    #elif defined(DEFERRED)
+        // Fill deferred G-buffer
+        float specIntensity = specColor.g;
+        float specPower = cMatSpecColor.a / 255.0;
+
+        float3 finalColor = iVertexLight * diffColor.rgb;
+
+        oColor = float4(GetFog(finalColor, fogFactor), 1.0);
+        oAlbedo = fogFactor * float4(diffColor.rgb, specIntensity);
+        oNormal = float4(normal * 0.5 + 0.5, specPower);
+        oDepth = iWorldPos.w;
+    #else
+        // Ambient & per-vertex lighting
+        float3 finalColor = iVertexLight * diffColor.rgb;
+
+        #ifdef MATERIAL
+            // Add light pre-pass accumulation result
+            // Lights are accumulated at half intensity. Bring back to full intensity now
+            float4 lightInput = 2.0 * tex2Dproj(sLightBuffer, iScreenPos);
+            float3 lightSpecColor = lightInput.a * (lightInput.rgb / GetIntensity(lightInput.rgb));
+
+            finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
+        #endif
+
+        oColor = float4(GetFog(finalColor, fogFactor), diffColor.a);
+    #endif
+}

+ 62 - 0
Bin/CoreData/Shaders/HLSL/Text.hlsl

@@ -0,0 +1,62 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+#ifdef TEXT_EFFECT_SHADOW
+uniform float2 cShadowOffset;
+uniform float4 cShadowColor;
+#endif
+
+#ifdef TEXT_EFFECT_STROKE
+uniform float4 cStrokeColor;
+#endif
+
+void VS(float4 iPos : POSITION,
+        float4 iColor : COLOR0,
+        float2 iTexCoord : TEXCOORD0,
+        out float4 oPos : POSITION,
+        out float4 oColor : COLOR0,
+        out float2 oTexCoord : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oColor = iColor;
+    oTexCoord = iTexCoord;
+}
+
+void PS(float4 iColor : COLOR0,
+        float2 iTexCoord : TEXCOORD0,
+        out float4 oColor : COLOR0)
+{
+    oColor.rgb = iColor.rgb;
+
+#ifdef SIGNED_DISTANCE_FIELD
+    float distance = tex2D(sDiffMap, iTexCoord).a;
+    if (distance < 0.5f)
+    {
+    #ifdef TEXT_EFFECT_SHADOW
+        if (tex2D(sDiffMap, iTexCoord - cShadowOffset).a > 0.5f)
+            oColor = cShadowColor;
+        else
+    #endif
+        oColor.a = 0.0f;
+    }
+    else
+    {
+    #ifdef TEXT_EFFECT_STROKE
+        if (distance < 0.525f)
+            oColor.rgb = cStrokeColor.rgb;
+    #endif
+
+    #ifdef TEXT_EFFECT_SHADOW
+        if (tex2D(sDiffMap, iTexCoord + cShadowOffset).a < 0.5f)
+            oColor.a = iColor.a;
+        else
+    #endif
+        oColor.a = iColor.a * smoothstep(0.5f, 0.505f, distance);
+    }
+#else
+    oColor.a = iColor.a * tex2D(sDiffMap, iTexCoord).a;
+#endif
+}

+ 38 - 0
Bin/CoreData/Shaders/HLSL/Tonemap.hlsl

@@ -0,0 +1,38 @@
+#include "Uniforms.hlsl"
+#include "Transform.hlsl"
+#include "Samplers.hlsl"
+#include "ScreenPos.hlsl"
+#include "PostProcess.hlsl"
+
+uniform float cTonemapExposureBias;
+uniform float cTonemapMaxWhite;
+
+void VS(float4 iPos : POSITION,
+    out float4 oPos : POSITION,
+    out float2 oScreenPos : TEXCOORD0)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oScreenPos = GetScreenPosPreDiv(oPos);
+}
+
+void PS(float2 iScreenPos : TEXCOORD0,
+    out float4 oColor : COLOR0)
+{
+    #ifdef REINHARDEQ3
+    float3 color = ReinhardEq3Tonemap(max(tex2D(sDiffMap, iScreenPos).rgb * cTonemapExposureBias, 0.0));
+    oColor = float4(color, 1.0);
+    #endif
+
+    #ifdef REINHARDEQ4
+    float3 color = ReinhardEq4Tonemap(max(tex2D(sDiffMap, iScreenPos).rgb * cTonemapExposureBias, 0.0), cTonemapMaxWhite);
+    oColor = float4(color, 1.0);
+    #endif
+
+    #ifdef UNCHARTED2
+    float3 color = Uncharted2Tonemap(max(tex2D(sDiffMap, iScreenPos).rgb * cTonemapExposureBias, 0.0)) / 
+        Uncharted2Tonemap(float3(cTonemapMaxWhite, cTonemapMaxWhite, cTonemapMaxWhite));
+    oColor = float4(color, 1.0);
+    #endif
+}

+ 63 - 0
Bin/CoreData/Shaders/HLSL/Transform.hlsl

@@ -0,0 +1,63 @@
+#ifdef COMPILEVS
+#ifdef SKINNED
+float4x3 GetSkinMatrix(float4 blendWeights, int4 blendIndices)
+{
+    return cSkinMatrices[blendIndices.x] * blendWeights.x +
+        cSkinMatrices[blendIndices.y] * blendWeights.y +
+        cSkinMatrices[blendIndices.z] * blendWeights.z +
+        cSkinMatrices[blendIndices.w] * blendWeights.w;
+}
+#endif
+
+float2 GetTexCoord(float2 iTexCoord)
+{
+    return float2(dot(iTexCoord, cUOffset.xy) + cUOffset.w, dot(iTexCoord, cVOffset.xy) + cVOffset.w);
+};
+
+float4 GetClipPos(float3 worldPos)
+{
+    return mul(float4(worldPos, 1.0), cViewProj);
+}
+
+float GetZonePos(float3 worldPos)
+{
+    return saturate(mul(float4(worldPos, 1.0), cZone).z);
+}
+
+float GetDepth(float4 clipPos)
+{
+    return dot(clipPos.zw, cDepthMode.zw);
+}
+
+float3 GetBillboardPos(float4 iPos, float2 iSize, float4x3 modelMatrix)
+{
+    return mul(iPos, modelMatrix) + mul(float3(iSize.x, iSize.y, 0.0), cBillboardRot);
+}
+
+float3 GetBillboardNormal()
+{
+    return float3(-cBillboardRot[2][0], -cBillboardRot[2][1], -cBillboardRot[2][2]);
+}
+
+#if defined(SKINNED)
+    #define iModelMatrix GetSkinMatrix(iBlendWeights, iBlendIndices);
+#elif defined(INSTANCED)
+    #define iModelMatrix iModelInstance
+#else
+    #define iModelMatrix cModel
+#endif
+
+#ifdef BILLBOARD
+    #define GetWorldPos(modelMatrix) GetBillboardPos(iPos, iSize, modelMatrix)
+#else
+    #define GetWorldPos(modelMatrix) mul(iPos, modelMatrix)
+#endif
+
+#ifdef BILLBOARD
+    #define GetWorldNormal(modelMatrix) GetBillboardNormal()
+#else
+    #define GetWorldNormal(modelMatrix) normalize(mul(iNormal, (float3x3)modelMatrix))
+#endif
+
+#define GetWorldTangent(modelMatrix) normalize(mul(iTangent.xyz, (float3x3)modelMatrix))
+#endif

+ 60 - 0
Bin/CoreData/Shaders/HLSL/Uniforms.hlsl

@@ -0,0 +1,60 @@
+#ifdef COMPILEVS
+// Vertex shader uniforms
+uniform float3 cAmbientStartColor;
+uniform float3 cAmbientEndColor;
+uniform float3x3 cBillboardRot;
+uniform float3 cCameraPos;
+uniform float3x3 cCameraRot;
+uniform float cNearClip;
+uniform float cFarClip;
+uniform float4 cDepthMode;
+uniform float cDeltaTime;
+uniform float cElapsedTime;
+uniform float3 cFrustumSize;
+uniform float4 cGBufferOffsets;
+uniform float3 cLightDir;
+uniform float4 cLightPos;
+uniform float4x3 cModel;
+uniform float4x4 cViewProj;
+uniform float4 cUOffset;
+uniform float4 cVOffset;
+uniform float4x3 cZone;
+uniform float4x4 cLightMatrices[4];
+#ifdef SKINNED
+    uniform float4x3 cSkinMatrices[64];
+#endif
+#ifdef NUMVERTEXLIGHTS
+    uniform float4 cVertexLights[4*3];
+#endif
+#endif
+
+#ifdef COMPILEPS
+// Pixel shader uniforms
+uniform float3 cAmbientColor;
+uniform float3 cCameraPosPS;
+uniform float cDeltaTimePS;
+uniform float4 cDepthReconstruct;
+uniform float cElapsedTimePS;
+uniform float4 cFogParams;
+uniform float3 cFogColor;
+uniform float2 cGBufferInvSize;
+uniform float4 cLightColor;
+uniform float4 cLightPosPS;
+uniform float3 cLightDirPS;
+uniform float4 cMatDiffColor;
+uniform float3 cMatEmissiveColor;
+uniform float3 cMatEnvMapColor;
+uniform float4 cMatSpecColor;
+uniform float cNearClipPS;
+uniform float cFarClipPS;
+uniform float4 cShadowCubeAdjust;
+uniform float4 cShadowDepthFade;
+uniform float2 cShadowIntensity;
+uniform float2 cShadowMapInvSize;
+uniform float4 cShadowSplits;
+#ifdef SM3
+    uniform float4x4 cLightMatricesPS[4];
+#else
+    uniform float4x4 cLightMatricesPS[3];
+#endif
+#endif

+ 89 - 0
Bin/CoreData/Shaders/HLSL/Unlit.hlsl

@@ -0,0 +1,89 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "Fog.hlsl"
+
+void VS(float4 iPos : POSITION,
+    float2 iTexCoord : TEXCOORD0,
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    #ifdef BILLBOARD
+        float2 iSize : TEXCOORD1,
+    #endif
+    out float2 oTexCoord : TEXCOORD0,
+    out float4 oWorldPos : TEXCOORD2,
+    #ifdef VERTEXCOLOR
+        out float4 oColor : COLOR0,
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetTexCoord(iTexCoord);
+    oWorldPos = float4(worldPos, GetDepth(oPos));
+
+    #ifdef VERTEXCOLOR
+        oColor = iColor;
+    #endif
+}
+
+void PS(float2 iTexCoord : TEXCOORD0,
+    float4 iWorldPos: TEXCOORD2,
+    #ifdef VERTEXCOLOR
+        float4 iColor : COLOR0,
+    #endif
+    #ifdef PREPASS
+        out float4 oDepth : COLOR1,
+    #endif
+    #ifdef DEFERRED
+        out float4 oAlbedo : COLOR1,
+        out float4 oNormal : COLOR2,
+        out float4 oDepth : COLOR3,
+    #endif
+    out float4 oColor : COLOR0)
+{
+    // Get material diffuse albedo
+    #ifdef DIFFMAP
+        float4 diffColor = cMatDiffColor * tex2D(sDiffMap, 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
+
+    #if defined(PREPASS)
+        // Fill light pre-pass G-Buffer
+        oColor = float4(0.5, 0.5, 0.5, 1.0);
+        oDepth = iWorldPos.w;
+    #elif defined(DEFERRED)
+        // Fill deferred G-buffer
+        oColor = float4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
+        oAlbedo = float4(0.0, 0.0, 0.0, 0.0);
+        oNormal = float4(0.5, 0.5, 0.5, 1.0);
+        oDepth = iWorldPos.w;
+    #else
+        oColor = float4(GetFog(diffColor.rgb, fogFactor), diffColor.a);
+    #endif
+}

+ 123 - 0
Bin/CoreData/Shaders/HLSL/Vegetation.hlsl

@@ -0,0 +1,123 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Lighting.hlsl"
+#include "Fog.hlsl"
+
+uniform float cWindHeightFactor;
+uniform float cWindHeightPivot;
+uniform float cWindPeriod;
+uniform float2 cWindWorldSpacing;
+
+void VS(float4 iPos : POSITION,
+    float3 iNormal : NORMAL,
+    float2 iTexCoord : TEXCOORD0,
+    #if defined(LIGHTMAP) || defined(AO)
+        float2 iTexCoord2 : TEXCOORD1,
+    #endif
+    #ifdef NORMALMAP
+        float4 iTangent : TANGENT,
+    #endif
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    #ifdef BILLBOARD
+        float2 iSize : TEXCOORD1,
+    #endif
+    #ifndef NORMALMAP
+        out float2 oTexCoord : TEXCOORD0,
+    #else
+        out float4 oTexCoord : TEXCOORD0,
+        out float4 oTangent : TEXCOORD3,
+    #endif
+    out float3 oNormal : TEXCOORD1,
+    out float4 oWorldPos : TEXCOORD2,
+    #ifdef PERPIXEL
+        #ifdef SHADOW
+            out float4 oShadowPos[NUMCASCADES] : TEXCOORD4,
+        #endif
+        #ifdef SPOTLIGHT
+            out float4 oSpotPos : TEXCOORD5,
+        #endif
+        #ifdef POINTLIGHT
+            out float3 oCubeMaskVec : TEXCOORD5,
+        #endif
+    #else
+        out float3 oVertexLight : TEXCOORD4,
+        out float4 oScreenPos : TEXCOORD5,
+        #ifdef ENVCUBEMAP
+            out float3 oReflectionVec : TEXCOORD6,
+        #endif
+        #if defined(LIGHTMAP) || defined(AO)
+            out float2 oTexCoord2 : TEXCOORD7,
+        #endif
+    #endif
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    float height = worldPos.y - cModel._m31;
+
+    float windStrength = max(height - cWindHeightPivot, 0.0) * cWindHeightFactor;
+    float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
+    worldPos.x += windStrength * sin(windPeriod);
+    worldPos.z -= windStrength * cos(windPeriod);
+
+    oPos = GetClipPos(worldPos);
+    oNormal = GetWorldNormal(modelMatrix);
+    oWorldPos = float4(worldPos, GetDepth(oPos));
+
+    #ifdef NORMALMAP
+        float3 tangent = GetWorldTangent(modelMatrix);
+        float3 bitangent = cross(tangent, oNormal) * iTangent.w;
+        oTexCoord = float4(GetTexCoord(iTexCoord), bitangent.xy);
+        oTangent = float4(tangent, bitangent.z);
+    #else
+        oTexCoord = GetTexCoord(iTexCoord);
+    #endif
+
+    #ifdef PERPIXEL
+        // Per-pixel forward lighting
+        float4 projWorldPos = float4(worldPos.xyz, 1.0);
+
+        #ifdef SHADOW
+            // Shadow projection: transform from world space to shadow space
+            GetShadowPos(projWorldPos, oShadowPos);
+        #endif
+
+        #ifdef SPOTLIGHT
+            // Spotlight projection: transform from world space to projector texture coordinates
+            oSpotPos = mul(projWorldPos, cLightMatrices[0]);
+        #endif
+
+        #ifdef POINTLIGHT
+            oCubeMaskVec = mul(cLightPos.xyz - worldPos, (float3x3)cLightMatrices[0]);
+        #endif
+    #else
+        // Ambient & per-vertex lighting
+        #if defined(LIGHTMAP) || defined(AO)
+            // If using lightmap, disregard zone ambient light
+            // If using AO, calculate ambient in the PS
+            oVertexLight = float3(0.0, 0.0, 0.0);
+            oTexCoord2 = iTexCoord2;
+        #else
+            oVertexLight = GetAmbient(GetZonePos(worldPos));
+        #endif
+
+        #ifdef NUMVERTEXLIGHTS
+            for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
+                oVertexLight += GetVertexLight(i, worldPos, oNormal) * cVertexLights[i * 3].rgb;
+        #endif
+        
+        oScreenPos = GetScreenPos(oPos);
+
+        #ifdef ENVCUBEMAP
+            oReflectionVec = worldPos - cCameraPos;
+        #endif
+    #endif
+}

+ 32 - 0
Bin/CoreData/Shaders/HLSL/VegetationDepth.hlsl

@@ -0,0 +1,32 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+uniform float cWindHeightFactor;
+uniform float cWindHeightPivot;
+uniform float cWindPeriod;
+uniform float2 cWindWorldSpacing;
+
+void VS(float4 iPos : POSITION,
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    float2 iTexCoord : TEXCOORD0,
+    out float3 oTexCoord : TEXCOORD0,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+
+    float windStrength = max(iPos.y - cWindHeightPivot, 0.0) * cWindHeightFactor;
+    float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
+    worldPos.x += windStrength * sin(windPeriod);
+    worldPos.z -= windStrength * cos(windPeriod);
+
+    oPos = GetClipPos(worldPos);
+    oTexCoord = float3(GetTexCoord(iTexCoord), GetDepth(oPos));
+}

+ 32 - 0
Bin/CoreData/Shaders/HLSL/VegetationShadow.hlsl

@@ -0,0 +1,32 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+
+uniform float cWindHeightFactor;
+uniform float cWindHeightPivot;
+uniform float cWindPeriod;
+uniform float2 cWindWorldSpacing;
+
+void VS(float4 iPos : POSITION,
+    #ifdef SKINNED
+        float4 iBlendWeights : BLENDWEIGHT,
+        int4 iBlendIndices : BLENDINDICES,
+    #endif
+    #ifdef INSTANCED
+        float4x3 iModelInstance : TEXCOORD2,
+    #endif
+    float2 iTexCoord : TEXCOORD0,
+    out float2 oTexCoord : TEXCOORD0,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+
+    float windStrength = max(iPos.y - cWindHeightPivot, 0.0) * cWindHeightFactor;
+    float windPeriod = cElapsedTime * cWindPeriod + dot(worldPos.xz, cWindWorldSpacing);
+    worldPos.x += windStrength * sin(windPeriod);
+    worldPos.z -= windStrength * cos(windPeriod);
+
+    oPos = GetClipPos(worldPos);
+    oTexCoord = GetTexCoord(iTexCoord);
+}

+ 60 - 0
Bin/CoreData/Shaders/HLSL/Water.hlsl

@@ -0,0 +1,60 @@
+#include "Uniforms.hlsl"
+#include "Samplers.hlsl"
+#include "Transform.hlsl"
+#include "ScreenPos.hlsl"
+#include "Fog.hlsl"
+
+uniform float2 cNoiseSpeed;
+uniform float cNoiseTiling;
+uniform float cNoiseStrength;
+uniform float cFresnelPower;
+uniform float3 cWaterTint;
+
+void VS(float4 iPos : POSITION,
+    float3 iNormal: NORMAL,
+    float2 iTexCoord : TEXCOORD0,
+    out float4 oScreenPos : TEXCOORD0,
+    out float2 oReflectUV : TEXCOORD1,
+    out float2 oWaterUV : TEXCOORD2,
+    out float3 oNormal : TEXCOORD3,
+    out float4 oEyeVec : TEXCOORD4,
+    out float4 oPos : POSITION)
+{
+    float4x3 modelMatrix = iModelMatrix;
+    float3 worldPos = GetWorldPos(modelMatrix);
+    oPos = GetClipPos(worldPos);
+
+    oScreenPos = GetScreenPos(oPos);
+    // GetQuadTexCoord() returns a float2 that is OK for quad rendering; multiply it with output W
+    // coordinate to make it work with arbitrary meshes such as the water plane (perform divide in pixel shader)
+    oReflectUV = GetQuadTexCoord(oPos) * oPos.w;
+    oWaterUV = iTexCoord * cNoiseTiling + cElapsedTime * cNoiseSpeed;
+    oNormal = GetWorldNormal(modelMatrix);
+    oEyeVec = float4(cCameraPos - worldPos, GetDepth(oPos));
+}
+
+void PS(
+    float4 iScreenPos : TEXCOORD0,
+    float2 iReflectUV : TEXCOORD1,
+    float2 iWaterUV : TEXCOORD2,
+    float3 iNormal : TEXCOORD3,
+    float4 iEyeVec : TEXCOORD4,
+    out float4 oColor : COLOR0)
+{
+    float2 refractUV = iScreenPos.xy / iScreenPos.w;
+    float2 reflectUV = iReflectUV.xy / iScreenPos.w;
+
+    float2 noise = (tex2D(sNormalMap, iWaterUV).rg - 0.5) * cNoiseStrength;
+    refractUV += noise;
+    // Do not shift reflect UV coordinate upward, because it will reveal the clipping of geometry below water
+    if (noise.y < 0.0)
+        noise.y = 0.0;
+    reflectUV += noise;
+
+    float fresnel = pow(1.0 - saturate(dot(normalize(iEyeVec.xyz), iNormal)), cFresnelPower);
+    float3 refractColor = tex2D(sEnvMap, refractUV).rgb * cWaterTint;
+    float3 reflectColor = tex2D(sDiffMap, reflectUV).rgb;
+    float3 finalColor = lerp(refractColor, reflectColor, fresnel);
+
+    oColor = float4(GetFog(finalColor, GetFogFactor(iEyeVec.w)), 1.0);
+}

+ 10 - 0
Bin/CoreData/Techniques/Diff.xml

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

+ 9 - 0
Bin/CoreData/Techniques/DiffAO.xml

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

+ 5 - 0
Bin/CoreData/Techniques/DiffAOAlpha.xml

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

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