Browse Source

- move effects and networking to separate jar files

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9190 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
nor..67 13 years ago
parent
commit
b0ada38d21
83 changed files with 7596 additions and 132 deletions
  1. 34 2
      engine/build.xml
  2. 14 5
      engine/nbproject/build-impl.xml
  3. 2 2
      engine/nbproject/genfiles.properties
  4. 126 123
      engine/nbproject/project.properties
  5. 1 0
      engine/nbproject/project.xml
  6. 43 0
      engine/src/core-effects/Common/MatDefs/Post/BloomExtract.j3md
  7. 36 0
      engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md
  8. 55 0
      engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.frag
  9. 48 0
      engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.j3md
  10. 57 0
      engine/src/core-effects/Common/MatDefs/Post/CartoonEdge15.frag
  11. 51 0
      engine/src/core-effects/Common/MatDefs/Post/CrossHatch.frag
  12. 41 0
      engine/src/core-effects/Common/MatDefs/Post/CrossHatch.j3md
  13. 53 0
      engine/src/core-effects/Common/MatDefs/Post/CrossHatch15.frag
  14. 89 0
      engine/src/core-effects/Common/MatDefs/Post/DepthOfField.frag
  15. 25 0
      engine/src/core-effects/Common/MatDefs/Post/DepthOfField.j3md
  16. 88 0
      engine/src/core-effects/Common/MatDefs/Post/FXAA.frag
  17. 20 0
      engine/src/core-effects/Common/MatDefs/Post/FXAA.j3md
  18. 18 0
      engine/src/core-effects/Common/MatDefs/Post/FXAA.vert
  19. 11 0
      engine/src/core-effects/Common/MatDefs/Post/Fade.frag
  20. 34 0
      engine/src/core-effects/Common/MatDefs/Post/Fade.j3md
  21. 11 0
      engine/src/core-effects/Common/MatDefs/Post/Fade15.frag
  22. 21 0
      engine/src/core-effects/Common/MatDefs/Post/Fog.frag
  23. 39 0
      engine/src/core-effects/Common/MatDefs/Post/Fog.j3md
  24. 24 0
      engine/src/core-effects/Common/MatDefs/Post/Fog15.frag
  25. 23 0
      engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.frag
  26. 39 0
      engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.j3md
  27. 26 0
      engine/src/core-effects/Common/MatDefs/Post/GammaCorrection15.frag
  28. 36 0
      engine/src/core-effects/Common/MatDefs/Post/LightScattering.frag
  29. 41 0
      engine/src/core-effects/Common/MatDefs/Post/LightScattering.j3md
  30. 14 0
      engine/src/core-effects/Common/MatDefs/Post/LightScattering.vert
  31. 39 0
      engine/src/core-effects/Common/MatDefs/Post/LightScattering15.frag
  32. 14 0
      engine/src/core-effects/Common/MatDefs/Post/LightScattering15.vert
  33. 9 0
      engine/src/core-effects/Common/MatDefs/Post/Overlay.frag
  34. 36 0
      engine/src/core-effects/Common/MatDefs/Post/Overlay.j3md
  35. 11 0
      engine/src/core-effects/Common/MatDefs/Post/Overlay15.frag
  36. 10 0
      engine/src/core-effects/Common/MatDefs/Post/Post.vert
  37. 12 0
      engine/src/core-effects/Common/MatDefs/Post/Post15.vert
  38. 18 0
      engine/src/core-effects/Common/MatDefs/Post/Posterization.frag
  39. 32 0
      engine/src/core-effects/Common/MatDefs/Post/Posterization.j3md
  40. 20 0
      engine/src/core-effects/Common/MatDefs/Post/Posterization15.frag
  41. 29 0
      engine/src/core-effects/Common/MatDefs/Post/bloomExtract.frag
  42. 33 0
      engine/src/core-effects/Common/MatDefs/Post/bloomExtract15.frag
  43. 12 0
      engine/src/core-effects/Common/MatDefs/Post/bloomFinal.frag
  44. 15 0
      engine/src/core-effects/Common/MatDefs/Post/bloomFinal15.frag
  45. BIN
      engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.png
  46. 21 0
      engine/src/core-effects/Common/MatDefs/SSAO/normal.frag
  47. 16 0
      engine/src/core-effects/Common/MatDefs/SSAO/normal.vert
  48. 104 0
      engine/src/core-effects/Common/MatDefs/SSAO/ssao.frag
  49. 51 0
      engine/src/core-effects/Common/MatDefs/SSAO/ssao.j3md
  50. 96 0
      engine/src/core-effects/Common/MatDefs/SSAO/ssao15.frag
  51. 159 0
      engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.frag
  52. 57 0
      engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.j3md
  53. 160 0
      engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur15.frag
  54. 34 0
      engine/src/core-effects/Common/MatDefs/Water/SimpleWater.j3md
  55. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpg
  56. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpg
  57. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg
  58. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg
  59. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg
  60. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg
  61. BIN
      engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.dds
  62. 402 0
      engine/src/core-effects/Common/MatDefs/Water/Water.frag
  63. 90 0
      engine/src/core-effects/Common/MatDefs/Water/Water.j3md
  64. 419 0
      engine/src/core-effects/Common/MatDefs/Water/Water15.frag
  65. 126 0
      engine/src/core-effects/Common/MatDefs/Water/simple_water.frag
  66. 87 0
      engine/src/core-effects/Common/MatDefs/Water/simple_water.vert
  67. 309 0
      engine/src/core-effects/com/jme3/post/filters/BloomFilter.java
  68. 245 0
      engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java
  69. 111 0
      engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java
  70. 305 0
      engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java
  71. 158 0
      engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java
  72. 95 0
      engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java
  73. 177 0
      engine/src/core-effects/com/jme3/post/filters/FadeFilter.java
  74. 172 0
      engine/src/core-effects/com/jme3/post/filters/FogFilter.java
  75. 78 0
      engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java
  76. 243 0
      engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java
  77. 147 0
      engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java
  78. 156 0
      engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java
  79. 80 0
      engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
  80. 324 0
      engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java
  81. 125 0
      engine/src/core-effects/com/jme3/water/ReflectionProcessor.java
  82. 589 0
      engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java
  83. 1050 0
      engine/src/core-effects/com/jme3/water/WaterFilter.java

+ 34 - 2
engine/build.xml

@@ -21,6 +21,8 @@
     
     
     <target name="-do-compile" description="Overrides default compile target to separate the build into folders" depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources">
     <target name="-do-compile" description="Overrides default compile target to separate the build into folders" depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources">
         <mkdir dir="${build.dir}/core"/>
         <mkdir dir="${build.dir}/core"/>
+        <mkdir dir="${build.dir}/effects"/>
+        <mkdir dir="${build.dir}/networking"/>
         <mkdir dir="${build.dir}/plugins"/>
         <mkdir dir="${build.dir}/plugins"/>
         <mkdir dir="${build.dir}/jogg"/>
         <mkdir dir="${build.dir}/jogg"/>
         <mkdir dir="${build.dir}/blender"/>
         <mkdir dir="${build.dir}/blender"/>
@@ -35,7 +37,7 @@
         <echo>Compile Core</echo>
         <echo>Compile Core</echo>
         <j2seproject3:javac 
         <j2seproject3:javac 
             destdir="${build.dir}/core"
             destdir="${build.dir}/core"
-            srcdir="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.tools.dir}:${src.networking.dir}"
+            srcdir="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.tools.dir}"
             gensrcdir="${build.generated.sources.dir}"/>
             gensrcdir="${build.generated.sources.dir}"/>
         <copy todir="${build.dir}/core">
         <copy todir="${build.dir}/core">
             <fileset dir="${src.core.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.core.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
@@ -44,6 +46,26 @@
             <fileset dir="${src.tools.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.tools.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
         </copy>
         </copy>
         
         
+        <echo>Compile Effects</echo>
+        <j2seproject3:javac 
+            destdir="${build.dir}/effects"
+            srcdir="${src.core-effects.dir}"
+            classpath="${javac.classpath}:${build.dir}/core"
+            gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.dir}/effects">
+            <fileset dir="${src.core-effects.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+
+        <echo>Compile Networking</echo>
+        <j2seproject3:javac 
+            destdir="${build.dir}/networking"
+            srcdir="${src.networking.dir}"
+            classpath="${javac.classpath}:${build.dir}/core"
+            gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.dir}/networking">
+            <fileset dir="${src.networking.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+
         <echo>Compile Plugins (Ogre, XML)</echo>
         <echo>Compile Plugins (Ogre, XML)</echo>
         <j2seproject3:javac 
         <j2seproject3:javac 
             destdir="${build.dir}/plugins"
             destdir="${build.dir}/plugins"
@@ -153,7 +175,7 @@
         <j2seproject3:javac 
         <j2seproject3:javac 
             destdir="${build.classes.dir}"
             destdir="${build.classes.dir}"
             srcdir="${src.test.dir}"
             srcdir="${src.test.dir}"
-            classpath="${javac.classpath}:${build.dir}/core:${build.dir}/plugins:${build.dir}/jogg:${build.dir}/desktop:${build.dir}/blender:${build.dir}/terrain:${build.dir}/jbullet:${build.dir}/niftygui"
+            classpath="${javac.classpath}:${build.dir}/core:${build.dir}/effects:${build.dir}/networking:${build.dir}/plugins:${build.dir}/jogg:${build.dir}/desktop:${build.dir}/blender:${build.dir}/terrain:${build.dir}/jbullet:${build.dir}/niftygui"
             gensrcdir="${build.generated.sources.dir}"/>
             gensrcdir="${build.generated.sources.dir}"/>
         <copy todir="${build.classes.dir}">
         <copy todir="${build.classes.dir}">
             <fileset dir="${src.test.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.test.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
@@ -163,6 +185,8 @@
     <target name="-pre-jar" description="Prepares the separate jME3-xxx.jar files and modifies properties for libraries to be used for lib/ folder, Manifest etc.">
     <target name="-pre-jar" description="Prepares the separate jME3-xxx.jar files and modifies properties for libraries to be used for lib/ folder, Manifest etc.">
         <echo>Building Engine JAR files..</echo>
         <echo>Building Engine JAR files..</echo>
         <jar jarfile="${build.dir}/jME3-core.jar" basedir="${build.dir}/core" compress="true"/>
         <jar jarfile="${build.dir}/jME3-core.jar" basedir="${build.dir}/core" compress="true"/>
+        <jar jarfile="${build.dir}/jME3-effects.jar" basedir="${build.dir}/effects" compress="true"/>
+        <jar jarfile="${build.dir}/jME3-networking.jar" basedir="${build.dir}/networking" compress="true"/>
         <jar jarfile="${build.dir}/jME3-plugins.jar" basedir="${build.dir}/plugins" compress="true"/>
         <jar jarfile="${build.dir}/jME3-plugins.jar" basedir="${build.dir}/plugins" compress="true"/>
         <jar jarfile="${build.dir}/jME3-jogg.jar" basedir="${build.dir}/jogg" compress="true"/>
         <jar jarfile="${build.dir}/jME3-jogg.jar" basedir="${build.dir}/jogg" compress="true"/>
         <jar jarfile="${build.dir}/jME3-desktop.jar" basedir="${build.dir}/desktop" compress="true"/>
         <jar jarfile="${build.dir}/jME3-desktop.jar" basedir="${build.dir}/desktop" compress="true"/>
@@ -183,6 +207,8 @@
         <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
         <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
         
         
         <property location="${build.dir}/core" name="build.core.dir.resolved"/>
         <property location="${build.dir}/core" name="build.core.dir.resolved"/>
+        <property location="${build.dir}/effects" name="build.effects.dir.resolved"/>
+        <property location="${build.dir}/networking" name="build.networking.dir.resolved"/>
         <property location="${build.dir}/plugins" name="build.plugins.dir.resolved"/>
         <property location="${build.dir}/plugins" name="build.plugins.dir.resolved"/>
         <property location="${build.dir}/jogg" name="build.jogg.dir.resolved"/>
         <property location="${build.dir}/jogg" name="build.jogg.dir.resolved"/>
         <property location="${build.dir}/desktop" name="build.desktop.dir.resolved"/>
         <property location="${build.dir}/desktop" name="build.desktop.dir.resolved"/>
@@ -199,6 +225,8 @@
             <map from="${build.classes.dir.resolved}" to=""/>
             <map from="${build.classes.dir.resolved}" to=""/>
             
             
             <map from="${build.core.dir.resolved}" to=""/>
             <map from="${build.core.dir.resolved}" to=""/>
+            <map from="${build.effects.dir.resolved}" to=""/>
+            <map from="${build.networking.dir.resolved}" to=""/>
             <map from="${build.plugins.dir.resolved}" to=""/>
             <map from="${build.plugins.dir.resolved}" to=""/>
             <map from="${build.jogg.dir.resolved}" to=""/>
             <map from="${build.jogg.dir.resolved}" to=""/>
             <map from="${build.desktop.dir.resolved}" to=""/>
             <map from="${build.desktop.dir.resolved}" to=""/>
@@ -214,6 +242,8 @@
             <map from="${android.jar.resolved}" to=""/>
             <map from="${android.jar.resolved}" to=""/>
 
 
             <path path="${build.dir}/jME3-core.jar"/>
             <path path="${build.dir}/jME3-core.jar"/>
+            <path path="${build.dir}/jME3-effects.jar"/>
+            <path path="${build.dir}/jME3-networking.jar"/>
             <path path="${build.dir}/jME3-plugins.jar"/>
             <path path="${build.dir}/jME3-plugins.jar"/>
             <path path="${build.dir}/jME3-jogg.jar"/>
             <path path="${build.dir}/jME3-jogg.jar"/>
             <path path="${build.dir}/jME3-desktop.jar"/>
             <path path="${build.dir}/jME3-desktop.jar"/>
@@ -328,6 +358,7 @@
         <zip destfile="${dist.dir}/jMonkeyEngine3-sources.zip">
         <zip destfile="${dist.dir}/jMonkeyEngine3-sources.zip">
             <zipfileset dir="${src.core.dir}"/>
             <zipfileset dir="${src.core.dir}"/>
             <zipfileset dir="${src.core-data.dir}"/>
             <zipfileset dir="${src.core-data.dir}"/>
+            <zipfileset dir="${src.core-effects.dir}"/>
             <zipfileset dir="${src.core-plugins.dir}"/>
             <zipfileset dir="${src.core-plugins.dir}"/>
             <zipfileset dir="${src.desktop.dir}"/>
             <zipfileset dir="${src.desktop.dir}"/>
             <zipfileset dir="${src.jbullet.dir}"/>
             <zipfileset dir="${src.jbullet.dir}"/>
@@ -385,6 +416,7 @@
             <zipfileset dir="${dist.dir}/javadoc" prefix="javadoc"/>
             <zipfileset dir="${dist.dir}/javadoc" prefix="javadoc"/>
             <zipfileset dir="${src.core.dir}" prefix="source"/>
             <zipfileset dir="${src.core.dir}" prefix="source"/>
             <zipfileset dir="${src.core-data.dir}" prefix="source"/>
             <zipfileset dir="${src.core-data.dir}" prefix="source"/>
+            <zipfileset dir="${src.core-effects.dir}" prefix="source"/>
             <zipfileset dir="${src.core-plugins.dir}" prefix="source"/>
             <zipfileset dir="${src.core-plugins.dir}" prefix="source"/>
             <zipfileset dir="${src.desktop.dir}" prefix="source"/>
             <zipfileset dir="${src.desktop.dir}" prefix="source"/>
             <zipfileset dir="${src.jbullet.dir}" prefix="source"/>
             <zipfileset dir="${src.jbullet.dir}" prefix="source"/>

+ 14 - 5
engine/nbproject/build-impl.xml

@@ -168,6 +168,7 @@ is divided into following sections:
             <or>
             <or>
                 <available file="${src.core.dir}"/>
                 <available file="${src.core.dir}"/>
                 <available file="${src.core-data.dir}"/>
                 <available file="${src.core-data.dir}"/>
+                <available file="${src.core-effects.dir}"/>
                 <available file="${src.core-plugins.dir}"/>
                 <available file="${src.core-plugins.dir}"/>
                 <available file="${src.desktop.dir}"/>
                 <available file="${src.desktop.dir}"/>
                 <available file="${src.terrain.dir}"/>
                 <available file="${src.terrain.dir}"/>
@@ -251,6 +252,7 @@ is divided into following sections:
     <target depends="-pre-init,-init-private,-init-libraries,-init-user,-init-project,-do-init" name="-init-check">
     <target depends="-pre-init,-init-private,-init-libraries,-init-user,-init-project,-do-init" name="-init-check">
         <fail unless="src.core.dir">Must set src.core.dir</fail>
         <fail unless="src.core.dir">Must set src.core.dir</fail>
         <fail unless="src.core-data.dir">Must set src.core-data.dir</fail>
         <fail unless="src.core-data.dir">Must set src.core-data.dir</fail>
+        <fail unless="src.core-effects.dir">Must set src.core-effects.dir</fail>
         <fail unless="src.core-plugins.dir">Must set src.core-plugins.dir</fail>
         <fail unless="src.core-plugins.dir">Must set src.core-plugins.dir</fail>
         <fail unless="src.desktop.dir">Must set src.desktop.dir</fail>
         <fail unless="src.desktop.dir">Must set src.desktop.dir</fail>
         <fail unless="src.terrain.dir">Must set src.terrain.dir</fail>
         <fail unless="src.terrain.dir">Must set src.terrain.dir</fail>
@@ -289,7 +291,7 @@ is divided into following sections:
     </target>
     </target>
     <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
     <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
         <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
         <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
-            <attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
+            <attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-effects.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
             <attribute default="${build.classes.dir}" name="destdir"/>
             <attribute default="${build.classes.dir}" name="destdir"/>
             <attribute default="${javac.classpath}" name="classpath"/>
             <attribute default="${javac.classpath}" name="classpath"/>
             <attribute default="${javac.processorpath}" name="processorpath"/>
             <attribute default="${javac.processorpath}" name="processorpath"/>
@@ -329,7 +331,7 @@ is divided into following sections:
     </target>
     </target>
     <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
     <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
         <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
         <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
-            <attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
+            <attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-effects.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
             <attribute default="${build.classes.dir}" name="destdir"/>
             <attribute default="${build.classes.dir}" name="destdir"/>
             <attribute default="${javac.classpath}" name="classpath"/>
             <attribute default="${javac.classpath}" name="classpath"/>
             <attribute default="${javac.processorpath}" name="processorpath"/>
             <attribute default="${javac.processorpath}" name="processorpath"/>
@@ -361,7 +363,7 @@ is divided into following sections:
     </target>
     </target>
     <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
     <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
         <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
         <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
-            <attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
+            <attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-effects.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
             <attribute default="${build.classes.dir}" name="destdir"/>
             <attribute default="${build.classes.dir}" name="destdir"/>
             <attribute default="${javac.classpath}" name="classpath"/>
             <attribute default="${javac.classpath}" name="classpath"/>
             <sequential>
             <sequential>
@@ -659,13 +661,14 @@ is divided into following sections:
                 <include name="*"/>
                 <include name="*"/>
             </dirset>
             </dirset>
         </pathconvert>
         </pathconvert>
-        <j2seproject3:depend srcdir="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}:${build.generated.subdirs}"/>
+        <j2seproject3:depend srcdir="${src.core.dir}:${src.core-data.dir}:${src.core-effects.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}:${build.generated.subdirs}"/>
     </target>
     </target>
     <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
     <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
         <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
         <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
         <copy todir="${build.classes.dir}">
         <copy todir="${build.classes.dir}">
             <fileset dir="${src.core.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.core.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.core-data.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.core-data.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+            <fileset dir="${src.core-effects.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.core-plugins.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.core-plugins.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.desktop.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.desktop.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.terrain.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
             <fileset dir="${src.terrain.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
@@ -703,7 +706,7 @@ is divided into following sections:
     <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
     <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
         <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
         <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
         <j2seproject3:force-recompile/>
         <j2seproject3:force-recompile/>
-        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}"/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.core.dir}:${src.core-data.dir}:${src.core-effects.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-native.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}"/>
     </target>
     </target>
     <target name="-post-compile-single">
     <target name="-post-compile-single">
         <!-- Empty placeholder for easier customization. -->
         <!-- Empty placeholder for easier customization. -->
@@ -929,6 +932,9 @@ is divided into following sections:
             <fileset dir="${src.core-data.dir}" excludes="*.java,${excludes}" includes="${includes}">
             <fileset dir="${src.core-data.dir}" excludes="*.java,${excludes}" includes="${includes}">
                 <filename name="**/*.java"/>
                 <filename name="**/*.java"/>
             </fileset>
             </fileset>
+            <fileset dir="${src.core-effects.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
             <fileset dir="${src.core-plugins.dir}" excludes="*.java,${excludes}" includes="${includes}">
             <fileset dir="${src.core-plugins.dir}" excludes="*.java,${excludes}" includes="${includes}">
                 <filename name="**/*.java"/>
                 <filename name="**/*.java"/>
             </fileset>
             </fileset>
@@ -992,6 +998,9 @@ is divided into following sections:
             <fileset dir="${src.core-data.dir}" excludes="${excludes}" includes="${includes}">
             <fileset dir="${src.core-data.dir}" excludes="${excludes}" includes="${includes}">
                 <filename name="**/doc-files/**"/>
                 <filename name="**/doc-files/**"/>
             </fileset>
             </fileset>
+            <fileset dir="${src.core-effects.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
             <fileset dir="${src.core-plugins.dir}" excludes="${excludes}" includes="${includes}">
             <fileset dir="${src.core-plugins.dir}" excludes="${excludes}" includes="${includes}">
                 <filename name="**/doc-files/**"/>
                 <filename name="**/doc-files/**"/>
             </fileset>
             </fileset>

+ 2 - 2
engine/nbproject/genfiles.properties

@@ -3,8 +3,8 @@ build.xml.script.CRC32=34d4c2f2
 build.xml.stylesheet.CRC32=958a1d3e
 build.xml.stylesheet.CRC32=958a1d3e
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
-nbproject/build-impl.xml.data.CRC32=5d760efd
-nbproject/build-impl.xml.script.CRC32=a73ff29f
+nbproject/build-impl.xml.data.CRC32=ba8f4e88
+nbproject/build-impl.xml.script.CRC32=9dc03a5e
 nbproject/[email protected]
 nbproject/[email protected]
 nbproject/profiler-build-impl.xml.data.CRC32=aff514c1
 nbproject/profiler-build-impl.xml.data.CRC32=aff514c1
 nbproject/profiler-build-impl.xml.script.CRC32=abda56ed
 nbproject/profiler-build-impl.xml.script.CRC32=abda56ed

+ 126 - 123
engine/nbproject/project.properties

@@ -1,123 +1,126 @@
-annotation.processing.enabled=false
-annotation.processing.enabled.in.editor=false
-annotation.processing.run.all.processors=true
-ant.customtasks.libs=JWSAntTasks
-application.homepage=http://www.jmonkeyengine.com/
-application.title=jMonkeyEngine 3.0
-application.vendor=jMonkeyEngine
-build.classes.dir=${build.dir}/classes
-build.classes.excludes=**/*.java,**/*.form
-# This directory is removed when the project is cleaned:
-build.dir=build
-build.generated.dir=${build.dir}/generated
-build.generated.sources.dir=${build.dir}/generated-sources
-# Only compile against the classpath explicitly listed here:
-build.sysclasspath=ignore
-build.test.classes.dir=${build.dir}/test/classes
-build.test.results.dir=${build.dir}/test/results
-# Uncomment to specify the preferred debugger connection transport:
-#debug.transport=dt_socket
-debug.classpath=\
-    ${run.classpath}
-debug.test.classpath=\
-    ${run.test.classpath}
-# This directory is removed when the project is cleaned:
-dist.dir=dist
-dist.jar=${dist.dir}/jMonkeyEngine3.jar
-dist.javadoc.dir=${dist.dir}/javadoc
-endorsed.classpath=
-excludes=
-file.reference.src-test-data=src/test-data
-includes=**
-jar.archive.disabled=${jnlp.enabled}
-jar.compress=true
-jar.index=${jnlp.enabled}
-javac.classpath=\
-    ${libs.jogg.classpath}:\
-    ${libs.jbullet.classpath}:\
-    ${libs.lwjgl.classpath}:\
-    ${libs.niftygui1.3.classpath}:\
-    ${libs.jme3-test-data.classpath}:\
-    ${libs.android.classpath}:\
-    ${libs.bullet.classpath}
-# Space-separated list of extra javac options
-javac.compilerargs=
-javac.deprecation=false
-javac.processorpath=\
-    ${javac.classpath}
-javac.source=1.5
-javac.target=1.5
-javac.test.classpath=\
-    ${javac.classpath}:\
-    ${build.classes.dir}:\
-    ${libs.junit_4.classpath}
-javadoc.additionalparam=-public 
-javadoc.author=false
-javadoc.encoding=${source.encoding}
-javadoc.noindex=false
-javadoc.nonavbar=false
-javadoc.notree=false
-javadoc.private=false
-javadoc.splitindex=true
-javadoc.use=true
-javadoc.version=false
-javadoc.windowtitle=jMonkeyEngine3
-jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
-jnlp.applet.class=jme3test.awt.AppHarness
-jnlp.applet.height=300
-jnlp.applet.width=300
-jnlp.codebase.type=user
-jnlp.codebase.user=http://jmonkeyengine.com/javawebstart/
-jnlp.descriptor=application
-jnlp.enabled=false
-jnlp.icon=/Users/normenhansen/Pictures/jme/icons/jme-logo48.png
-jnlp.mixed.code=default
-jnlp.offline-allowed=true
-jnlp.signed=true
-jnlp.signing=generated
-jnlp.signing.alias=
-jnlp.signing.keystore=
-main.class=jme3test.TestChooser
-manifest.file=MANIFEST.MF
-meta.inf.dir=${src.dir}/META-INF
-mkdist.disabled=false
-platform.active=default_platform
-run.classpath=\
-    ${javac.classpath}:\
-    ${build.classes.dir}:\
-    ${build.dir}/core:\
-    ${build.dir}/plugins:\
-    ${build.dir}/jogg:\
-    ${build.dir}/desktop:\
-    ${build.dir}/blender:\
-    ${build.dir}/terrain:\
-    ${build.dir}/jbullet:\
-    ${build.dir}/bullet:\
-    ${build.dir}/niftygui:\
-    ${build.dir}/lwjgl:\
-    ${build.dir}/android
-run.jvmargs=-Xms128m -Xmx128m -XX:MaxDirectMemorySize=256M
-run.test.classpath=\
-    ${javac.test.classpath}:\
-    ${build.test.classes.dir}
-source.encoding=UTF-8
-src.android.dir=src/android
-src.blender.dir=src/blender
-src.bullet-common.dir=src/bullet-common
-src.bullet-native.dir=src/bullet-native
-src.bullet.dir=src/bullet
-src.core-data.dir=src/core-data
-src.core-plugins.dir=src/core-plugins
-src.core.dir=src/core
-src.desktop.dir=src/desktop
-src.jbullet.dir=src/jbullet
-src.jogg.dir=src/jogg
-src.lwjgl.dir=src/lwjgl
-src.networking.dir=src\\networking
-src.niftygui.dir=src/niftygui
-src.ogre.dir=src/ogre
-src.terrain.dir=src/terrain
-src.test.dir=src/test
-src.tools.dir=src/tools
-src.xml.dir=src/xml
-test.test.dir=test
+annotation.processing.enabled=false
+annotation.processing.enabled.in.editor=false
+annotation.processing.run.all.processors=true
+ant.customtasks.libs=JWSAntTasks
+application.homepage=http://www.jmonkeyengine.com/
+application.title=jMonkeyEngine 3.0
+application.vendor=jMonkeyEngine
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/jMonkeyEngine3.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+file.reference.src-test-data=src/test-data
+includes=**
+jar.archive.disabled=${jnlp.enabled}
+jar.compress=true
+jar.index=${jnlp.enabled}
+javac.classpath=\
+    ${libs.jogg.classpath}:\
+    ${libs.jbullet.classpath}:\
+    ${libs.lwjgl.classpath}:\
+    ${libs.niftygui1.3.classpath}:\
+    ${libs.jme3-test-data.classpath}:\
+    ${libs.android.classpath}:\
+    ${libs.bullet.classpath}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.5
+javac.target=1.5
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}:\
+    ${libs.junit_4.classpath}
+javadoc.additionalparam=-public 
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=jMonkeyEngine3
+jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
+jnlp.applet.class=jme3test.awt.AppHarness
+jnlp.applet.height=300
+jnlp.applet.width=300
+jnlp.codebase.type=user
+jnlp.codebase.user=http://jmonkeyengine.com/javawebstart/
+jnlp.descriptor=application
+jnlp.enabled=false
+jnlp.icon=/Users/normenhansen/Pictures/jme/icons/jme-logo48.png
+jnlp.mixed.code=default
+jnlp.offline-allowed=true
+jnlp.signed=true
+jnlp.signing=generated
+jnlp.signing.alias=
+jnlp.signing.keystore=
+main.class=jme3test.TestChooser
+manifest.file=MANIFEST.MF
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}:\
+    ${build.dir}/core:\
+    ${build.dir}/effects:\
+    ${build.dir}/networking:\
+    ${build.dir}/plugins:\
+    ${build.dir}/jogg:\
+    ${build.dir}/desktop:\
+    ${build.dir}/blender:\
+    ${build.dir}/terrain:\
+    ${build.dir}/jbullet:\
+    ${build.dir}/bullet:\
+    ${build.dir}/niftygui:\
+    ${build.dir}/lwjgl:\
+    ${build.dir}/android
+run.jvmargs=-Xms128m -Xmx128m -XX:MaxDirectMemorySize=256M
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.android.dir=src/android
+src.blender.dir=src/blender
+src.bullet-common.dir=src/bullet-common
+src.bullet-native.dir=src/bullet-native
+src.bullet.dir=src/bullet
+src.core-data.dir=src/core-data
+src.core-effects.dir=src/core-effects
+src.core-plugins.dir=src/core-plugins
+src.core.dir=src/core
+src.desktop.dir=src/desktop
+src.jbullet.dir=src/jbullet
+src.jogg.dir=src/jogg
+src.lwjgl.dir=src/lwjgl
+src.networking.dir=src/networking
+src.niftygui.dir=src/niftygui
+src.ogre.dir=src/ogre
+src.terrain.dir=src/terrain
+src.test.dir=src/test
+src.tools.dir=src/tools
+src.xml.dir=src/xml
+test.test.dir=test

+ 1 - 0
engine/nbproject/project.xml

@@ -13,6 +13,7 @@
             <source-roots>
             <source-roots>
                 <root id="src.core.dir" name="Core"/>
                 <root id="src.core.dir" name="Core"/>
                 <root id="src.core-data.dir" name="Core-Data"/>
                 <root id="src.core-data.dir" name="Core-Data"/>
+                <root id="src.core-effects.dir" name="Core-Effects"/>
                 <root id="src.core-plugins.dir" name="Core-Plugins"/>
                 <root id="src.core-plugins.dir" name="Core-Plugins"/>
                 <root id="src.desktop.dir" name="Desktop"/>
                 <root id="src.desktop.dir" name="Desktop"/>
                 <root id="src.terrain.dir" name="Terrain"/>
                 <root id="src.terrain.dir" name="Terrain"/>

+ 43 - 0
engine/src/core-effects/Common/MatDefs/Post/BloomExtract.j3md

@@ -0,0 +1,43 @@
+MaterialDef Bloom {
+
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture
+        Float ExposurePow
+        Float ExposureCutoff
+        Boolean Extract
+        Texture2D GlowMap
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/bloomExtract15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            HAS_GLOWMAP : GlowMap
+            DO_EXTRACT : Extract
+            RESOLVE_MS : NumSamples
+        }
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/bloomExtract.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            HAS_GLOWMAP : GlowMap
+            DO_EXTRACT : Extract
+        }
+    }
+
+    Technique FixedFunc {
+    }
+}

+ 36 - 0
engine/src/core-effects/Common/MatDefs/Post/BloomFinal.j3md

@@ -0,0 +1,36 @@
+MaterialDef Bloom Final {
+
+    MaterialParameters {
+          Int NumSamples
+        Texture2D Texture
+        Texture2D BloomTex
+        Float BloomIntensity
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/bloomFinal15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+        }
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/bloomFinal.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+
+
+
+    Technique FixedFunc {
+    }
+}

+ 55 - 0
engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.frag

@@ -0,0 +1,55 @@
+uniform vec4 m_EdgeColor;
+
+uniform float m_EdgeWidth;
+uniform float m_EdgeIntensity;
+
+uniform float m_NormalThreshold;
+uniform float m_DepthThreshold;
+
+uniform float m_NormalSensitivity;
+uniform float m_DepthSensitivity;
+
+varying vec2 texCoord;
+
+uniform sampler2D m_Texture;
+uniform sampler2D m_NormalsTexture;
+uniform sampler2D m_DepthTexture;
+
+uniform vec2 g_Resolution;
+
+vec4 fetchNormalDepth(vec2 tc){
+    vec4 nd;
+    nd.xyz = texture2D(m_NormalsTexture, tc).rgb;
+    nd.w   = texture2D(m_DepthTexture,   tc).r;
+    return nd;
+}
+
+void main(){
+    vec3 color = texture2D(m_Texture, texCoord).rgb;
+
+    vec2 edgeOffset = vec2(m_EdgeWidth) / g_Resolution;
+
+    vec4 n1 = fetchNormalDepth(texCoord + vec2(-1.0, -1.0) * edgeOffset);
+    vec4 n2 = fetchNormalDepth(texCoord + vec2( 1.0,  1.0) * edgeOffset);
+    vec4 n3 = fetchNormalDepth(texCoord + vec2(-1.0,  1.0) * edgeOffset);
+    vec4 n4 = fetchNormalDepth(texCoord + vec2( 1.0, -1.0) * edgeOffset);
+
+    // Work out how much the normal and depth values are changing.
+    vec4 diagonalDelta = abs(n1 - n2) + abs(n3 - n4);
+
+    float normalDelta = dot(diagonalDelta.xyz, vec3(1.0));
+    float depthDelta = diagonalDelta.w;
+
+    // Filter out very small changes, in order to produce nice clean results.
+    normalDelta = clamp((normalDelta - m_NormalThreshold) * m_NormalSensitivity, 0.0, 1.0);
+    depthDelta  = clamp((depthDelta - m_DepthThreshold) * m_DepthSensitivity,    0.0, 1.0);
+
+    // Does this pixel lie on an edge?
+    float edgeAmount = clamp(normalDelta + depthDelta, 0.0, 1.0) * m_EdgeIntensity;
+
+    // Apply the edge detection result to the main scene color.
+    //color *= (1.0 - edgeAmount);
+    color = mix (color,m_EdgeColor.rgb,edgeAmount);
+   
+    gl_FragColor = vec4(color, 1.0);
+}

+ 48 - 0
engine/src/core-effects/Common/MatDefs/Post/CartoonEdge.j3md

@@ -0,0 +1,48 @@
+MaterialDef Cartoon Edge {
+
+    MaterialParameters {
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D Texture
+        Texture2D NormalsTexture
+        Texture2D DepthTexture
+        Color EdgeColor
+        Float EdgeWidth
+        Float EdgeIntensity
+        Float NormalThreshold
+        Float DepthThreshold
+        Float NormalSensitivity
+        Float DepthSensitivity
+    }
+
+     Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/CartoonEdge15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+        }
+    }
+
+   
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/CartoonEdge.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+        }
+    }
+
+    Technique FixedFunc {
+    }
+}

+ 57 - 0
engine/src/core-effects/Common/MatDefs/Post/CartoonEdge15.frag

@@ -0,0 +1,57 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform sampler2D m_NormalsTexture;
+uniform vec2 g_Resolution;
+
+uniform vec4 m_EdgeColor;
+
+uniform float m_EdgeWidth;
+uniform float m_EdgeIntensity;
+
+uniform float m_NormalThreshold;
+uniform float m_DepthThreshold;
+
+uniform float m_NormalSensitivity;
+uniform float m_DepthSensitivity;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+vec4 fetchNormalDepth(vec2 tc){
+    vec4 nd;
+    nd.xyz = texture2D(m_NormalsTexture, tc).rgb;
+    nd.w   = fetchTextureSample(m_DepthTexture,   tc,0).r;
+    return nd;
+}
+
+void main(){
+    vec3 color = getColor(m_Texture, texCoord).rgb;
+
+    vec2 edgeOffset = vec2(m_EdgeWidth) / textureSize(m_NormalsTexture, 0);
+    vec4 n1 = fetchNormalDepth(texCoord + vec2(-1.0, -1.0) * edgeOffset);
+    vec4 n2 = fetchNormalDepth(texCoord + vec2( 1.0,  1.0) * edgeOffset);
+    vec4 n3 = fetchNormalDepth(texCoord + vec2(-1.0,  1.0) * edgeOffset);
+    vec4 n4 = fetchNormalDepth(texCoord + vec2( 1.0, -1.0) * edgeOffset);
+
+    // Work out how much the normal and depth values are changing.
+    vec4 diagonalDelta = abs(n1 - n2) + abs(n3 - n4);
+
+    float normalDelta = dot(diagonalDelta.xyz, vec3(1.0));
+    float depthDelta = diagonalDelta.w;
+
+    // Filter out very small changes, in order to produce nice clean results.
+    normalDelta = clamp((normalDelta - m_NormalThreshold) * m_NormalSensitivity, 0.0, 1.0);
+    depthDelta  = clamp((depthDelta - m_DepthThreshold) * m_DepthSensitivity,    0.0, 1.0);
+
+    // Does this pixel lie on an edge?
+    float edgeAmount = clamp(normalDelta + depthDelta, 0.0, 1.0) * m_EdgeIntensity;
+
+    // Apply the edge detection result to the main scene color.
+    //color *= (1.0 - edgeAmount);
+    color = mix (color,m_EdgeColor.rgb,edgeAmount);
+
+    outFragColor = vec4(color, 1.0);
+}

+ 51 - 0
engine/src/core-effects/Common/MatDefs/Post/CrossHatch.frag

@@ -0,0 +1,51 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+ 
+uniform vec4 m_LineColor;
+uniform vec4 m_PaperColor;
+uniform float m_ColorInfluenceLine;
+uniform float m_ColorInfluencePaper;
+ 
+uniform float m_FillValue;
+uniform float m_Luminance1;
+uniform float m_Luminance2;
+uniform float m_Luminance3;
+uniform float m_Luminance4;
+uniform float m_Luminance5;
+ 
+uniform float m_LineDistance;
+uniform float m_LineThickness;
+ 
+void main() {
+    vec4 texVal = texture2D(m_Texture, texCoord);
+    float linePixel = 0.0;
+ 
+    float lum = texVal.r*0.2126 + texVal.g*0.7152 + texVal.b*0.0722;
+ 
+    if (lum < m_Luminance1){
+        if (mod(gl_FragCoord.x + gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+            linePixel = 1.0;
+    }
+    if (lum < m_Luminance2){
+        if (mod(gl_FragCoord.x - gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+            linePixel = 1.0;
+    }
+    if (lum < m_Luminance3){
+        if (mod(gl_FragCoord.x + gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+            linePixel = 1.0;
+    }
+    if (lum < m_Luminance4){
+        if (mod(gl_FragCoord.x - gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+            linePixel = 1.0;
+    }
+    if (lum < m_Luminance5){ // No line, make a blob instead
+        linePixel = m_FillValue;
+    }
+ 
+    // Mix line color with existing color information
+    vec4 lineColor = mix(m_LineColor, texVal, m_ColorInfluenceLine);
+    // Mix paper color with existing color information
+    vec4 paperColor = mix(m_PaperColor, texVal, m_ColorInfluencePaper);
+ 
+    gl_FragColor = mix(paperColor, lineColor, linePixel);
+}

+ 41 - 0
engine/src/core-effects/Common/MatDefs/Post/CrossHatch.j3md

@@ -0,0 +1,41 @@
+MaterialDef CrossHatch {
+ 
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture;
+        Vector4 LineColor;
+        Vector4 PaperColor;
+        Float ColorInfluenceLine;
+        Float ColorInfluencePaper;
+        Float FillValue;
+        Float Luminance1;
+        Float Luminance2;
+        Float Luminance3;
+        Float Luminance4;
+        Float Luminance5;
+        Float LineThickness;
+        Float LineDistance;
+    }
+ 
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/CrossHatch15.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+ 
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/CrossHatch.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+ 
+    Technique FixedFunc {
+    }
+ 
+}

+ 53 - 0
engine/src/core-effects/Common/MatDefs/Post/CrossHatch15.frag

@@ -0,0 +1,53 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+ 
+uniform COLORTEXTURE m_Texture;
+in vec2 texCoord;
+ 
+uniform vec4 m_LineColor;
+uniform vec4 m_PaperColor;
+uniform float m_ColorInfluenceLine;
+uniform float m_ColorInfluencePaper;
+ 
+uniform float m_FillValue;
+uniform float m_Luminance1;
+uniform float m_Luminance2;
+uniform float m_Luminance3;
+uniform float m_Luminance4;
+uniform float m_Luminance5;
+ 
+uniform float m_LineDistance;
+uniform float m_LineThickness;
+ 
+void main() {
+    vec4 texVal = getColor(m_Texture, texCoord);
+    float linePixel = 0;
+ 
+    float lum = texVal.r*0.2126 + texVal.g*0.7152 + texVal.b*0.0722;
+ 
+    if (lum < m_Luminance1){
+        if (mod(gl_FragCoord.x + gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+            linePixel = 1;
+    }
+    if (lum < m_Luminance2){
+        if (mod(gl_FragCoord.x - gl_FragCoord.y, m_LineDistance * 2.0) < m_LineThickness)
+            linePixel = 1;
+    }
+    if (lum < m_Luminance3){
+        if (mod(gl_FragCoord.x + gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+            linePixel = 1;
+    }
+    if (lum < m_Luminance4){
+        if (mod(gl_FragCoord.x - gl_FragCoord.y - m_LineDistance, m_LineDistance) < m_LineThickness)
+            linePixel = 1;
+    }
+    if (lum < m_Luminance5){ // No line, make a blob instead
+        linePixel = m_FillValue;
+    }
+ 
+    // Mix line color with existing color information
+    vec4 lineColor = mix(m_LineColor, texVal, m_ColorInfluenceLine);
+    // Mix paper color with existing color information
+    vec4 paperColor = mix(m_PaperColor, texVal, m_ColorInfluencePaper);
+ 
+    gl_FragColor = mix(paperColor, lineColor, linePixel);
+}

+ 89 - 0
engine/src/core-effects/Common/MatDefs/Post/DepthOfField.frag

@@ -0,0 +1,89 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+varying vec2 texCoord;
+
+uniform float m_FocusRange;
+uniform float m_FocusDistance;
+uniform float m_XScale;
+uniform float m_YScale;
+
+vec2 m_NearFar = vec2( 0.1, 1000.0 );
+
+void main() {
+
+    vec4 texVal = texture2D( m_Texture, texCoord );
+
+    float zBuffer = texture2D( m_DepthTexture, texCoord ).r;
+
+    //
+    // z_buffer_value = a + b / z;
+    //
+    // Where:
+    //  a = zFar / ( zFar - zNear )
+    //  b = zFar * zNear / ( zNear - zFar )
+    //  z = distance from the eye to the object
+    //
+    // Which means:
+    // zb - a = b / z;
+    // z * (zb - a) = b
+    // z = b / (zb - a)
+    //
+    float a = m_NearFar.y / (m_NearFar.y - m_NearFar.x);
+    float b = m_NearFar.y * m_NearFar.x / (m_NearFar.x - m_NearFar.y);
+    float z = b / (zBuffer - a);
+
+    // Above could be the same for any depth-based filter
+
+    // We want to be purely focused right at
+    // m_FocusDistance and be purely unfocused
+    // at +/- m_FocusRange to either side of that.
+    float unfocus = min( 1.0, abs( z - m_FocusDistance ) / m_FocusRange );
+
+    if( unfocus < 0.2 ) {
+        // If we are mostly in focus then don't bother with the
+        // convolution filter
+        gl_FragColor = texVal;
+    } else {
+    // Perform a wide convolution filter and we scatter it
+    // a bit to avoid some texture look-ups.  Instead of
+    // a full 5x5 (25-1 lookups) we'll skip every other one
+    // to only perform 12.
+    // 1  0  1  0  1
+    // 0  1  0  1  0
+    // 1  0  x  0  1
+    // 0  1  0  1  0
+    // 1  0  1  0  1
+    //
+    // You can get away with 8 just around the outside but
+    // it looks more jittery to me.
+
+    vec4 sum = vec4(0.0);
+
+    float x = texCoord.x;
+    float y = texCoord.y;
+
+    float xScale = m_XScale;
+    float yScale = m_YScale;
+
+    // In order from lower left to right, depending on how you look at it
+    sum += texture2D( m_Texture, vec2(x - 2.0 * xScale, y - 2.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x - 0.0 * xScale, y - 2.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x + 2.0 * xScale, y - 2.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x - 1.0 * xScale, y - 1.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x + 1.0 * xScale, y - 1.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x - 2.0 * xScale, y - 0.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x + 2.0 * xScale, y - 0.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x - 1.0 * xScale, y + 1.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x + 1.0 * xScale, y + 1.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x - 2.0 * xScale, y + 2.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x - 0.0 * xScale, y + 2.0 * yScale) );
+    sum += texture2D( m_Texture, vec2(x + 2.0 * xScale, y + 2.0 * yScale) );
+
+    sum = sum / 12.0;
+
+    gl_FragColor = mix( texVal, sum, unfocus );
+
+    // I used this for debugging the range
+   // gl_FragColor.r = unfocus;
+}
+}

+ 25 - 0
engine/src/core-effects/Common/MatDefs/Post/DepthOfField.j3md

@@ -0,0 +1,25 @@
+MaterialDef Depth Of Field {
+
+    MaterialParameters {
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D Texture
+        Texture2D DepthTexture
+        Float FocusRange;
+        Float FocusDistance;
+        Float XScale;
+        Float YScale;
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/DepthOfField.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+
+    Technique FixedFunc {
+    }
+}

+ 88 - 0
engine/src/core-effects/Common/MatDefs/Post/FXAA.frag

@@ -0,0 +1,88 @@
+#extension GL_EXT_gpu_shader4 : enable
+
+uniform sampler2D m_Texture;
+uniform vec2 g_Resolution;
+
+uniform float m_VxOffset;
+uniform float m_SpanMax;
+uniform float m_ReduceMul;
+
+varying vec2 texCoord;
+varying vec4 posPos;
+
+#define FxaaTex(t, p) texture2D(t, p)
+
+#if __VERSION__ >= 130
+    #define OffsetVec(a, b) ivec2(a, b)
+    #define FxaaTexOff(t, p, o, r) textureOffset(t, p, o)
+#elif defined(GL_EXT_gpu_shader4)
+    #define OffsetVec(a, b) ivec2(a, b)
+    #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o)
+#else
+    #define OffsetVec(a, b) vec2(a, b)
+    #define FxaaTexOff(t, p, o, r) texture2D(t, p + o * r)
+#endif
+
+vec3 FxaaPixelShader(
+  vec4 posPos,   // Output of FxaaVertexShader interpolated across screen.
+  sampler2D tex, // Input texture.
+  vec2 rcpFrame) // Constant {1.0/frameWidth, 1.0/frameHeight}.
+{
+
+    #define FXAA_REDUCE_MIN   (1.0/128.0)
+    //#define FXAA_REDUCE_MUL   (1.0/8.0)
+    //#define FXAA_SPAN_MAX     8.0
+
+    vec3 rgbNW = FxaaTex(tex, posPos.zw).xyz;
+    vec3 rgbNE = FxaaTexOff(tex, posPos.zw, OffsetVec(1,0), rcpFrame.xy).xyz;
+    vec3 rgbSW = FxaaTexOff(tex, posPos.zw, OffsetVec(0,1), rcpFrame.xy).xyz;
+    vec3 rgbSE = FxaaTexOff(tex, posPos.zw, OffsetVec(1,1), rcpFrame.xy).xyz;
+
+    vec3 rgbM  = FxaaTex(tex, posPos.xy).xyz;
+
+    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)));
+
+    vec2 dir;
+    dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
+    dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
+
+    float dirReduce = max(
+        (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * m_ReduceMul),
+        FXAA_REDUCE_MIN);
+    float rcpDirMin = 1.0/(min(abs(dir.x), abs(dir.y)) + dirReduce);
+    dir = min(vec2( m_SpanMax,  m_SpanMax),
+          max(vec2(-m_SpanMax, -m_SpanMax),
+          dir * rcpDirMin)) * rcpFrame.xy;
+
+    vec3 rgbA = (1.0/2.0) * (
+        FxaaTex(tex, posPos.xy + dir * vec2(1.0/3.0 - 0.5)).xyz +
+        FxaaTex(tex, posPos.xy + dir * vec2(2.0/3.0 - 0.5)).xyz);
+    vec3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
+        FxaaTex(tex, posPos.xy + dir * vec2(0.0/3.0 - 0.5)).xyz +
+        FxaaTex(tex, posPos.xy + dir * vec2(3.0/3.0 - 0.5)).xyz);
+
+    float lumaB = dot(rgbB, luma);
+
+    if ((lumaB < lumaMin) || (lumaB > lumaMax))
+    {
+        return rgbA;
+    }
+    else
+    {
+        return rgbB; 
+    }
+}
+
+void main()
+{
+    vec2 rcpFrame = vec2(1.0) / g_Resolution;
+    gl_FragColor = vec4(FxaaPixelShader(posPos, m_Texture, rcpFrame), 1.0);
+}

+ 20 - 0
engine/src/core-effects/Common/MatDefs/Post/FXAA.j3md

@@ -0,0 +1,20 @@
+MaterialDef FXAA {
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture
+        Float SubPixelShift
+        Float VxOffset
+        Float SpanMax
+        Float ReduceMul
+    }
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/FXAA.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/FXAA.frag
+        WorldParameters {
+            WorldViewProjectionMatrix
+            Resolution
+        }
+    }
+    Technique FixedFunc {
+    }
+}

+ 18 - 0
engine/src/core-effects/Common/MatDefs/Post/FXAA.vert

@@ -0,0 +1,18 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec2 g_Resolution;
+
+uniform float m_SubPixelShift;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+
+varying vec2 texCoord;
+varying vec4 posPos;
+
+void main() {
+    gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0);
+    texCoord = inTexCoord;
+    vec2 rcpFrame = vec2(1.0) / g_Resolution;
+    posPos.xy = inTexCoord.xy;
+    posPos.zw = inTexCoord.xy - (rcpFrame * vec2(0.5 + m_SubPixelShift));
+}

+ 11 - 0
engine/src/core-effects/Common/MatDefs/Post/Fade.frag

@@ -0,0 +1,11 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+
+uniform float m_Value;
+
+void main() {
+       vec4 texVal = texture2D(m_Texture, texCoord);
+
+       gl_FragColor = texVal * m_Value;
+
+}

+ 34 - 0
engine/src/core-effects/Common/MatDefs/Post/Fade.j3md

@@ -0,0 +1,34 @@
+MaterialDef Fade {
+
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture
+        Float Value
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/Fade15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+        }
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/Fade.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix           
+        }
+    }
+
+    Technique FixedFunc {
+    }
+
+}

+ 11 - 0
engine/src/core-effects/Common/MatDefs/Post/Fade15.frag

@@ -0,0 +1,11 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform float m_Value;
+
+in vec2 texCoord;
+
+void main() {
+    vec4 texVal = getColor(m_Texture, texCoord);
+    gl_FragColor = texVal * m_Value;
+}

+ 21 - 0
engine/src/core-effects/Common/MatDefs/Post/Fog.frag

@@ -0,0 +1,21 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+varying vec2 texCoord;
+
+uniform vec4 m_FogColor;
+uniform float m_FogDensity;
+uniform float m_FogDistance;
+
+vec2 m_FrustumNearFar=vec2(1.0,m_FogDistance);
+const float LOG2 = 1.442695;
+
+void main() {
+       vec4 texVal = texture2D(m_Texture, texCoord);      
+       float fogVal =texture2D(m_DepthTexture,texCoord).r;
+       float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - fogVal* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+       float fogFactor = exp2( -m_FogDensity * m_FogDensity * depth *  depth * LOG2 );
+       fogFactor = clamp(fogFactor, 0.0, 1.0);
+       gl_FragColor =mix(m_FogColor,texVal,fogFactor);
+
+}

+ 39 - 0
engine/src/core-effects/Common/MatDefs/Post/Fog.j3md

@@ -0,0 +1,39 @@
+MaterialDef Fade {
+
+    MaterialParameters {
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D Texture
+        Texture2D DepthTexture
+        Vector4 FogColor;
+        Float FogDensity;
+        Float FogDistance;
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/Fog15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+        }
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/Fog.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+
+    Technique FixedFunc {
+    }
+
+}

+ 24 - 0
engine/src/core-effects/Common/MatDefs/Post/Fog15.frag

@@ -0,0 +1,24 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform vec4 m_FogColor;
+uniform float m_FogDensity;
+uniform float m_FogDistance;
+
+in vec2 texCoord;
+
+vec2 m_FrustumNearFar=vec2(1.0,m_FogDistance);
+const float LOG2 = 1.442695;
+
+void main() {
+       vec4 texVal = getColor(m_Texture, texCoord);
+       float fogVal = getDepth(m_DepthTexture,texCoord).r;
+       float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - fogVal* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+       float fogFactor = exp2( -m_FogDensity * m_FogDensity * depth *  depth * LOG2 );
+       fogFactor = clamp(fogFactor, 0.0, 1.0);
+       gl_FragColor =mix(m_FogColor,texVal,fogFactor);
+
+}

+ 23 - 0
engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.frag

@@ -0,0 +1,23 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+
+uniform float m_gamma;
+
+vec3 gamma(vec3 L,float gamma)
+{
+	return pow(L, vec3(1.0 / gamma));
+}
+
+void main() {
+    vec4 texVal = texture2D(m_Texture, texCoord);
+ 
+ 	if(m_gamma > 0.0)
+ 	{
+    	texVal.rgb = gamma(texVal.rgb , m_gamma);
+ 	}
+ 	#ifdef COMPUTE_LUMA
+ 		texVal.a = dot(texVal.rgb, vec3(0.299, 0.587, 0.114));
+ 	#endif
+ 	
+    gl_FragColor = texVal;
+}

+ 39 - 0
engine/src/core-effects/Common/MatDefs/Post/GammaCorrection.j3md

@@ -0,0 +1,39 @@
+MaterialDef GammaCorrection {
+ 
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture
+        Float gamma
+        Boolean computeLuma
+    }
+ 
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/GammaCorrection15.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+        
+        Defines {
+            COMPUTE_LUMA : computeLuma
+        }
+    }
+ 
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/GammaCorrection.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+        
+         Defines {
+            COMPUTE_LUMA : computeLuma
+        }
+    }
+ 
+    Technique FixedFunc {
+    }
+ 
+}

+ 26 - 0
engine/src/core-effects/Common/MatDefs/Post/GammaCorrection15.frag

@@ -0,0 +1,26 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+ 
+uniform COLORTEXTURE m_Texture;
+in vec2 texCoord;
+ 
+uniform float m_gamma;
+
+vec3 gamma(vec3 L,float gamma)
+{
+	return pow(L, vec3(1.0 / gamma));
+}
+ 
+void main() {
+    vec4 texVal = texture2D(m_Texture, texCoord);
+ 
+ 	if(m_gamma > 0.0)
+ 	{
+    	texVal.rgb = gamma(texVal.rgb , m_gamma);
+ 	}
+ 	
+ 	#ifdef COMPUTE_LUMA
+ 		texVal.a = dot(texVal.rgb, vec3(0.299, 0.587, 0.114));
+ 	#endif
+ 
+    gl_FragColor = texVal;
+}

+ 36 - 0
engine/src/core-effects/Common/MatDefs/Post/LightScattering.frag

@@ -0,0 +1,36 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform int m_NbSamples;
+uniform float m_BlurStart;
+uniform float m_BlurWidth;
+uniform float m_LightDensity;
+uniform bool m_Display;
+
+varying vec2 lightPos;
+varying vec2 texCoord;
+
+void main(void)
+{
+   if(m_Display){
+
+       vec4 colorRes= texture2D(m_Texture,texCoord);
+       float factor=(m_BlurWidth/float(m_NbSamples-1.0));
+       float scale;
+       vec2 texCoo=texCoord-lightPos;
+       vec2 scaledCoord;
+       vec4 res = vec4(0.0);
+       for(int i=0; i<m_NbSamples; i++) {
+            scale = i * factor + m_BlurStart ;
+            scaledCoord=texCoo*scale+lightPos;
+            if(texture2D(m_DepthTexture,scaledCoord).r==1.0){
+                res += texture2D(m_Texture,scaledCoord);
+            }
+        }
+        res /= m_NbSamples;
+
+        //Blend the original color with the averaged pixels
+        gl_FragColor =mix( colorRes, res, m_LightDensity);
+    }else{
+        gl_FragColor= texture2D(m_Texture,texCoord);
+    }
+}

+ 41 - 0
engine/src/core-effects/Common/MatDefs/Post/LightScattering.j3md

@@ -0,0 +1,41 @@
+MaterialDef Light Scattering {
+ MaterialParameters {
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D Texture
+        Texture2D DepthTexture       
+        Vector3 LightPosition
+        Int NbSamples
+        Float BlurStart
+        Float BlurWidth
+        Float LightDensity
+        Boolean Display
+        Boolean multiSampledDepth
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/LightScattering15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/LightScattering15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+        }
+    }
+
+    Technique {
+        VertexShader GLSL120:   Common/MatDefs/Post/LightScattering.vert
+        FragmentShader GLSL120: Common/MatDefs/Post/LightScattering.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+
+    Technique FixedFunc {
+    }
+}

+ 14 - 0
engine/src/core-effects/Common/MatDefs/Post/LightScattering.vert

@@ -0,0 +1,14 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec3 m_LightPosition;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+varying vec2 texCoord;
+varying vec2 lightPos;
+
+void main() {
+    vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+    gl_Position = vec4(pos, 0.0, 1.0);
+    lightPos=m_LightPosition.xy;
+    texCoord = inTexCoord;
+}

+ 39 - 0
engine/src/core-effects/Common/MatDefs/Post/LightScattering15.frag

@@ -0,0 +1,39 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform int m_NbSamples;
+uniform float m_BlurStart;
+uniform float m_BlurWidth;
+uniform float m_LightDensity;
+uniform bool m_Display;
+
+in vec2 lightPos;
+in vec2 texCoord;
+
+void main(void)
+{
+   if(m_Display){
+
+       vec4 colorRes= getColor(m_Texture,texCoord);
+       float factor=(m_BlurWidth/float(m_NbSamples-1.0));
+       float scale;
+       vec2 texCoo=texCoord-lightPos;
+       vec2 scaledCoord;
+       vec4 res = vec4(0.0);
+       for(int i=0; i<m_NbSamples; i++) {
+            scale = i * factor + m_BlurStart ;
+            scaledCoord=texCoo*scale+lightPos;            
+            if(fetchTextureSample(m_DepthTexture, scaledCoord,0).r==1.0){
+                res += fetchTextureSample(m_Texture,scaledCoord,0);
+            }
+        }
+        res /= m_NbSamples;
+
+        //Blend the original color with the averaged pixels
+        gl_FragColor =mix( colorRes, res, m_LightDensity);
+    }else{
+        gl_FragColor= getColor(m_Texture,texCoord);
+    }
+}

+ 14 - 0
engine/src/core-effects/Common/MatDefs/Post/LightScattering15.vert

@@ -0,0 +1,14 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform vec3 m_LightPosition;
+
+in vec4 inPosition;
+in vec2 inTexCoord;
+out vec2 texCoord;
+out vec2 lightPos;
+
+void main() {
+    vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+    gl_Position = vec4(pos, 0.0, 1.0);
+    lightPos=m_LightPosition.xy;
+    texCoord = inTexCoord;
+}

+ 9 - 0
engine/src/core-effects/Common/MatDefs/Post/Overlay.frag

@@ -0,0 +1,9 @@
+uniform sampler2D m_Texture;
+uniform vec4 m_Color;
+varying vec2 texCoord;
+
+void main() {
+      vec4 texVal = texture2D(m_Texture, texCoord);
+      gl_FragColor = texVal * m_Color;
+}
+

+ 36 - 0
engine/src/core-effects/Common/MatDefs/Post/Overlay.j3md

@@ -0,0 +1,36 @@
+MaterialDef Default GUI {
+
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture
+        Color Color        
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/Overlay15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+        }
+
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/Overlay.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+    }
+
+    Technique FixedFunc {
+    }
+
+}

+ 11 - 0
engine/src/core-effects/Common/MatDefs/Post/Overlay15.frag

@@ -0,0 +1,11 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform vec4 m_Color;
+in vec2 texCoord;
+
+void main() {
+      vec4 texVal = getColor(m_Texture, texCoord);
+      gl_FragColor = texVal * m_Color;
+}
+

+ 10 - 0
engine/src/core-effects/Common/MatDefs/Post/Post.vert

@@ -0,0 +1,10 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+varying vec2 texCoord;
+
+void main() {  
+    gl_Position = inPosition * 2.0 - 1.0; //vec4(pos, 0.0, 1.0);
+    texCoord = inTexCoord;
+}

+ 12 - 0
engine/src/core-effects/Common/MatDefs/Post/Post15.vert

@@ -0,0 +1,12 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+in vec4 inPosition;
+in vec2 inTexCoord;
+
+out vec2 texCoord;
+
+void main() {
+    vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+    gl_Position = vec4(pos, 0.0, 1.0);
+    texCoord = inTexCoord;
+}

+ 18 - 0
engine/src/core-effects/Common/MatDefs/Post/Posterization.frag

@@ -0,0 +1,18 @@
+uniform sampler2D m_Texture;
+varying vec2 texCoord;
+ 
+uniform int m_NumColors;
+uniform float m_Gamma;
+uniform float m_Strength;
+ 
+void main() {
+    vec4 texVal = texture2D(m_Texture, texCoord);
+ 
+    texVal = pow(texVal, vec4(m_Gamma));
+    texVal = texVal * vec4(m_NumColors);
+    texVal = floor(texVal);
+    texVal = texVal / vec4(m_NumColors);
+    texVal = pow(texVal, vec4(1.0/m_Gamma));
+ 
+    gl_FragColor = mix(texture2D(m_Texture, texCoord), texVal, m_Strength);
+}

+ 32 - 0
engine/src/core-effects/Common/MatDefs/Post/Posterization.j3md

@@ -0,0 +1,32 @@
+MaterialDef Posterization {
+ 
+    MaterialParameters {
+        Int NumSamples
+        Texture2D Texture;
+        Int NumColors;
+        Float Gamma;
+        Float Strength;
+    }
+ 
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/Post/Posterization15.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+ 
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL100: Common/MatDefs/Post/Posterization.frag
+ 
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+    }
+ 
+    Technique FixedFunc {
+    }
+ 
+}

+ 20 - 0
engine/src/core-effects/Common/MatDefs/Post/Posterization15.frag

@@ -0,0 +1,20 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+ 
+uniform COLORTEXTURE m_Texture;
+in vec2 texCoord;
+ 
+uniform int m_NumColors;
+uniform float m_Gamma;
+uniform float m_Strength;
+ 
+void main() {
+    vec4 texVal = getColor(m_Texture, texCoord);
+ 
+    texVal = pow(texVal, vec4(m_Gamma));
+    texVal = texVal * m_NumColors;
+    texVal = floor(texVal);
+    texVal = texVal / m_NumColors;
+    texVal = pow(texVal, vec4(1.0/m_Gamma));
+ 
+    gl_FragColor = mix(getColor(m_Texture, texCoord), texVal, m_Strength);
+}

+ 29 - 0
engine/src/core-effects/Common/MatDefs/Post/bloomExtract.frag

@@ -0,0 +1,29 @@
+uniform float m_ExposurePow;
+uniform float m_ExposureCutoff;
+uniform sampler2D m_Texture;
+
+varying vec2 texCoord;
+
+#ifdef HAS_GLOWMAP
+  uniform sampler2D m_GlowMap;
+#endif
+
+void main(){ 
+   vec4 color = vec4(0.0);
+   #ifdef DO_EXTRACT
+    color = texture2D( m_Texture, texCoord );
+    if ( (color.r+color.g+color.b)/3.0 < m_ExposureCutoff ) {
+          color = vec4(0.0);
+    }else{
+          color = pow(color,vec4(m_ExposurePow));
+    }
+   #endif
+
+   #ifdef HAS_GLOWMAP
+        vec4 glowColor = texture2D(m_GlowMap, texCoord);
+        glowColor = pow(glowColor, vec4(m_ExposurePow));
+        color += glowColor;
+   #endif
+   
+   gl_FragColor = color;
+}

+ 33 - 0
engine/src/core-effects/Common/MatDefs/Post/bloomExtract15.frag

@@ -0,0 +1,33 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+
+uniform float m_ExposurePow;
+uniform float m_ExposureCutoff;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+#ifdef HAS_GLOWMAP
+  uniform sampler2D m_GlowMap;
+#endif
+
+void main(){
+   vec4 color = vec4(0.0);
+   #ifdef DO_EXTRACT
+     color = getColorSingle(m_Texture, texCoord);
+     if ( (color.r + color.g + color.b) / 3.0 >= m_ExposureCutoff ) {
+         color = pow(color, vec4(m_ExposurePow));
+     }else{
+         color = vec4(0.0);
+     }
+   #endif
+
+   #ifdef HAS_GLOWMAP
+        vec4 glowColor = texture2D( m_GlowMap, texCoord );
+        glowColor = pow(glowColor, vec4(m_ExposurePow));
+        color += glowColor;
+   #endif
+   
+   outFragColor = color;
+}

+ 12 - 0
engine/src/core-effects/Common/MatDefs/Post/bloomFinal.frag

@@ -0,0 +1,12 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_BloomTex;
+uniform float m_BloomIntensity;
+
+varying vec2 texCoord;
+
+void main(){
+   vec4 colorRes = texture2D(m_Texture, texCoord);
+   vec4 bloom = texture2D(m_BloomTex, texCoord);
+   gl_FragColor = bloom * m_BloomIntensity + colorRes;
+}
+

+ 15 - 0
engine/src/core-effects/Common/MatDefs/Post/bloomFinal15.frag

@@ -0,0 +1,15 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+
+uniform sampler2D m_BloomTex;
+uniform float m_BloomIntensity;
+
+in vec2 texCoord;
+
+void main(){
+  vec4 colorRes = getColor(m_Texture,texCoord);
+  vec4 bloom = texture2D(m_BloomTex, texCoord);
+  gl_FragColor = bloom * m_BloomIntensity + colorRes;
+}
+

BIN
engine/src/core-effects/Common/MatDefs/SSAO/Textures/random.png


+ 21 - 0
engine/src/core-effects/Common/MatDefs/SSAO/normal.frag

@@ -0,0 +1,21 @@
+varying vec3 normal;
+varying vec2 texCoord;
+
+
+#ifdef DIFFUSEMAP_ALPHA
+    uniform sampler2D m_DiffuseMap;
+    uniform float m_AlphaDiscardThreshold;
+#endif
+
+void main(void)
+{
+
+    #ifdef DIFFUSEMAP_ALPHA
+        if(texture2D(m_DiffuseMap,texCoord).a<m_AlphaDiscardThreshold){
+            discard;
+        }
+    #endif
+    gl_FragColor = vec4(normal.xy* 0.5 + 0.5,-normal.z* 0.5 + 0.5, 1.0);
+
+}
+

+ 16 - 0
engine/src/core-effects/Common/MatDefs/SSAO/normal.vert

@@ -0,0 +1,16 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform mat3 g_NormalMatrix;
+
+attribute vec3 inPosition;
+attribute vec3 inNormal;
+attribute vec4 inTexCoord;
+
+varying vec3 normal;
+varying vec2 texCoord;
+
+void main(void)
+{
+   texCoord=inTexCoord.xy;
+   normal = normalize(g_NormalMatrix * inNormal);
+   gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition,1.0);
+}

+ 104 - 0
engine/src/core-effects/Common/MatDefs/SSAO/ssao.frag

@@ -0,0 +1,104 @@
+uniform vec2 g_Resolution;
+uniform vec2 m_FrustumNearFar;
+uniform sampler2D m_Texture;
+uniform sampler2D m_Normals;
+uniform sampler2D m_DepthTexture;
+uniform vec3 m_FrustumCorner;
+uniform float m_SampleRadius;
+uniform float m_Intensity;
+uniform float m_Scale;
+uniform float m_Bias;
+uniform bool m_UseOnlyAo;
+uniform bool m_UseAo;
+uniform vec2[4] m_Samples;
+
+varying vec2 texCoord;
+
+float depthv;
+
+vec3 getPosition(in vec2 uv){
+  //Reconstruction from depth
+  depthv =texture2D(m_DepthTexture,uv).r;
+  float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+  //one frustum corner method
+  float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x);
+  float y = mix(-m_FrustumCorner.y, m_FrustumCorner.y, uv.y);
+
+  return depth* vec3(x, y, m_FrustumCorner.z);
+}
+
+vec3 getNormal(in vec2 uv){
+  return normalize(texture2D(m_Normals, uv).xyz * 2.0 - 1.0);
+}
+
+vec2 getRandom(in vec2 uv){
+   float rand=(fract(uv.x*(g_Resolution.x/2.0))*0.25)+(fract(uv.y*(g_Resolution.y/2.0))*0.5);
+   return normalize(vec2(rand,rand));
+}
+
+float doAmbientOcclusion(in vec2 tc, in vec3 pos, in vec3 norm){
+   vec3 diff = getPosition(tc)- pos;
+   vec3 v = normalize(diff);
+   float d = length(diff) * m_Scale;
+
+   return max(0.0, dot(norm, v) - m_Bias) * ( 1.0/(1.0 + d) ) * m_Intensity;
+}
+
+vec4 getColor(in float result){
+
+ if(m_UseOnlyAo){
+     return vec4(result,result,result, 1.0);
+ }
+ if(m_UseAo){
+      return texture2D(m_Texture,texCoord)* vec4(result,result,result, 1.0);
+  }else{
+      return texture2D(m_Texture,texCoord);
+  }
+
+}
+
+vec2 reflection(in vec2 v1,in vec2 v2){
+    vec2 result= 2.0 * dot(v2, v1) * v2;
+    result=v1-result;
+    return result;
+}
+
+
+//const vec2 vec[4] = vec2[4](vec2(1.0,0.0), vec2(-1.0,0.0), vec2(0.0,1.0), vec2(0.0,-1.0));
+void main(){
+
+   float result;
+
+   //vec2 vec[4] = { vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0) };
+   vec3 position = getPosition(texCoord);
+    //optimization, do not calculate AO if depth is 1
+   if(depthv==1.0){
+        gl_FragColor=getColor(1.0);
+        return;
+   }
+   vec3 normal = getNormal(texCoord);
+   vec2 rand = getRandom(texCoord);
+
+   float ao = 0.0;
+   float rad =m_SampleRadius / position.z;
+
+
+   int iterations = 4;
+   for (int j = 0; j < iterations; ++j){
+      vec2 coord1 = reflection(vec2(m_Samples[j]), vec2(rand)) * vec2(rad,rad);
+      vec2 coord2 = vec2(coord1.x* 0.707 - coord1.y* 0.707, coord1.x* 0.707 + coord1.y* 0.707) ;
+
+      ao += doAmbientOcclusion(texCoord + coord1.xy * 0.25, position, normal);
+      ao += doAmbientOcclusion(texCoord + coord2 * 0.50, position, normal);
+      ao += doAmbientOcclusion(texCoord + coord1.xy * 0.75, position, normal);
+      ao += doAmbientOcclusion(texCoord + coord2 * 1.00, position, normal);
+
+   }
+   ao /= float(iterations) * 4.0;
+   result = 1.0-ao;
+
+   gl_FragColor=getColor(result);
+
+//gl_FragColor=vec4(normal,1.0);
+}

+ 51 - 0
engine/src/core-effects/Common/MatDefs/SSAO/ssao.j3md

@@ -0,0 +1,51 @@
+MaterialDef SSAO {
+
+    MaterialParameters {
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D Texture
+        Texture2D RandomMap
+        Texture2D Normals
+        Texture2D DepthTexture
+        Vector3 FrustumCorner
+        Float SampleRadius
+        Float Intensity
+        Float Scale
+        Float Bias
+        Vector2 FrustumNearFar
+        Vector2Array Samples
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/SSAO/ssao15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+        }
+
+        Defines {
+            RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+        }
+    }
+
+    Technique {
+        VertexShader GLSL120:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL120: Common/MatDefs/SSAO/ssao.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+
+        }
+    }
+
+
+
+    Technique FixedFunc {
+    }
+}

+ 96 - 0
engine/src/core-effects/Common/MatDefs/SSAO/ssao15.frag

@@ -0,0 +1,96 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+uniform vec2 g_Resolution;
+uniform vec2 m_FrustumNearFar;
+uniform sampler2D m_Normals;
+uniform sampler2D m_RandomMap;
+uniform vec3 m_FrustumCorner;
+uniform float m_SampleRadius;
+uniform float m_Intensity;
+uniform float m_Scale;
+uniform float m_Bias;
+uniform vec2[4] m_Samples;
+
+in vec2 texCoord;
+
+float depthv;
+
+vec3 getPosition(in vec2 uv){
+  //Reconstruction from depth
+  depthv =getDepth(m_DepthTexture,uv).r;
+  float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+
+  //one frustum corner method
+  float x = mix(-m_FrustumCorner.x, m_FrustumCorner.x, uv.x);
+  float y = mix(-m_FrustumCorner.y, m_FrustumCorner.y, uv.y);
+
+  return depth* vec3(x, y, m_FrustumCorner.z);
+}
+
+vec3 getNormal(in vec2 uv){
+  return normalize(texture2D(m_Normals, uv).xyz * 2.0 - 1.0);
+}
+
+vec2 getRandom(in vec2 uv){
+   //float rand=(fract(uv.x*(g_Resolution.x/2.0))*0.25)+(fract(uv.y*(g_Resolution.y/2.0))*0.5);
+   vec4 rand=texture2D(m_RandomMap,g_Resolution * uv / 128.0 * 3.0)*2.0 -1.0;
+
+   return normalize(rand.xy);
+}
+
+float doAmbientOcclusion(in vec2 tc, in vec3 pos, in vec3 norm){
+   vec3 diff = getPosition(tc)- pos;
+   vec3 v = normalize(diff);
+   float d = length(diff) * m_Scale;
+
+   return max(0.0, dot(norm, v) - m_Bias) * ( 1.0/(1.0 + d) ) * m_Intensity;
+}
+
+
+vec2 reflection(in vec2 v1,in vec2 v2){
+    vec2 result= 2.0 * dot(v2, v1) * v2;
+    result=v1-result;
+    return result;
+}
+
+
+//const vec2 vec[4] = vec2[4](vec2(1.0,0.0), vec2(-1.0,0.0), vec2(0.0,1.0), vec2(0.0,-1.0));
+void main(){
+
+   float result;
+
+   //vec2 vec[4] = { vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0) };
+   vec3 position = getPosition(texCoord);
+    //optimization, do not calculate AO if depth is 1
+   if(depthv==1.0){
+        gl_FragColor=vec4(1.0);
+        return;
+   }
+   vec3 normal = getNormal(texCoord);
+   vec2 rand = getRandom(texCoord);
+
+   float ao = 0.0;
+   float rad =m_SampleRadius / position.z;
+
+
+   int iterations = 4;
+   for (int j = 0; j < iterations; ++j){
+      vec2 coord1 = reflection(vec2(m_Samples[j]), rand) * vec2(rad,rad);
+      vec2 coord2 = vec2(coord1.x* 0.707 - coord1.y* 0.707, coord1.x* 0.707 + coord1.y* 0.707) ;
+
+      ao += doAmbientOcclusion(texCoord + coord1.xy * 0.25, position, normal);
+      ao += doAmbientOcclusion(texCoord + coord2 * 0.50, position, normal);
+      ao += doAmbientOcclusion(texCoord + coord1.xy * 0.75, position, normal);
+      ao += doAmbientOcclusion(texCoord + coord2 * 1.00, position, normal);
+
+   }
+   ao /= float(iterations) * 4.0;
+   result = 1.0-ao;
+
+   gl_FragColor=vec4(result,result,result, 1.0);
+//gl_FragColor=vec4(depthv,depthv,depthv, 1.0);
+
+}

+ 159 - 0
engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.frag

@@ -0,0 +1,159 @@
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform sampler2D m_SSAOMap;
+uniform vec2 g_Resolution;
+uniform bool m_UseOnlyAo;
+uniform bool m_UseAo;
+uniform float m_XScale;
+uniform float m_YScale;
+uniform vec2 m_FrustumNearFar;
+
+varying vec2 texCoord;
+
+vec4 getColor(vec4 color){
+
+    
+    #ifdef USE_ONLY_AO
+        return color;
+    #endif
+    #ifdef USE_AO
+        return texture2D(m_Texture,texCoord)* color;
+    #endif
+    
+    return texture2D(m_Texture,texCoord);
+
+}
+
+float readDepth(in vec2 uv){
+    float depthv =texture2D(m_DepthTexture,uv).r;
+    return (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+}
+
+ const float epsilon = 0.005;
+
+
+/*
+    const int kernelSize=7;
+   
+    vec4 bilateralFilter() {
+        vec4 color = vec4(0.0);
+
+        vec2 sample;
+        float sum = 0.0;
+        float coefZ;
+        float Zp = readDepth(texCoord);
+
+        for(int i = -(kernelSize-1); i <= (kernelSize-1); i+=2) {
+            for(int j = -(kernelSize-1); j <= (kernelSize-1); j+=2) {
+                  sample = texCoord + vec2(i,j) / g_Resolution;           
+                float zTmp =readDepth(sample);
+                coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+                sum += coefZ;
+
+                color += coefZ * texture2D(m_SSAOMap,sample);
+             
+            }
+        }
+
+        return color / sum;
+    }
+*/
+
+    vec4 convolutionFilter(){
+           vec4 sum = vec4(0.0);
+
+            float x = texCoord.x;
+            float y = texCoord.y;
+
+            float xScale = m_XScale;
+            float yScale = m_YScale;
+       
+            float zsum = 1.0;
+        float Zp =readDepth(texCoord);
+
+
+        vec2 sample = vec2(x - 2.0 * xScale, y - 2.0 * yScale);           
+        float zTmp =readDepth(sample);
+        float coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 0.0 * xScale, y - 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 2.0 * xScale, y - 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 1.0 * xScale, y - 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 1.0 * xScale, y - 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+  
+        sample = vec2(x - 2.0 * xScale, y - 0.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 2.0 * xScale, y - 0.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 1.0 * xScale, y + 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+   
+        sample = vec2(x + 1.0 * xScale, y + 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 2.0 * xScale, y + 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+  
+        sample = vec2(x - 0.0 * xScale, y + 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 2.0 * xScale, y + 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+
+        return  sum / zsum;
+    }
+
+
+    void main(){
+        //  float depth =texture2D(m_DepthTexture,uv).r;
+
+       gl_FragColor=getColor(convolutionFilter());
+      // gl_FragColor=getColor(bilateralFilter());
+      //  gl_FragColor=texture2D(m_SSAOMap,texCoord);
+
+    }

+ 57 - 0
engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur.j3md

@@ -0,0 +1,57 @@
+MaterialDef SSAOBlur {
+
+    MaterialParameters {       
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D Texture
+        Texture2D SSAOMap
+        Texture2D DepthTexture
+        Vector2 FrustumNearFar
+        Boolean UseAo
+        Boolean UseOnlyAo        
+        Float XScale
+        Float YScale
+    }
+
+    Technique {
+        VertexShader GLSL150:   Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150: Common/MatDefs/SSAO/ssaoBlur15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+        }
+
+        Defines {
+            USE_AO : UseAo
+            USE_ONLY_AO : UseOnlyAo
+            RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+        }
+    }
+
+    Technique {
+        VertexShader GLSL120:   Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL120: Common/MatDefs/SSAO/ssaoBlur.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+
+        }
+        
+        Defines {
+            USE_AO : UseAo
+            USE_ONLY_AO : UseOnlyAo
+            RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+        }
+    }
+
+
+
+    Technique FixedFunc {
+    }
+}

+ 160 - 0
engine/src/core-effects/Common/MatDefs/SSAO/ssaoBlur15.frag

@@ -0,0 +1,160 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+uniform sampler2D m_SSAOMap;
+uniform vec2 g_Resolution;
+uniform bool m_UseOnlyAo;
+uniform bool m_UseAo;
+uniform float m_XScale;
+uniform float m_YScale;
+uniform vec2 m_FrustumNearFar;
+
+in vec2 texCoord;
+
+vec4 getResult(vec4 color){
+ 
+    #ifdef USE_ONLY_AO
+        return color;
+    #endif
+    #ifdef USE_AO
+        return getColor(m_Texture,texCoord)* color;
+    #endif
+    
+    return getColor(m_Texture,texCoord);
+
+}
+
+float readDepth(in vec2 uv){
+    float depthv =fetchTextureSample(m_DepthTexture,uv,0).r;
+    return (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - depthv* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+}
+
+ const float epsilon = 0.005;
+
+
+/*
+    const int kernelSize=7;
+   
+    vec4 bilateralFilter() {
+        vec4 color = vec4(0.0);
+
+        vec2 sample;
+        float sum = 0.0;
+        float coefZ;
+        float Zp = readDepth(texCoord);
+
+        for(int i = -(kernelSize-1); i <= (kernelSize-1); i+=2) {
+            for(int j = -(kernelSize-1); j <= (kernelSize-1); j+=2) {
+                  sample = texCoord + vec2(i,j) / g_Resolution;           
+                float zTmp =readDepth(sample);
+                coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+                sum += coefZ;
+
+                color += coefZ * texture2D(m_SSAOMap,sample);
+             
+            }
+        }
+
+        return color / sum;
+    }
+*/
+
+    vec4 convolutionFilter(){
+           vec4 sum = vec4(0.0);
+
+            float x = texCoord.x;
+            float y = texCoord.y;
+
+            float xScale = m_XScale;
+            float yScale = m_YScale;
+       
+            float zsum = 1.0;
+        float Zp =readDepth(texCoord);
+
+
+        vec2 sample = vec2(x - 2.0 * xScale, y - 2.0 * yScale);           
+        float zTmp =readDepth(sample);
+        float coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 0.0 * xScale, y - 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 2.0 * xScale, y - 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 1.0 * xScale, y - 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 1.0 * xScale, y - 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+  
+        sample = vec2(x - 2.0 * xScale, y - 0.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 2.0 * xScale, y - 0.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 1.0 * xScale, y + 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+   
+        sample = vec2(x + 1.0 * xScale, y + 1.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x - 2.0 * xScale, y + 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+  
+        sample = vec2(x - 0.0 * xScale, y + 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+        sample = vec2(x + 2.0 * xScale, y + 2.0 * yScale);           
+        zTmp =readDepth(sample);
+        coefZ = 1.0 / (epsilon + abs(Zp - zTmp));               
+        zsum += coefZ;
+        sum += coefZ* texture2D( m_SSAOMap, sample);
+
+
+        return  sum / zsum;
+    }
+
+
+    void main(){
+        //  float depth =texture2D(m_DepthTexture,uv).r;
+
+       gl_FragColor=getResult(convolutionFilter());
+      // gl_FragColor=getResult(bilateralFilter());
+      //  gl_FragColor=getColor(m_SSAOMap,texCoord);
+
+    }

+ 34 - 0
engine/src/core-effects/Common/MatDefs/Water/SimpleWater.j3md

@@ -0,0 +1,34 @@
+MaterialDef Simple Water {
+
+    MaterialParameters {
+        Texture2D water_reflection
+        Texture2D water_refraction
+        Texture2D water_depthmap
+        Texture2D water_normalmap
+        Texture2D water_dudvmap
+        Vector4 waterColor
+        Vector3 lightPos
+        Float time
+        Float waterDepth
+        Vector4 distortionScale
+        Vector4 distortionMix
+        Vector4 texScale
+        Vector2 FrustumNearFar
+        Float waterTransparency
+    }
+
+    Technique {
+        VertexShader GLSL100:   Common/MatDefs/Water/simple_water.vert
+        FragmentShader GLSL100: Common/MatDefs/Water/simple_water.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+            WorldViewMatrix
+            Resolution
+            CameraPosition
+        }
+    }
+
+    Technique FixedFunc {
+    }
+}

BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/caustics.jpg


BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/dudv_map.jpg


BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/foam.jpg


BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/foam2.jpg


BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/foam3.jpg


BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/heightmap.jpg


BIN
engine/src/core-effects/Common/MatDefs/Water/Textures/water_normalmap.dds


+ 402 - 0
engine/src/core-effects/Common/MatDefs/Water/Water.frag

@@ -0,0 +1,402 @@
+// Water pixel shader
+// Copyright (C) JMonkeyEngine 3.0
+// by Remy Bouquet (nehon) for JMonkeyEngine 3.0
+// original HLSL version by Wojciech Toman 2009
+
+uniform sampler2D m_HeightMap;
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform sampler2D m_NormalMap;
+uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
+uniform sampler2D m_ReflectionMap;
+
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform mat4 m_TextureProjMatrix;
+uniform vec3 m_CameraPosition;
+
+uniform float m_WaterHeight;
+uniform float m_Time;
+uniform float m_WaterTransparency;
+uniform float m_NormalScale;
+uniform float m_R0;
+uniform float m_MaxAmplitude;
+uniform vec3 m_LightDir;
+uniform vec4 m_LightColor;
+uniform float m_ShoreHardness;
+uniform float m_FoamHardness;
+uniform float m_RefractionStrength;
+uniform vec3 m_FoamExistence;
+uniform vec3 m_ColorExtinction;
+uniform float m_Shininess;
+uniform vec4 m_WaterColor;
+uniform vec4 m_DeepWaterColor;
+uniform vec2 m_WindDirection;
+uniform float m_SunScale;
+uniform float m_WaveScale;
+uniform float m_UnderWaterFogDistance;
+uniform float m_CausticsIntensity;
+
+vec2 scale = vec2(m_WaveScale, m_WaveScale);
+float refractionScale = m_WaveScale;
+
+// Modifies 4 sampled normals. Increase first values to have more
+// smaller "waves" or last to have more bigger "waves"
+const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0);
+// Strength of displacement along normal.
+// Strength of displacement along normal.
+uniform float m_ReflectionDisplace;
+// Water transparency along eye vector.
+const float visibility = 3.0;
+// foam intensity
+uniform float m_FoamIntensity ;
+
+varying vec2 texCoord;
+
+mat3 MatrixInverse(in mat3 inMatrix){  
+    float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);
+    mat3 T = transpose(inMatrix);
+    return mat3(cross(T[1], T[2]),
+        cross(T[2], T[0]),
+        cross(T[0], T[1])) / det;
+}
+
+
+mat3 computeTangentFrame(in vec3 N, in vec3 P, in vec2 UV) {
+    vec3 dp1 = dFdx(P);
+    vec3 dp2 = dFdy(P);
+    vec2 duv1 = dFdx(UV);
+    vec2 duv2 = dFdy(UV);
+
+    // solve the linear system
+    mat3 M = mat3(dp1, dp2, cross(dp1, dp2));
+    //vec3 dp1xdp2 = cross(dp1, dp2);
+    mat3 inverseM = MatrixInverse(M);
+    //mat2x3 inverseM = mat2x3(cross(dp2, dp1xdp2), cross(dp1xdp2, dp1));
+
+    vec3 T = inverseM * vec3(duv1.x, duv2.x, 0.0);
+    vec3 B = inverseM * vec3(duv1.y, duv2.y, 0.0);
+
+    //vec3 T = inverseM * vec2(duv1.x, duv2.x);
+    //vec3 B = inverseM * vec2(duv1.y, duv2.y);
+
+    // construct tangent frame
+    float maxLength = max(length(T), length(B));
+    T = T / maxLength;
+    B = B / maxLength;
+
+    //vec3 tangent = normalize(T);
+    //vec3 binormal = normalize(B);
+
+    return mat3(T, B, N);
+}
+
+float saturate(in float val){
+    return clamp(val,0.0,1.0);
+}
+
+vec3 saturate(in vec3 val){
+    return clamp(val,vec3(0.0),vec3(1.0));
+}
+
+
+vec3 getPosition(in float depth, in vec2 uv){
+    vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+    pos = m_ViewProjectionMatrixInverse * pos;
+    return pos.xyz / pos.w;
+}
+
+// Function calculating fresnel term.
+// - normal - normalized normal vector
+// - eyeVec - normalized eye vector
+float fresnelTerm(in vec3 normal,in vec3 eyeVec){
+    float angle = 1.0 - saturate(dot(normal, eyeVec));
+    float fresnel = angle * angle;
+    fresnel = fresnel * fresnel;
+    fresnel = fresnel * angle;
+    return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
+}
+
+vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance);
+const float LOG2 = 1.442695;
+
+vec4 underWater(){
+
+
+    float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
+    vec3 color2 = texture2D(m_Texture, texCoord).rgb;
+    
+    vec3 position = getPosition(sceneDepth, texCoord);
+    float level = m_WaterHeight;
+
+    vec3 eyeVec = position - m_CameraPosition;    
+ 
+    // Find intersection with water surface
+    vec3 eyeVecNorm = normalize(eyeVec);
+    float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+    vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+    vec2 texC = vec2(0.0);
+
+    float cameraDepth = length(m_CameraPosition - surfacePoint);  
+    texC = (surfacePoint.xz + eyeVecNorm.xz) * scale + m_Time * 0.03 * m_WindDirection;
+    float bias = texture2D(m_HeightMap, texC).r;
+    level += bias * m_MaxAmplitude;
+    t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+    surfacePoint = m_CameraPosition + eyeVecNorm * t; 
+    eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+    // Find normal of water surface
+    float normal1 = texture2D(m_HeightMap, (texC + vec2(-1.0, 0.0) / 256.0)).r;
+    float normal2 = texture2D(m_HeightMap, (texC + vec2(1.0, 0.0) / 256.0)).r;
+    float normal3 = texture2D(m_HeightMap, (texC + vec2(0.0, -1.0) / 256.0)).r;
+    float normal4 = texture2D(m_HeightMap, (texC + vec2(0.0, 1.0) / 256.0)).r;
+
+    vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+    vec3 normal = myNormal*-1.0;
+    float fresnel = fresnelTerm(normal, eyeVecNorm); 
+
+    vec3 refraction = color2;
+    #ifdef ENABLE_REFRACTION
+        texC = texCoord.xy *sin (fresnel+1.0);
+        refraction = texture2D(m_Texture, texC).rgb;
+    #endif 
+
+   float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+   refraction = mix(mix(refraction, m_DeepWaterColor.rgb * waterCol, m_WaterTransparency),  m_WaterColor.rgb* waterCol,m_WaterTransparency);
+
+    vec3 foam = vec3(0.0);
+    #ifdef ENABLE_FOAM    
+        texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+        vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+        if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+            foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity  * m_FoamIntensity * 0.3 *
+               saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+        }
+        foam *= m_LightColor.rgb;    
+    #endif
+
+
+
+    vec3 specular = vec3(0.0);   
+    vec3 color ;
+    float fogFactor;
+
+    if(position.y>level){
+        #ifdef ENABLE_SPECULAR
+            if(step(0.9999,sceneDepth)==1.0){
+                vec3 lightDir=normalize(m_LightDir);
+                vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+                float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+                specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+                specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+                specular=specular * m_LightColor.rgb * 100.0;
+            }
+        #endif
+        float fogIntensity= 8.0 * m_WaterTransparency;
+        fogFactor = exp2( -fogIntensity * fogIntensity * cameraDepth * 0.03 * LOG2 );
+        fogFactor = clamp(fogFactor, 0.0, 1.0);        
+        color =mix(m_DeepWaterColor.rgb,refraction,fogFactor);   
+        specular=specular*fogFactor;    
+        color = saturate(color + max(specular, foam ));
+    }else{
+        vec3 caustics = vec3(0.0);
+        #ifdef ENABLE_CAUSTICS 
+            vec2 windDirection=m_WindDirection;
+            texC = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time  + position.x) * 0.01;
+            vec2 texCoord2 = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time  + position.z) * 0.01;
+            caustics += (texture2D(m_CausticsMap, texC)+ texture2D(m_CausticsMap, texCoord2)).rgb;      
+            caustics=saturate(mix(m_WaterColor.rgb,caustics,m_CausticsIntensity));            
+            color=mix(color2,caustics,m_CausticsIntensity);          
+        #else
+            color=color2;
+        #endif
+                
+        float fogDepth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - sceneDepth* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+        float fogIntensity= 18 * m_WaterTransparency;
+        fogFactor = exp2( -fogIntensity * fogIntensity * fogDepth *  fogDepth * LOG2 );
+        fogFactor = clamp(fogFactor, 0.0, 1.0);
+        color =mix(m_DeepWaterColor.rgb,color,fogFactor);
+    }
+
+    return vec4(color, 1.0);   
+}
+
+void main(){
+    float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
+    float isAtFarPlane = step(0.99998, sceneDepth);
+
+    vec3 color2 = texture2D(m_Texture, texCoord).rgb;
+    vec3 color = color2;
+
+    vec3 position = getPosition(sceneDepth,texCoord);
+
+    float level = m_WaterHeight;
+
+    // If we are underwater let's go to under water function
+    if(level >= m_CameraPosition.y){
+        gl_FragColor = underWater();
+        return ;
+    }
+
+    //#ifndef ENABLE_RIPPLES
+    // This optimization won't work on NVIDIA cards if ripples are enabled
+    if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
+        gl_FragColor = vec4(color2, 1.0);
+        return;
+    }
+    //#endif
+
+    vec3 eyeVec = position - m_CameraPosition;
+    float diff = level - position.y;
+    float cameraDepth = m_CameraPosition.y - position.y;
+
+    // Find intersection with water surface
+    vec3 eyeVecNorm = normalize(eyeVec);
+    float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+    vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+    vec2 texC;
+    int samples = 1;
+    #ifdef ENABLE_HQ_SHORELINE
+        samples = 10;
+    #endif
+    float biasFactor = 1.0/samples;
+    for (int i = 0; i < samples; i++){
+        texC = (surfacePoint.xz + eyeVecNorm.xz * biasFactor) * scale + m_Time * 0.03 * m_WindDirection;
+
+        float bias = texture2D(m_HeightMap, texC).r;
+
+        bias *= biasFactor;
+        level += bias * m_MaxAmplitude;
+        t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+        surfacePoint = m_CameraPosition + eyeVecNorm * t;
+    }
+
+    float depth = length(position - surfacePoint);
+    float depth2 = surfacePoint.y - position.y;
+
+    // XXX: HACK ALERT: Increase water depth to infinity if at far plane
+    // Prevents "foam on horizon" issue
+    // For best results, replace the "100.0" below with the
+    // highest value in the m_ColorExtinction vec3
+    depth  += isAtFarPlane * 100.0;
+    depth2 += isAtFarPlane * 100.0;
+
+    eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+    // Find normal of water surface
+    float normal1 = texture2D(m_HeightMap, (texC + vec2(-1.0, 0.0) / 256.0)).r;
+    float normal2 = texture2D(m_HeightMap, (texC + vec2(1.0, 0.0) / 256.0)).r;
+    float normal3 = texture2D(m_HeightMap, (texC + vec2(0.0, -1.0) / 256.0)).r;
+    float normal4 = texture2D(m_HeightMap, (texC + vec2(0.0, 1.0) / 256.0)).r;
+
+    vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+    vec3 normal = vec3(0.0);
+
+    #ifdef ENABLE_RIPPLES
+        texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
+        mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal0a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+        texC = surfacePoint.xz * 0.4 + m_WindDirection * m_Time* 0.8;
+        tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal1a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+        texC = surfacePoint.xz * 0.2 + m_WindDirection * m_Time * 0.4;
+        tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal2a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+        texC = surfacePoint.xz * 0.1 + m_WindDirection * m_Time * 0.2;
+        tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal3a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+        normal = normalize(normal0a * normalModifier.x + normal1a * normalModifier.y +normal2a * normalModifier.z + normal3a * normalModifier.w);
+        // XXX: Here's another way to fix the terrain edge issue,
+        // But it requires GLSL 1.3 and still looks kinda incorrect
+        // around edges
+        // To make the shader 1.2 compatible we use a trick :
+        // we clamp the x value of the normal and compare it to it's former value instead of using isnan.
+        normal = clamp(normal.x,0.0,1.0)!=normal.x ? myNormal : normal;
+        //if (position.y > level){
+        //    gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
+        //    return;
+        //}
+    #else
+        normal = myNormal;
+    #endif
+    
+    vec3 refraction = color2;
+    #ifdef ENABLE_REFRACTION
+        texC = texCoord.xy;
+        texC += sin(m_Time*1.8  + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
+        refraction = texture2D(m_Texture, texC).rgb;
+    #endif
+
+    vec3 waterPosition = surfacePoint.xyz;
+    waterPosition.y -= (level - m_WaterHeight);
+    vec4 texCoordProj = m_TextureProjMatrix * vec4(waterPosition, 1.0);
+
+    texCoordProj.x = texCoordProj.x + m_ReflectionDisplace * normal.x;
+    texCoordProj.z = texCoordProj.z + m_ReflectionDisplace * normal.z;
+    texCoordProj /= texCoordProj.w;
+    texCoordProj.y = 1.0 - texCoordProj.y;
+
+    vec3 reflection = texture2D(m_ReflectionMap, texCoordProj.xy).rgb;
+
+    float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+    float depthN = depth * m_WaterTransparency;
+    float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+    refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
+        m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
+
+    vec3 foam = vec3(0.0);
+    #ifdef ENABLE_FOAM
+        texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+        vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+        if(depth2 < m_FoamExistence.x){
+            foam = (texture2D(m_FoamMap, texC).r + texture2D(m_FoamMap, texCoord2)).rgb * m_FoamIntensity;
+        }else if(depth2 < m_FoamExistence.y){
+            foam = mix((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity, vec4(0.0),
+                (depth2 - m_FoamExistence.x) / (m_FoamExistence.y - m_FoamExistence.x)).rgb;
+        }
+
+        if(m_MaxAmplitude - m_FoamExistence.z > 0.0001){
+           foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity  * m_FoamIntensity * 0.3 *
+               saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+        }
+        foam *= m_LightColor.rgb;
+    #endif
+
+    vec3 specular =vec3(0.0);
+    #ifdef ENABLE_SPECULAR
+        vec3 lightDir=normalize(m_LightDir);
+        vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+        float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+        specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+        specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+        //foam does not shine
+        specular=specular * m_LightColor.rgb - (5.0 * foam);
+    #endif
+
+    color = mix(refraction, reflection, fresnel);
+    color = mix(refraction, color, saturate(depth * m_ShoreHardness));
+    color = saturate(color + max(specular, foam ));
+    color = mix(refraction, color, saturate(depth* m_FoamHardness));
+        
+
+    // XXX: HACK ALERT:
+    // We trick the GeForces to think they have
+    // to calculate the derivatives for all these pixels by using step()!
+    // That way we won't get pixels around the edges of the terrain,
+    // Where the derivatives are undefined
+    if(position.y > level){
+            color = color2;
+    }
+
+    gl_FragColor = vec4(color,1.0);
+    
+}

+ 90 - 0
engine/src/core-effects/Common/MatDefs/Water/Water.j3md

@@ -0,0 +1,90 @@
+MaterialDef Advanced Water {
+
+    MaterialParameters {
+        Int NumSamples
+        Int NumSamplesDepth
+        Texture2D FoamMap
+        Texture2D CausticsMap
+        Texture2D NormalMap
+        Texture2D ReflectionMap
+        Texture2D HeightMap
+        Texture2D Texture
+        Texture2D DepthTexture        
+        Vector3 CameraPosition
+        Float Time
+        Vector3 frustumCorner
+        Matrix4 TextureProjMatrix
+        Matrix4 ViewProjectionMatrixInverse
+        Float WaterHeight
+        Vector3 LightDir
+        Float WaterTransparency
+        Float NormalScale
+        Float R0
+        Float MaxAmplitude
+        Color LightColor
+        Float ShoreHardness
+        Float FoamHardness
+        Float RefractionStrength
+        Float WaveScale
+        Vector3 FoamExistence
+        Float SunScale
+        Vector3 ColorExtinction
+        Float Shininess
+        Color WaterColor
+        Color DeepWaterColor
+        Vector2 WindDirection
+        Float ReflectionDisplace
+        Float FoamIntensity
+        Float CausticsIntensity
+        Float UnderWaterFogDistance
+
+        Boolean UseRipples
+        Boolean UseHQShoreline
+        Boolean UseSpecular
+        Boolean UseFoam
+        Boolean UseCaustics 
+        Boolean UseRefraction
+
+    }
+
+    Technique {
+        VertexShader   GLSL150 : Common/MatDefs/Post/Post15.vert
+        FragmentShader GLSL150 : Common/MatDefs/Water/Water15.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+
+        Defines {
+          RESOLVE_MS : NumSamples
+            RESOLVE_DEPTH_MS : NumSamplesDepth
+            ENABLE_RIPPLES : UseRipples
+            ENABLE_HQ_SHORELINE : UseHQShoreline
+            ENABLE_SPECULAR : UseSpecular
+            ENABLE_FOAM : UseFoam
+            ENABLE_CAUSTICS : UseCaustics
+            ENABLE_REFRACTION : UseRefraction
+        }
+    }
+
+    Technique {
+        VertexShader   GLSL100 : Common/MatDefs/Post/Post.vert
+        FragmentShader GLSL120 : Common/MatDefs/Water/Water.frag
+
+        WorldParameters {
+            WorldViewProjectionMatrix
+        }
+        Defines {
+            ENABLE_RIPPLES : UseRipples
+            ENABLE_HQ_SHORELINE : UseHQShoreline
+            ENABLE_SPECULAR : UseSpecular
+            ENABLE_FOAM : UseFoam
+            ENABLE_CAUSTICS : UseCaustics
+            ENABLE_REFRACTION : UseRefraction
+
+        }
+    }
+
+    Technique FixedFunc {
+    }
+}

+ 419 - 0
engine/src/core-effects/Common/MatDefs/Water/Water15.frag

@@ -0,0 +1,419 @@
+#import "Common/ShaderLib/MultiSample.glsllib"
+
+// Water pixel shader
+// Copyright (C) JMonkeyEngine 3.0
+// by Remy Bouquet (nehon) for JMonkeyEngine 3.0
+// original HLSL version by Wojciech Toman 2009
+
+uniform COLORTEXTURE m_Texture;
+uniform DEPTHTEXTURE m_DepthTexture;
+
+
+uniform sampler2D m_HeightMap;
+uniform sampler2D m_NormalMap;
+uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
+uniform sampler2D m_ReflectionMap;
+
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform mat4 m_TextureProjMatrix;
+uniform vec3 m_CameraPosition;
+
+uniform float m_WaterHeight;
+uniform float m_Time;
+uniform float m_WaterTransparency;
+uniform float m_NormalScale;
+uniform float m_R0;
+uniform float m_MaxAmplitude;
+uniform vec3 m_LightDir;
+uniform vec4 m_LightColor;
+uniform float m_ShoreHardness;
+uniform float m_FoamHardness;
+uniform float m_RefractionStrength;
+uniform vec3 m_FoamExistence;
+uniform vec3 m_ColorExtinction;
+uniform float m_Shininess;
+uniform vec4 m_WaterColor;
+uniform vec4 m_DeepWaterColor;
+uniform vec2 m_WindDirection;
+uniform float m_SunScale;
+uniform float m_WaveScale;
+uniform float m_UnderWaterFogDistance;
+uniform float m_CausticsIntensity;
+
+
+vec2 scale = vec2(m_WaveScale, m_WaveScale);
+float refractionScale = m_WaveScale;
+
+// Modifies 4 sampled normals. Increase first values to have more
+// smaller "waves" or last to have more bigger "waves"
+const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0);
+// Strength of displacement along normal.
+uniform float m_ReflectionDisplace;
+// Water transparency along eye vector.
+const float visibility = 3.0;
+// foam intensity
+uniform float m_FoamIntensity ;
+
+in vec2 texCoord;
+out vec4 outFragColor;
+
+mat3 MatrixInverse(in mat3 inMatrix){
+    float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);
+    mat3 T = transpose(inMatrix);
+    return mat3(cross(T[1], T[2]),
+        cross(T[2], T[0]),
+        cross(T[0], T[1])) / det;
+}
+
+
+mat3 computeTangentFrame(in vec3 N, in vec3 P, in vec2 UV) {
+    vec3 dp1 = dFdx(P);
+    vec3 dp2 = dFdy(P);
+    vec2 duv1 = dFdx(UV);
+    vec2 duv2 = dFdy(UV);
+
+    // solve the linear system
+    vec3 dp1xdp2 = cross(dp1, dp2);
+    mat2x3 inverseM = mat2x3(cross(dp2, dp1xdp2), cross(dp1xdp2, dp1));
+
+    vec3 T = inverseM * vec2(duv1.x, duv2.x);
+    vec3 B = inverseM * vec2(duv1.y, duv2.y);
+
+    // construct tangent frame
+    float maxLength = max(length(T), length(B));
+    T = T / maxLength;
+    B = B / maxLength;
+
+    return mat3(T, B, N);
+}
+
+float saturate(in float val){
+    return clamp(val,0.0,1.0);
+}
+
+vec3 saturate(in vec3 val){
+    return clamp(val,vec3(0.0),vec3(1.0));
+}
+
+vec3 getPosition(in float depth, in vec2 uv){
+    vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+    pos = m_ViewProjectionMatrixInverse * pos;
+    return pos.xyz / pos.w;
+}
+
+// Function calculating fresnel term.
+// - normal - normalized normal vector
+// - eyeVec - normalized eye vector
+float fresnelTerm(in vec3 normal,in vec3 eyeVec){
+    float angle = 1.0 - max(0.0, dot(normal, eyeVec));
+    float fresnel = angle * angle;
+    fresnel = fresnel * fresnel;
+    fresnel = fresnel * angle;
+    return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
+}
+
+vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance);
+const float LOG2 = 1.442695;
+
+vec4 underWater(int sampleNum){
+
+
+    float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
+    vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
+    
+    vec3 position = getPosition(sceneDepth, texCoord);
+    float level = m_WaterHeight;
+
+    vec3 eyeVec = position - m_CameraPosition;    
+ 
+    // Find intersection with water surface
+    vec3 eyeVecNorm = normalize(eyeVec);
+    float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+    vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+    vec2 texC = vec2(0.0);
+
+    float cameraDepth = length(m_CameraPosition - surfacePoint);  
+    texC = (surfacePoint.xz + eyeVecNorm.xz) * scale + m_Time * 0.03 * m_WindDirection;
+    float bias = texture(m_HeightMap, texC).r;
+    level += bias * m_MaxAmplitude;
+    t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+    surfacePoint = m_CameraPosition + eyeVecNorm * t; 
+    eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+    // Find normal of water surface
+    float normal1 = textureOffset(m_HeightMap, texC, ivec2(-1.0,  0.0)).r;
+    float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1.0,  0.0)).r;
+    float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0.0, -1.0)).r;
+    float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0.0,  1.0)).r;
+
+    vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+    vec3 normal = myNormal*-1.0;
+    float fresnel = fresnelTerm(normal, eyeVecNorm); 
+
+    vec3 refraction = color2;
+    #ifdef ENABLE_REFRACTION
+        texC = texCoord.xy *sin (fresnel+1.0);
+        #ifdef RESOLVE_MS
+            ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
+            refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
+        #else
+            ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
+            refraction = texelFetch(m_Texture, iTexC, 0).rgb;
+        #endif
+    #endif 
+
+   float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+   refraction = mix(mix(refraction, m_DeepWaterColor.rgb * waterCol, m_WaterTransparency),  m_WaterColor.rgb* waterCol,m_WaterTransparency);
+
+    vec3 foam = vec3(0.0);
+    #ifdef ENABLE_FOAM    
+        texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+        vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+        if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+            foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity  * m_FoamIntensity * 0.3 *
+               saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+        }
+        foam *= m_LightColor.rgb;    
+    #endif
+
+
+
+    vec3 specular = vec3(0.0);   
+    vec3 color ;
+    float fogFactor;
+
+    if(position.y>level){
+        #ifdef ENABLE_SPECULAR
+            if(step(0.9999,sceneDepth)==1.0){
+                vec3 lightDir=normalize(m_LightDir);
+                vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+                float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+                specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+                specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+                specular=specular * m_LightColor.rgb * 100.0;
+            }
+        #endif
+        float fogIntensity= 8.0 * m_WaterTransparency;
+        fogFactor = exp2( -fogIntensity * fogIntensity * cameraDepth * 0.03 * LOG2 );
+        fogFactor = clamp(fogFactor, 0.0, 1.0);        
+        color =mix(m_DeepWaterColor.rgb,refraction,fogFactor);   
+        specular=specular*fogFactor;    
+        color = saturate(color + max(specular, foam ));
+    }else{
+        vec3 caustics = vec3(0.0);
+        #ifdef ENABLE_CAUSTICS 
+            vec2 windDirection=m_WindDirection;
+            texC = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time  + position.x) * 0.01;
+            vec2 texCoord2 = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time  + position.z) * 0.01;
+            caustics += (texture2D(m_CausticsMap, texC)+ texture2D(m_CausticsMap, texCoord2)).rgb;                  
+            caustics=saturate(mix(m_WaterColor.rgb,caustics,m_CausticsIntensity));            
+            color=mix(color2,caustics,m_CausticsIntensity);
+        #else
+            color=color2;
+        #endif
+                
+        float fogDepth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - sceneDepth* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+        float fogIntensity= 18 * m_WaterTransparency;
+        fogFactor = exp2( -fogIntensity * fogIntensity * fogDepth *  fogDepth * LOG2 );
+        fogFactor = clamp(fogFactor, 0.0, 1.0);
+        color =mix(m_DeepWaterColor.rgb,color,fogFactor);
+    }
+
+    return vec4(color, 1.0);   
+}
+// NOTE: This will be called even for single-sampling
+vec4 main_multiSample(int sampleNum){
+    // If we are underwater let's call the underwater function
+    if(m_WaterHeight >= m_CameraPosition.y){
+
+        return underWater(sampleNum);
+    }
+
+    float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
+    vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
+
+    vec3 color = color2;
+    vec3 position = getPosition(sceneDepth, texCoord);
+
+    float level = m_WaterHeight;
+    
+    float isAtFarPlane = step(0.99998, sceneDepth);
+    //#ifndef ENABLE_RIPPLES
+    // This optimization won't work on NVIDIA cards if ripples are enabled
+    if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
+
+        return vec4(color2, 1.0);
+    }
+    //#endif
+
+    vec3 eyeVec = position - m_CameraPosition;    
+    float cameraDepth = m_CameraPosition.y - position.y;
+
+    // Find intersection with water surface
+    vec3 eyeVecNorm = normalize(eyeVec);
+    float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+    vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+    vec2 texC = vec2(0.0);
+    int samples = 1;
+    #ifdef ENABLE_HQ_SHORELINE
+        samples = 10;
+    #endif
+
+    float biasFactor = 1.0 / samples;
+    for (int i = 0; i < samples; i++){
+        texC = (surfacePoint.xz + eyeVecNorm.xz * biasFactor) * scale + m_Time * 0.03 * m_WindDirection;
+
+        float bias = texture(m_HeightMap, texC).r;
+
+        bias *= biasFactor;
+        level += bias * m_MaxAmplitude;
+        t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+        surfacePoint = m_CameraPosition + eyeVecNorm * t;
+    }
+
+    float depth = length(position - surfacePoint);
+    float depth2 = surfacePoint.y - position.y;
+
+    // XXX: HACK ALERT: Increase water depth to infinity if at far plane
+    // Prevents "foam on horizon" issue
+    // For best results, replace the "100.0" below with the
+    // highest value in the m_ColorExtinction vec3
+    depth  += isAtFarPlane * 100.0;
+    depth2 += isAtFarPlane * 100.0;
+
+    eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+    // Find normal of water surface
+    float normal1 = textureOffset(m_HeightMap, texC, ivec2(-1.0,  0.0)).r;
+    float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1.0,  0.0)).r;
+    float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0.0, -1.0)).r;
+    float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0.0,  1.0)).r;
+
+    vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+    vec3 normal = vec3(0.0);
+
+    #ifdef ENABLE_RIPPLES
+        texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
+        mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal0a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+        texC = surfacePoint.xz * 0.4 + m_WindDirection * m_Time* 0.8;
+        tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal1a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+        texC = surfacePoint.xz * 0.2 + m_WindDirection * m_Time * 0.4;
+        tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal2a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+        texC = surfacePoint.xz * 0.1 + m_WindDirection * m_Time * 0.2;
+        tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+        vec3 normal3a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
+
+        normal = normalize(normal0a * normalModifier.x + normal1a * normalModifier.y +normal2a * normalModifier.z + normal3a * normalModifier.w);
+        // XXX: Here's another way to fix the terrain edge issue,
+        // But it requires GLSL 1.3 and still looks kinda incorrect
+        // around edges
+        normal = isnan(normal.x) ? myNormal : normal;
+        //if (position.y > level){
+        //    gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
+        //    return;
+        //}
+    #else
+        normal = myNormal;
+    #endif
+
+    vec3 refraction = color2;
+    #ifdef ENABLE_REFRACTION
+       // texC = texCoord.xy+ m_ReflectionDisplace * normal.x;
+        texC = texCoord.xy;
+        texC += sin(m_Time*1.8  + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
+        #ifdef RESOLVE_MS
+            ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
+            refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
+        #else
+            ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
+            refraction = texelFetch(m_Texture, iTexC, 0).rgb;
+        #endif
+    #endif
+
+    vec3 waterPosition = surfacePoint.xyz;
+    waterPosition.y -= (level - m_WaterHeight);
+    vec4 texCoordProj = m_TextureProjMatrix * vec4(waterPosition, 1.0);
+
+    texCoordProj.x = texCoordProj.x + m_ReflectionDisplace * normal.x;
+    texCoordProj.z = texCoordProj.z + m_ReflectionDisplace * normal.z;
+    texCoordProj /= texCoordProj.w;
+    texCoordProj.y = 1.0 - texCoordProj.y;
+
+    vec3 reflection = texture(m_ReflectionMap, texCoordProj.xy).rgb;
+
+    float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+    float depthN = depth * m_WaterTransparency;
+    float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+    refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
+        m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
+
+
+
+
+    vec3 foam = vec3(0.0);
+    #ifdef ENABLE_FOAM
+        texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+        vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+        if(depth2 < m_FoamExistence.x){
+            foam = (texture2D(m_FoamMap, texC).r + texture2D(m_FoamMap, texCoord2)).rgb * vec3(m_FoamIntensity);
+        }else if(depth2 < m_FoamExistence.y){
+            foam = mix((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity , vec4(0.0),
+                (depth2 - m_FoamExistence.x) / (m_FoamExistence.y - m_FoamExistence.x)).rgb;
+        }
+
+        
+        if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+            foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity  * m_FoamIntensity * 0.3 *
+               saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+        }
+        foam *= m_LightColor.rgb;
+    #endif
+
+    vec3 specular = vec3(0.0);
+    #ifdef ENABLE_SPECULAR
+        vec3 lightDir=normalize(m_LightDir);
+        vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+        float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+        specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+        specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+        //foam does not shine
+        specular=specular * m_LightColor.rgb - (5.0 * foam);
+    #endif
+
+    color = mix(refraction, reflection, fresnel);
+    color = mix(refraction, color, saturate(depth * m_ShoreHardness));
+    color = saturate(color + max(specular, foam ));
+    color = mix(refraction, color, saturate(depth* m_FoamHardness));
+
+
+    // XXX: HACK ALERT:
+    // We trick the GeForces to think they have
+    // to calculate the derivatives for all these pixels by using step()!
+    // That way we won't get pixels around the edges of the terrain,
+    // Where the derivatives are undefined
+    return vec4(mix(color, color2, step(level, position.y)), 1.0);
+}
+
+void main(){
+    #ifdef RESOLVE_MS
+        vec4 color = vec4(0.0);
+        for (int i = 0; i < m_NumSamples; i++){
+            color += main_multiSample(i);
+        }
+        outFragColor = color / m_NumSamples;
+    #else
+        outFragColor = main_multiSample(0);
+    #endif
+}

+ 126 - 0
engine/src/core-effects/Common/MatDefs/Water/simple_water.frag

@@ -0,0 +1,126 @@
+/*
+GLSL conversion of Michael Horsch water demo
+http://www.bonzaisoftware.com/wfs.html
+Converted by Mars_999
+8/20/2005
+*/
+
+uniform sampler2D m_water_normalmap;
+uniform sampler2D m_water_reflection;
+uniform sampler2D m_water_refraction;
+uniform sampler2D m_water_dudvmap;
+uniform sampler2D m_water_depthmap;
+uniform vec4 m_waterColor;
+uniform float m_waterDepth;
+uniform vec4 m_distortionScale;
+uniform vec4 m_distortionMix;
+uniform vec4 m_texScale;
+uniform vec2 m_FrustumNearFar;
+uniform float m_waterTransparency;
+
+
+
+varying vec4 lightDir; //lightpos
+varying vec4 waterTex1; //moving texcoords
+varying vec4 waterTex2; //moving texcoords
+varying vec4 position; //for projection
+varying vec4 viewDir; //viewts
+varying vec4 viewLightDir;
+varying vec4 viewCamDir;
+
+//unit 0 = m_water_reflection
+//unit 1 = m_water_refraction
+//unit 2 = m_water_normalmap
+//unit 3 = m_water_dudvmap
+//unit 4 = m_water_depthmap
+
+ const vec4 two = vec4(2.0, 2.0, 2.0, 1.0);
+ const vec4 mone = vec4(-1.0, -1.0, -1.0, 1.0);
+
+ const vec4 ofive = vec4(0.5,0.5,0.5,1.0);
+
+ const float exponent = 64.0;
+
+float tangDot(in vec3 v1, in vec3 v2){
+    float d = dot(v1,v2);
+    #ifdef V_TANGENT
+        d = 1.0 - d*d;
+        return step(0.0, d) * sqrt(d);
+    #else
+        return d;
+    #endif
+}
+
+vec4 readDepth(vec2 uv){
+    float depth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - texture2D(m_water_depthmap, uv).r* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+    return vec4( depth);
+}
+
+void main(void)
+{
+ 
+
+     vec4 lightTS = normalize(lightDir);
+     vec4 viewt = normalize(viewDir);
+     vec4 disdis = texture2D(m_water_dudvmap, vec2(waterTex2 * m_texScale));
+     vec4 fdist = texture2D(m_water_dudvmap, vec2(waterTex1 + disdis*m_distortionMix));
+     fdist =normalize( fdist * 2.0 - 1.0)* m_distortionScale;
+  
+
+     //load normalmap
+     vec4 nmap = texture2D(m_water_normalmap, vec2(waterTex1 + disdis*m_distortionMix));
+     nmap = (nmap-ofive) * two;
+    // nmap = nmap*2.0-1.0;
+     vec4 vNorm = normalize(nmap);
+
+     
+     vec4 projCoord = position / position.w;
+     projCoord =(projCoord+1.0)*0.5 + fdist;
+     projCoord = clamp(projCoord, 0.001, 0.999);
+
+     //load reflection,refraction and depth texture
+     vec4 refl = texture2D(m_water_reflection, vec2(projCoord.x,1.0-projCoord.y));
+     vec4 refr = texture2D(m_water_refraction, vec2(projCoord));
+     vec4 wdepth =readDepth(vec2(projCoord));
+  
+     wdepth = vec4(pow(wdepth.x, m_waterDepth));
+     vec4 invdepth = 1.0 - wdepth;
+
+
+ // Blinn - Phong
+  //    vec4 H = (viewt - lightTS);
+  //   vec4 specular =vec4(pow(max(dot(H, vNorm), 0.0), exponent));
+
+// Standard Phong
+
+  //   vec4 R =reflect(-L, vNorm);
+ //    vec4 specular =vec4( pow(max(dot(R, E), 0.0),exponent));
+
+ 
+     //calculate specular highlight
+     vec4 L=normalize(viewLightDir);  
+    vec4 E=normalize(viewCamDir);
+     vec4 vRef = normalize(reflect(-L,vNorm));
+     float stemp =max(0.0, dot( vRef,E) );
+     //initializing to 0 to avoid artifacts on old intel cards
+     vec4 specular = vec4(0.0,0.0,0.0,0.0);
+    if(stemp>0.0){
+         stemp = pow(stemp, exponent);
+         specular = vec4(stemp);
+    }
+
+
+
+    vec4 fresnelTerm = vec4(0.02+0.97*pow((1.0-dot(normalize(viewt), vNorm)),5.0));
+
+
+
+    fresnelTerm=fresnelTerm*invdepth*m_waterTransparency;
+    fresnelTerm=clamp(fresnelTerm,0.0,1.0);
+
+    refr*=(fresnelTerm);
+    refr *= invdepth;
+    refr= refr+ m_waterColor*wdepth*fresnelTerm;
+
+    gl_FragColor =(refr+ refl*(1.0-fresnelTerm))+specular;
+}

+ 87 - 0
engine/src/core-effects/Common/MatDefs/Water/simple_water.vert

@@ -0,0 +1,87 @@
+/*
+GLSL conversion of Michael Horsch water demo
+http://www.bonzaisoftware.com/wfs.html
+Converted by Mars_999
+8/20/2005
+*/
+uniform vec3 m_lightPos;
+uniform float m_time;
+
+uniform mat4 g_WorldViewProjectionMatrix;
+uniform mat4 g_WorldViewMatrix;
+uniform mat4 g_ViewMatrix;
+uniform vec3 g_CameraPosition;
+uniform mat3 g_NormalMatrix;
+
+attribute vec4 inPosition;
+attribute vec2 inTexCoord;
+attribute vec3 inTangent;
+attribute vec3 inNormal;
+
+varying vec4 lightDir;
+varying vec4 waterTex1;
+varying vec4 waterTex2;
+varying vec4 position;
+varying vec4 viewDir;
+varying vec4 viewpos;
+varying vec4 viewLightDir;
+varying vec4 viewCamDir;
+
+
+//unit 0 = water_reflection
+//unit 1 = water_refraction
+//unit 2 = water_normalmap
+//unit 3 = water_dudvmap
+//unit 4 = water_depthmap
+
+void main(void)
+{
+    viewpos.x = g_CameraPosition.x;
+    viewpos.y = g_CameraPosition.y;
+    viewpos.z = g_CameraPosition.z;
+    viewpos.w = 1.0;
+
+    vec4  temp;
+    vec4 tangent = vec4(1.0, 0.0, 0.0, 0.0);
+    vec4 norm = vec4(0.0, 1.0, 0.0, 0.0);
+    vec4 binormal = vec4(0.0, 0.0, 1.0, 0.0);
+
+
+    temp = viewpos - inPosition;
+
+    viewDir.x = dot(temp, tangent);
+    viewDir.y = dot(temp, binormal);
+    viewDir.z = dot(temp, norm);
+    viewDir.w = 0.0;
+
+    temp = vec4(m_lightPos,1.0)- inPosition;
+    lightDir.x = dot(temp, tangent);
+    lightDir.y = dot(temp, binormal);
+    lightDir.z = dot(temp, norm);
+    lightDir.w = 0.0;
+
+   vec4 viewSpaceLightPos=g_ViewMatrix*vec4(m_lightPos,1.0);
+   vec4 viewSpacePos=g_WorldViewMatrix*inPosition;
+   vec3 wvNormal  = normalize(g_NormalMatrix * inNormal);
+   vec3 wvTangent = normalize(g_NormalMatrix * inTangent);
+   vec3 wvBinormal = cross(wvNormal, wvTangent);
+   mat3 tbnMat = mat3(wvTangent, wvBinormal, wvNormal);
+
+    temp = viewSpaceLightPos - viewSpacePos;
+    viewLightDir.xyz=temp.xyz*tbnMat;
+    viewLightDir.w = 0.0;
+
+    temp = -viewSpacePos;
+    viewCamDir.xyz =temp.xyz*tbnMat;
+    viewCamDir.w = 0.0;
+
+
+    vec4 t1 = vec4(0.0, -m_time, 0.0,0.0);
+    vec4 t2 = vec4(0.0, m_time, 0.0,0.0);
+
+    waterTex1 =vec4(inTexCoord,0.0,0.0) + t1;
+    waterTex2 =vec4(inTexCoord ,0.0,0.0)+ t2;
+
+    position = g_WorldViewProjectionMatrix * inPosition;
+    gl_Position = position;
+}

+ 309 - 0
engine/src/core-effects/com/jme3/post/filters/BloomFilter.java

@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.texture.Image.Format;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * BloomFilter is used to make objects in the scene have a glow effect.<br>
+ * There are 2 mode : Scene and Objects.<br>
+ * Scene mode extracts the bright parts of the scene to make them glow<br>
+ * Object mode make objects glow according to their material's glowMap or their GlowColor<br>
+ * @see <a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bloom_and_glow">advanced:bloom_and_glow</a> for more details
+ * 
+ * @author Rémy Bouquet aka Nehon
+ */
+public class BloomFilter extends Filter {
+
+    /**
+     * GlowMode specifies if the glow will be applied to the whole scene,or to objects that have aglow color or a glow map
+     */
+    public enum GlowMode {
+
+        /**
+         * Apply bloom filter to bright areas in the scene.
+         */
+        Scene,
+        /**
+         * Apply bloom only to objects that have a glow map or a glow color.
+         */
+        Objects,
+        /**
+         * Apply bloom to both bright parts of the scene and objects with glow map.
+         */
+        SceneAndObjects;
+    }
+
+    private GlowMode glowMode = GlowMode.Scene;
+    //Bloom parameters
+    private float blurScale = 1.5f;
+    private float exposurePower = 5.0f;
+    private float exposureCutOff = 0.0f;
+    private float bloomIntensity = 2.0f;
+    private float downSamplingFactor = 1;
+    private Pass preGlowPass;
+    private Pass extractPass;
+    private Pass horizontalBlur = new Pass();
+    private Pass verticalalBlur = new Pass();
+    private Material extractMat;
+    private Material vBlurMat;
+    private Material hBlurMat;
+    private int screenWidth;
+    private int screenHeight;    
+
+    /**
+     * Creates a Bloom filter
+     */
+    public BloomFilter() {
+        super("BloomFilter");
+    }
+
+    /**
+     * Creates the bloom filter with the specific glow mode
+     * @param glowMode
+     */
+    public BloomFilter(GlowMode glowMode) {
+        this();
+        this.glowMode = glowMode;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        screenWidth = (int) Math.max(1, (w / downSamplingFactor));
+        screenHeight = (int) Math.max(1, (h / downSamplingFactor));
+        //    System.out.println(screenWidth + " " + screenHeight);
+        if (glowMode != GlowMode.Scene) {
+            preGlowPass = new Pass();
+            preGlowPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth);
+        }
+
+        postRenderPasses = new ArrayList<Pass>();
+        //configuring extractPass
+        extractMat = new Material(manager, "Common/MatDefs/Post/BloomExtract.j3md");
+        extractPass = new Pass() {
+
+            @Override
+            public boolean requiresSceneAsTexture() {
+                return true;
+            }
+
+            @Override
+            public void beforeRender() {
+                extractMat.setFloat("ExposurePow", exposurePower);
+                extractMat.setFloat("ExposureCutoff", exposureCutOff);
+                if (glowMode != GlowMode.Scene) {
+                    extractMat.setTexture("GlowMap", preGlowPass.getRenderedTexture());
+                }
+                extractMat.setBoolean("Extract", glowMode != GlowMode.Objects);
+            }
+        };
+
+        extractPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, extractMat);
+        postRenderPasses.add(extractPass);
+
+        //configuring horizontal blur pass
+        hBlurMat = new Material(manager, "Common/MatDefs/Blur/HGaussianBlur.j3md");
+        horizontalBlur = new Pass() {
+
+            @Override
+            public void beforeRender() {
+                hBlurMat.setTexture("Texture", extractPass.getRenderedTexture());
+                hBlurMat.setFloat("Size", screenWidth);
+                hBlurMat.setFloat("Scale", blurScale);
+            }
+        };
+
+        horizontalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, hBlurMat);
+        postRenderPasses.add(horizontalBlur);
+
+        //configuring vertical blur pass
+        vBlurMat = new Material(manager, "Common/MatDefs/Blur/VGaussianBlur.j3md");
+        verticalalBlur = new Pass() {
+
+            @Override
+            public void beforeRender() {
+                vBlurMat.setTexture("Texture", horizontalBlur.getRenderedTexture());
+                vBlurMat.setFloat("Size", screenHeight);
+                vBlurMat.setFloat("Scale", blurScale);
+            }
+        };
+
+        verticalalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, vBlurMat);
+        postRenderPasses.add(verticalalBlur);
+
+
+        //final material
+        material = new Material(manager, "Common/MatDefs/Post/BloomFinal.j3md");
+        material.setTexture("BloomTex", verticalalBlur.getRenderedTexture());
+    }
+
+
+    @Override
+    protected Material getMaterial() {
+        material.setFloat("BloomIntensity", bloomIntensity);
+        return material;
+    }
+
+    @Override
+    protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+        if (glowMode != GlowMode.Scene) {           
+            renderManager.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha);            
+            renderManager.getRenderer().setFrameBuffer(preGlowPass.getRenderFrameBuffer());
+            renderManager.getRenderer().clearBuffers(true, true, true);
+            renderManager.setForcedTechnique("Glow");
+            renderManager.renderViewPortQueues(viewPort, false);         
+            renderManager.setForcedTechnique(null);
+            renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+        }
+    }
+
+    /**
+     * returns the bloom intensity
+     * @return 
+     */
+    public float getBloomIntensity() {
+        return bloomIntensity;
+    }
+
+    /**
+     * intensity of the bloom effect default is 2.0
+     * @param bloomIntensity
+     */
+    public void setBloomIntensity(float bloomIntensity) {
+        this.bloomIntensity = bloomIntensity;
+    }
+
+    /**
+     * returns the blur scale
+     * @return 
+     */
+    public float getBlurScale() {
+        return blurScale;
+    }
+
+    /**
+     * sets The spread of the bloom default is 1.5f
+     * @param blurScale
+     */
+    public void setBlurScale(float blurScale) {
+        this.blurScale = blurScale;
+    }
+
+    /**
+     * returns the exposure cutoff<br>
+     * for more details see {@link setExposureCutOff(float exposureCutOff)}
+     * @return 
+     */    
+    public float getExposureCutOff() {
+        return exposureCutOff;
+    }
+
+    /**
+     * Define the color threshold on which the bloom will be applied (0.0 to 1.0)
+     * @param exposureCutOff
+     */
+    public void setExposureCutOff(float exposureCutOff) {
+        this.exposureCutOff = exposureCutOff;
+    }
+
+    /**
+     * returns the exposure power<br>
+     * form more details see {@link setExposurePower(float exposurePower)}
+     * @return 
+     */
+    public float getExposurePower() {
+        return exposurePower;
+    }
+
+    /**
+     * defines how many time the bloom extracted color will be multiplied by itself. default id 5.0<br>
+     * a high value will reduce rough edges in the bloom and somhow the range of the bloom area     * 
+     * @param exposurePower
+     */
+    public void setExposurePower(float exposurePower) {
+        this.exposurePower = exposurePower;
+    }
+
+    /**
+     * returns the downSampling factor<br>
+     * form more details see {@link setDownSamplingFactor(float downSamplingFactor)}
+     * @return
+     */
+    public float getDownSamplingFactor() {
+        return downSamplingFactor;
+    }
+
+    /**
+     * Sets the downSampling factor : the size of the computed texture will be divided by this factor. default is 1 for no downsampling
+     * A 2 value is a good way of widening the blur
+     * @param downSamplingFactor
+     */
+    public void setDownSamplingFactor(float downSamplingFactor) {
+        this.downSamplingFactor = downSamplingFactor;
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(glowMode, "glowMode", GlowMode.Scene);
+        oc.write(blurScale, "blurScale", 1.5f);
+        oc.write(exposurePower, "exposurePower", 5.0f);
+        oc.write(exposureCutOff, "exposureCutOff", 0.0f);
+        oc.write(bloomIntensity, "bloomIntensity", 2.0f);
+        oc.write(downSamplingFactor, "downSamplingFactor", 1);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        glowMode = ic.readEnum("glowMode", GlowMode.class, GlowMode.Scene);
+        blurScale = ic.readFloat("blurScale", 1.5f);
+        exposurePower = ic.readFloat("exposurePower", 5.0f);
+        exposureCutOff = ic.readFloat("exposureCutOff", 0.0f);
+        bloomIntensity = ic.readFloat("bloomIntensity", 2.0f);
+        downSamplingFactor = ic.readFloat("downSamplingFactor", 1);
+    }
+}

+ 245 - 0
engine/src/core-effects/com/jme3/post/filters/CartoonEdgeFilter.java

@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.texture.Image.Format;
+
+/**
+ * Applies a cartoon-style edge detection filter to all objects in the scene.
+ *
+ * @author Kirill Vainer
+ */
+public class CartoonEdgeFilter extends Filter {
+
+    private Pass normalPass;
+    private float edgeWidth = 1.0f;
+    private float edgeIntensity = 1.0f;
+    private float normalThreshold = 0.5f;
+    private float depthThreshold = 0.1f;
+    private float normalSensitivity = 1.0f;
+    private float depthSensitivity = 10.0f;
+    private ColorRGBA edgeColor = new ColorRGBA(0, 0, 0, 1);
+
+    /**
+     * Creates a CartoonEdgeFilter
+     */
+    public CartoonEdgeFilter() {
+        super("CartoonEdgeFilter");
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return true;
+    }
+
+    @Override
+    protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+        Renderer r = renderManager.getRenderer();
+        r.setFrameBuffer(normalPass.getRenderFrameBuffer());
+        renderManager.getRenderer().clearBuffers(true, true, true);
+        renderManager.setForcedTechnique("PreNormalPass");
+        renderManager.renderViewPortQueues(viewPort, false);
+        renderManager.setForcedTechnique(null);
+        renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+    }
+
+    @Override
+    protected Material getMaterial() {
+        material.setTexture("NormalsTexture", normalPass.getRenderedTexture());
+        return material;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        normalPass = new Pass();
+        normalPass.init(renderManager.getRenderer(), w, h, Format.RGBA8, Format.Depth);
+        material = new Material(manager, "Common/MatDefs/Post/CartoonEdge.j3md");
+        material.setFloat("EdgeWidth", edgeWidth);
+        material.setFloat("EdgeIntensity", edgeIntensity);
+        material.setFloat("NormalThreshold", normalThreshold);
+        material.setFloat("DepthThreshold", depthThreshold);
+        material.setFloat("NormalSensitivity", normalSensitivity);
+        material.setFloat("DepthSensitivity", depthSensitivity);
+        material.setColor("EdgeColor", edgeColor);
+    }
+
+    /**
+     * Return the depth sensitivity<br>
+     * for more details see {@link setDepthSensitivity(float depthSensitivity)}
+     * @return 
+     */
+    public float getDepthSensitivity() {
+        return depthSensitivity;
+    }
+
+    /**
+     * sets the depth sensitivity<br>
+     * defines how much depth will influence edges, default is 10
+     * @param depthSensitivity 
+     */
+    public void setDepthSensitivity(float depthSensitivity) {
+        this.depthSensitivity = depthSensitivity;
+        if (material != null) {
+            material.setFloat("DepthSensitivity", depthSensitivity);
+        }
+    }
+
+    /**
+     * returns the depth threshold<br>
+     * for more details see {@link setDepthThreshold(float depthThreshold)}
+     * @return 
+     */
+    public float getDepthThreshold() {
+        return depthThreshold;
+    }
+
+    /**
+     * sets the depth threshold<br>
+     * Defines at what threshold of difference of depth an edge is outlined default is 0.1f
+     * @param depthThreshold 
+     */
+    public void setDepthThreshold(float depthThreshold) {
+        this.depthThreshold = depthThreshold;
+        if (material != null) {
+            material.setFloat("DepthThreshold", depthThreshold);
+        }
+    }
+
+    /**
+     * returns the edge intensity<br>
+     * for more details see {@link setEdgeIntensity(float edgeIntensity) }
+     * @return 
+     */
+    public float getEdgeIntensity() {
+        return edgeIntensity;
+    }
+
+    /**
+     * sets the edge intensity<br>
+     * Defineshow visilble will be the outlined edges
+     * @param edgeIntensity 
+     */
+    public void setEdgeIntensity(float edgeIntensity) {
+        this.edgeIntensity = edgeIntensity;
+        if (material != null) {
+            material.setFloat("EdgeIntensity", edgeIntensity);
+        }
+    }
+
+    /**
+     * returns the width of the edges
+     * @return 
+     */
+    public float getEdgeWidth() {
+        return edgeWidth;
+    }
+
+    /**
+     * sets the witdh of the edge in pixels default is 1
+     * @param edgeWidth 
+     */
+    public void setEdgeWidth(float edgeWidth) {
+        this.edgeWidth = edgeWidth;
+        if (material != null) {
+            material.setFloat("EdgeWidth", edgeWidth);
+        }
+
+    }
+
+    /**
+     * returns the normals sensitivity<br>
+     * form more details see {@link setNormalSensitivity(float normalSensitivity)}
+     * @return 
+     */
+    public float getNormalSensitivity() {
+        return normalSensitivity;
+    }
+
+    /**
+     * sets the normals sensitivity default is 1
+     * @param normalSensitivity 
+     */
+    public void setNormalSensitivity(float normalSensitivity) {
+        this.normalSensitivity = normalSensitivity;
+        if (material != null) {
+            material.setFloat("NormalSensitivity", normalSensitivity);
+        }
+    }
+
+    /**
+     * returns the normal threshold<br>
+     * for more details see {@link setNormalThreshold(float normalThreshold)}
+     * 
+     * @return 
+     */
+    public float getNormalThreshold() {
+        return normalThreshold;
+    }
+
+    /**
+     * sets the normal threshold default is 0.5
+     * @param normalThreshold 
+     */
+    public void setNormalThreshold(float normalThreshold) {
+        this.normalThreshold = normalThreshold;
+        if (material != null) {
+            material.setFloat("NormalThreshold", normalThreshold);
+        }
+    }
+
+    /**
+     * returns the edge color
+     * @return
+     */
+    public ColorRGBA getEdgeColor() {
+        return edgeColor;
+    }
+
+    /**
+     * Sets the edge color, default is black
+     * @param edgeColor
+     */
+    public void setEdgeColor(ColorRGBA edgeColor) {
+        this.edgeColor = edgeColor;
+        if (material != null) {
+            material.setColor("EdgeColor", edgeColor);
+        }
+    }
+}

+ 111 - 0
engine/src/core-effects/com/jme3/post/filters/ColorOverlayFilter.java

@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/** 
+ * This filter simply multiply the whole scene by a color
+ * @author Rémy Bouquet aka Nehon
+ */
+public class ColorOverlayFilter extends Filter {
+
+    private ColorRGBA color = ColorRGBA.White;
+
+    /**
+     * creates a colorOverlayFilter with a white coor (transparent)
+     */
+    public ColorOverlayFilter() {
+        super("Color Overlay");
+    }
+
+    /**
+     * creates a colorOverlayFilter with the given color
+     * @param color 
+     */
+    public ColorOverlayFilter(ColorRGBA color) {
+        this();
+        this.color = color;
+    }
+
+    @Override
+    protected Material getMaterial() {
+
+        material.setColor("Color", color);
+        return material;
+    }
+
+    /**
+     * returns the color
+     * @return color
+     */
+    public ColorRGBA getColor() {
+        return color;
+    }
+
+    /**
+     * sets the color 
+     * @param color 
+     */
+    public void setColor(ColorRGBA color) {
+        this.color = color;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(color, "color", ColorRGBA.White);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        color = (ColorRGBA) ic.readSavable("color", ColorRGBA.White);
+    }
+}

+ 305 - 0
engine/src/core-effects/com/jme3/post/filters/CrossHatchFilter.java

@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A Post Processing filter that makes the screen look like it was drawn as
+ * diagonal lines with a pen.
+ * Try combining this with a cartoon edge filter to obtain manga style visuals.
+ *
+ * Based on an article from Geeks3D:
+ *    <a href="http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/" rel="nofollow">http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/</a>
+ *
+ * @author Roy Straver a.k.a. Baal Garnaal
+ */
+public class CrossHatchFilter extends Filter {
+
+    private ColorRGBA lineColor = ColorRGBA.Black.clone();
+    private ColorRGBA paperColor = ColorRGBA.White.clone();
+    private float colorInfluenceLine = 0.8f;
+    private float colorInfluencePaper = 0.1f;
+    private float fillValue = 0.9f;
+    private float luminance1 = 0.9f;
+    private float luminance2 = 0.7f;
+    private float luminance3 = 0.5f;
+    private float luminance4 = 0.3f;
+    private float luminance5 = 0.0f;
+    private float lineThickness = 1.0f;
+    private float lineDistance = 4.0f;
+
+    /**
+     * Creates a crossHatch filter
+     */
+    public CrossHatchFilter() {
+        super("CrossHatchFilter");
+    }
+
+    /**
+     * Creates a crossHatch filter
+     * @param lineColor the colors of the lines
+     * @param paperColor the paper color
+     */
+    public CrossHatchFilter(ColorRGBA lineColor, ColorRGBA paperColor) {
+        this();
+        this.lineColor = lineColor;
+        this.paperColor = paperColor;
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return false;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/CrossHatch.j3md");
+        material.setColor("LineColor", lineColor);
+        material.setColor("PaperColor", paperColor);
+
+        material.setFloat("ColorInfluenceLine", colorInfluenceLine);
+        material.setFloat("ColorInfluencePaper", colorInfluencePaper);
+
+        material.setFloat("FillValue", fillValue);
+
+        material.setFloat("Luminance1", luminance1);
+        material.setFloat("Luminance2", luminance2);
+        material.setFloat("Luminance3", luminance3);
+        material.setFloat("Luminance4", luminance4);
+        material.setFloat("Luminance5", luminance5);
+
+        material.setFloat("LineThickness", lineThickness);
+        material.setFloat("LineDistance", lineDistance);
+    }
+
+    @Override
+    protected Material getMaterial() {
+        return material;
+    }
+
+    /**
+     * Sets color used to draw lines
+     * @param lineColor 
+     */
+    public void setLineColor(ColorRGBA lineColor) {
+        this.lineColor = lineColor;
+        if (material != null) {
+            material.setColor("LineColor", lineColor);
+        }
+    }
+
+    /**
+     * Sets color used as background
+     * @param paperColor 
+     */
+    public void setPaperColor(ColorRGBA paperColor) {
+        this.paperColor = paperColor;
+        if (material != null) {
+            material.setColor("PaperColor", paperColor);
+        }
+    }
+
+    /**
+     * Sets color influence of original image on lines drawn
+     * @param colorInfluenceLine 
+     */
+    public void setColorInfluenceLine(float colorInfluenceLine) {
+        this.colorInfluenceLine = colorInfluenceLine;
+        if (material != null) {
+            material.setFloat("ColorInfluenceLine", colorInfluenceLine);
+        }
+    }
+
+    /**
+     * Sets color influence of original image on non-line areas
+     * @param colorInfluencePaper 
+     */
+    public void setColorInfluencePaper(float colorInfluencePaper) {
+        this.colorInfluencePaper = colorInfluencePaper;
+        if (material != null) {
+            material.setFloat("ColorInfluencePaper", colorInfluencePaper);
+        }
+    }
+
+    /**
+     * Sets line/paper color ratio for areas with values < luminance5,
+     * really dark areas get no lines but a filled blob instead
+     * @param fillValue 
+     */
+    public void setFillValue(float fillValue) {
+        this.fillValue = fillValue;
+        if (material != null) {
+            material.setFloat("FillValue", fillValue);
+        }
+    }
+
+    /**
+     *
+     * Sets minimum luminance levels for lines drawn
+     * @param luminance1 Top-left to down right 1
+     * @param luminance2 Top-right to bottom left 1
+     * @param luminance3 Top-left to down right 2
+     * @param luminance4 Top-right to bottom left 2
+     * @param luminance5 Blobs
+     */
+    public void setLuminanceLevels(float luminance1, float luminance2, float luminance3, float luminance4, float luminance5) {
+        this.luminance1 = luminance1;
+        this.luminance2 = luminance2;
+        this.luminance3 = luminance3;
+        this.luminance4 = luminance4;
+        this.luminance5 = luminance5;
+
+        if (material != null) {
+            material.setFloat("Luminance1", luminance1);
+            material.setFloat("Luminance2", luminance2);
+            material.setFloat("Luminance3", luminance3);
+            material.setFloat("Luminance4", luminance4);
+            material.setFloat("Luminance5", luminance5);
+        }
+    }
+
+    /**
+     * Sets the thickness of lines drawn
+     * @param lineThickness 
+     */
+    public void setLineThickness(float lineThickness) {
+        this.lineThickness = lineThickness;
+        if (material != null) {
+            material.setFloat("LineThickness", lineThickness);
+        }
+    }
+
+    /**
+     * Sets minimum distance between lines drawn
+     * Primary lines are drawn at 2*lineDistance
+     * Secondary lines are drawn at lineDistance
+     * @param lineDistance 
+     */
+    public void setLineDistance(float lineDistance) {
+        this.lineDistance = lineDistance;
+        if (material != null) {
+            material.setFloat("LineDistance", lineDistance);
+        }
+    }
+
+    /**
+     * Returns line color
+     * @return 
+     */
+    public ColorRGBA getLineColor() {
+        return lineColor;
+    }
+
+    /**
+     * Returns paper background color
+     * @return 
+     */
+    public ColorRGBA getPaperColor() {
+        return paperColor;
+    }
+
+    /**
+     * Returns current influence of image colors on lines
+     */
+    public float getColorInfluenceLine() {
+        return colorInfluenceLine;
+    }
+
+    /**
+     * Returns current influence of image colors on paper background
+     */
+    public float getColorInfluencePaper() {
+        return colorInfluencePaper;
+    }
+
+    /**
+     * Returns line/paper color ratio for blobs
+     */
+    public float getFillValue() {
+        return fillValue;
+    }
+
+    /**
+     * Returns the thickness of the lines drawn
+     */
+    public float getLineThickness() {
+        return lineThickness;
+    }
+
+    /**
+     * Returns minimum distance between lines
+     */
+    public float getLineDistance() {
+        return lineDistance;
+    }
+
+    /**
+     * Returns treshold for lines 1
+     */
+    public float getLuminance1() {
+        return luminance1;
+    }
+
+    /**
+     * Returns treshold for lines 2
+     */
+    public float getLuminance2() {
+        return luminance2;
+    }
+
+    /**
+     * Returns treshold for lines 3
+     */
+    public float getLuminance3() {
+        return luminance3;
+    }
+
+    /**
+     * Returns treshold for lines 4
+     */
+    public float getLuminance4() {
+        return luminance4;
+    }
+
+    /**
+     * Returns treshold for blobs
+     */
+    public float getLuminance5() {
+        return luminance5;
+    }
+}

+ 158 - 0
engine/src/core-effects/com/jme3/post/filters/DepthOfFieldFilter.java

@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ *  A post-processing filter that performs a depth range
+ *  blur using a scaled convolution filter.
+ *
+ *  @version   $Revision: 779 $
+ *  @author    Paul Speed
+ */
+public class DepthOfFieldFilter extends Filter {
+
+    private float focusDistance = 50f;
+    private float focusRange = 10f;
+    private float blurScale = 1f;
+    // These values are set internally based on the
+    // viewport size.
+    private float xScale;
+    private float yScale;
+
+    /**
+     * Creates a DepthOfField filter
+     */
+    public DepthOfFieldFilter() {
+        super("Depth Of Field");
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return true;
+    }
+
+    @Override
+    protected Material getMaterial() {
+
+        return material;
+    }
+
+    @Override
+    protected void initFilter(AssetManager assets, RenderManager renderManager,
+            ViewPort vp, int w, int h) {
+        material = new Material(assets, "Common/MatDefs/Post/DepthOfField.j3md");
+        material.setFloat("FocusDistance", focusDistance);
+        material.setFloat("FocusRange", focusRange);
+
+
+        xScale = 1.0f / w;
+        yScale = 1.0f / h;
+
+        material.setFloat("XScale", blurScale * xScale);
+        material.setFloat("YScale", blurScale * yScale);
+    }
+
+    /**
+     *  Sets the distance at which objects are purely in focus.
+     */
+    public void setFocusDistance(float f) {
+
+        this.focusDistance = f;
+        if (material != null) {
+            material.setFloat("FocusDistance", focusDistance);
+        }
+
+    }
+
+    /**
+     * returns the focus distance
+     * @return 
+     */
+    public float getFocusDistance() {
+        return focusDistance;
+    }
+
+    /**
+     *  Sets the range to either side of focusDistance where the
+     *  objects go gradually out of focus.  Less than focusDistance - focusRange
+     *  and greater than focusDistance + focusRange, objects are maximally "blurred".
+     */
+    public void setFocusRange(float f) {
+        this.focusRange = f;
+        if (material != null) {
+            material.setFloat("FocusRange", focusRange);
+        }
+
+    }
+
+    /**
+     * returns the focus range
+     * @return 
+     */
+    public float getFocusRange() {
+        return focusRange;
+    }
+
+    /**
+     *  Sets the blur amount by scaling the convolution filter up or
+     *  down.  A value of 1 (the default) performs a sparse 5x5 evenly
+     *  distribubted convolution at pixel level accuracy.  Higher values skip
+     *  more pixels, and so on until you are no longer blurring the image
+     *  but simply hashing it.
+     *
+     *  The sparse convolution is as follows:
+     *%MINIFYHTMLc3d0cd9fab65de6875a381fd3f83e1b338%*
+     *  Where 'x' is the texel being modified.  Setting blur scale higher
+     *  than 1 spaces the samples out.
+     */
+    public void setBlurScale(float f) {
+        this.blurScale = f;
+        if (material != null) {
+            material.setFloat("XScale", blurScale * xScale);
+            material.setFloat("YScale", blurScale * yScale);
+        }
+    }
+
+    /**
+     * returns the blur scale
+     * @return 
+     */
+    public float getBlurScale() {
+        return blurScale;
+    }
+}

+ 95 - 0
engine/src/core-effects/com/jme3/post/filters/FXAAFilter.java

@@ -0,0 +1,95 @@
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * <a href="http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce/3/" rel="nofollow">http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-<span class="domtooltips" title="OpenGL (Open Graphics Library) is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics." id="domtooltipsspan11">opengl</span>-test-radeon-geforce/3/</a>
+ * <a href="http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf" rel="nofollow">http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf</a>
+ *
+ * @author Phate666 (adapted to jme3)
+ *
+ */
+public class FXAAFilter extends Filter {
+
+    private float subPixelShift = 1.0f / 4.0f;
+    private float vxOffset = 0.0f;
+    private float spanMax = 8.0f;
+    private float reduceMul = 1.0f / 8.0f;
+
+    public FXAAFilter() {
+        super("FXAAFilter");
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager,
+            RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/FXAA.j3md");   
+        material.setFloat("SubPixelShift", subPixelShift);
+        material.setFloat("VxOffset", vxOffset);
+        material.setFloat("SpanMax", spanMax);
+        material.setFloat("ReduceMul", reduceMul);
+    }
+
+    @Override
+    protected Material getMaterial() {
+        return material;
+    }
+
+    public void setSpanMax(float spanMax) {
+        this.spanMax = spanMax;
+        if (material != null) {
+            material.setFloat("SpanMax", this.spanMax);
+        }
+    }
+
+    /**
+     * set to 0.0f for higher quality
+     *
+     * @param subPixelShift
+     */
+    public void setSubPixelShift(float subPixelShift) {
+        this.subPixelShift = subPixelShift;
+        if (material != null) {
+            material.setFloat("SubPixelShif", this.subPixelShift);
+        }
+    }
+
+    /**
+     * set to 0.0f for higher quality
+     *
+     * @param reduceMul
+     */
+    public void setReduceMul(float reduceMul) {
+        this.reduceMul = reduceMul;
+        if (material != null) {
+            material.setFloat("ReduceMul", this.reduceMul);
+        }
+    }
+
+    public void setVxOffset(float vxOffset) {
+        this.vxOffset = vxOffset;
+        if (material != null) {
+            material.setFloat("VxOffset", this.vxOffset);
+        }
+    }
+
+    public float getReduceMul() {
+        return reduceMul;
+    }
+
+    public float getSpanMax() {
+        return spanMax;
+    }
+
+    public float getSubPixelShift() {
+        return subPixelShift;
+    }
+
+    public float getVxOffset() {
+        return vxOffset;
+    }
+}

+ 177 - 0
engine/src/core-effects/com/jme3/post/filters/FadeFilter.java

@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ *
+ * Fade Filter allows you to make an animated fade effect on a scene.
+ * @author Rémy Bouquet aka Nehon
+ * implemented from boxjar implementation
+ * @see <a href="http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559">http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559</a>
+ */
+public class FadeFilter extends Filter {
+
+    private float value = 1;
+    private boolean playing = false;
+    private float direction = 1;
+    private float duration = 1;
+
+    /**
+     * Creates a FadeFilter
+     */
+    public FadeFilter() {
+        super("Fade In/Out");
+    }
+
+    /**
+     * Creates a FadeFilter with the given duration
+     * @param duration 
+     */
+    public FadeFilter(float duration) {
+        this();
+        this.duration = duration;
+    }
+
+    @Override
+    protected Material getMaterial() {
+        material.setFloat("Value", value);
+        return material;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/Fade.j3md");
+    }
+
+    @Override
+    protected void preFrame(float tpf) {
+        if (playing) {
+            value += tpf * direction / duration;
+
+            if (direction > 0 && value > 1) {
+                value = 1;
+                playing = false;
+                setEnabled(false);
+            }
+            if (direction < 0 && value < 0) {
+                value = 0;
+                playing = false;
+                setEnabled(false);
+            }
+        }
+    }
+
+    /**
+     * returns the duration of the effect 
+     * @return 
+     */
+    public float getDuration() {
+        return duration;
+    }
+
+    /**
+     * Sets the duration of the filter default is 1 second
+     * @param duration 
+     */
+    public void setDuration(float duration) {
+        this.duration = duration;
+    }
+
+    /**
+     * fades the scene in (black to scene)
+     */
+    public void fadeIn() {
+        setEnabled(true);
+        direction = 1;
+        playing = true;
+    }
+
+    /**
+     * fades the scene out (scene to black)
+     */
+    public void fadeOut() {
+        setEnabled(true);
+        direction = -1;
+        playing = true;
+
+    }
+
+    public void pause() {
+        playing = false;
+    }
+    
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(duration, "duration", 1);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        duration = ic.readFloat("duration", 1);
+    }
+
+    /**
+     * return the current value of the fading
+     * can be used to chack if fade is complete (eg value=1)
+     * @return 
+     */
+    public float getValue() {
+        return value;
+    }
+
+    /**
+     * sets the fade value
+     * can be used to force complete black or compete scene
+     * @param value 
+     */
+    public void setValue(float value) {
+        this.value = value;       
+        if (material != null) {
+            material.setFloat("Value", value);
+        }
+    }
+}

+ 172 - 0
engine/src/core-effects/com/jme3/post/filters/FogFilter.java

@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ * A filter to render a fog effect
+ * @author Rémy Bouquet aka Nehon
+ */
+public class FogFilter extends Filter {
+
+    private ColorRGBA fogColor = ColorRGBA.White.clone();
+    private float fogDensity = 0.7f;
+    private float fogDistance = 1000;
+
+    /**
+     * Creates a FogFilter
+     */
+    public FogFilter() {
+        super("FogFilter");
+    }
+
+    /**
+     * Create a fog filter 
+     * @param fogColor the color of the fog (default is white)
+     * @param fogDensity the density of the fog (default is 0.7)
+     * @param fogDistance the distance of the fog (default is 1000)
+     */
+    public FogFilter(ColorRGBA fogColor, float fogDensity, float fogDistance) {
+        this();
+        this.fogColor = fogColor;
+        this.fogDensity = fogDensity;
+        this.fogDistance = fogDistance;
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return true;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/Fog.j3md");
+        material.setColor("FogColor", fogColor);
+        material.setFloat("FogDensity", fogDensity);
+        material.setFloat("FogDistance", fogDistance);
+    }
+
+    @Override
+    protected Material getMaterial() {
+
+        return material;
+    }
+
+
+    /**
+     * returns the fog color
+     * @return
+     */
+    public ColorRGBA getFogColor() {
+        return fogColor;
+    }
+
+    /**
+     * Sets the color of the fog
+     * @param fogColor
+     */
+    public void setFogColor(ColorRGBA fogColor) {
+        if (material != null) {
+            material.setColor("FogColor", fogColor);
+        }
+        this.fogColor = fogColor;
+    }
+
+    /**
+     * returns the fog density
+     * @return
+     */
+    public float getFogDensity() {
+        return fogDensity;
+    }
+
+    /**
+     * Sets the density of the fog, a high value gives a thick fog
+     * @param fogDensity
+     */
+    public void setFogDensity(float fogDensity) {
+        if (material != null) {
+            material.setFloat("FogDensity", fogDensity);
+        }
+        this.fogDensity = fogDensity;
+    }
+
+    /**
+     * returns the fog distance
+     * @return
+     */
+    public float getFogDistance() {
+        return fogDistance;
+    }
+
+    /**
+     * the distance of the fog. the higer the value the distant the fog looks
+     * @param fogDistance
+     */
+    public void setFogDistance(float fogDistance) {
+        if (material != null) {
+            material.setFloat("FogDistance", fogDistance);
+        }
+        this.fogDistance = fogDistance;
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(fogColor, "fogColor", ColorRGBA.White.clone());
+        oc.write(fogDensity, "fogDensity", 0.7f);
+        oc.write(fogDistance, "fogDistance", 1000);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        fogColor = (ColorRGBA) ic.readSavable("fogColor", ColorRGBA.White.clone());
+        fogDensity = ic.readFloat("fogDensity", 0.7f);
+        fogDistance = ic.readFloat("fogDistance", 1000);
+    }
+
+
+}

+ 78 - 0
engine/src/core-effects/com/jme3/post/filters/GammaCorrectionFilter.java

@@ -0,0 +1,78 @@
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * 
+ * @author Phate666
+ * @version 1.0 initial version
+ * @version 1.1 added luma
+ */
+public class GammaCorrectionFilter extends Filter
+{
+	private float gamma = 2.0f;
+	private boolean computeLuma = false;
+
+	public GammaCorrectionFilter()
+	{
+		super("GammaCorrectionFilter");
+	}
+
+	public GammaCorrectionFilter(float gamma)
+	{
+		this();
+		this.setGamma(gamma);
+	}
+
+	@Override
+	protected Material getMaterial()
+	{
+		return material;
+	}
+
+	@Override
+	protected void initFilter(AssetManager manager,
+			RenderManager renderManager, ViewPort vp, int w, int h)
+	{
+		material = new Material(manager,
+				"Common/MatDefs/Post/GammaCorrection.j3md");
+		material.setFloat("gamma", gamma);
+		material.setBoolean("computeLuma", computeLuma);
+	}
+
+	public float getGamma()
+	{
+		return gamma;
+	}
+
+	/**
+	 * set to 0.0 to disable gamma correction
+	 * @param gamma
+	 */
+	public void setGamma(float gamma)
+	{
+		if (material != null)
+		{
+			material.setFloat("gamma", gamma);
+		}
+		this.gamma = gamma;
+	}
+
+	public boolean isComputeLuma()
+	{
+		return computeLuma;
+	}
+
+	public void setComputeLuma(boolean computeLuma)
+	{
+		if (material != null)
+		{
+			material.setBoolean("computeLuma", computeLuma);
+		}
+		this.computeLuma = computeLuma;
+	}
+}

+ 243 - 0
engine/src/core-effects/com/jme3/post/filters/LightScatteringFilter.java

@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.post.Filter;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import java.io.IOException;
+
+/**
+ * LightScattering filters creates rays comming from a light sources 
+ * This is often reffered as god rays.
+ *
+ * @author Rémy Bouquet aka Nehon
+ */
+public class LightScatteringFilter extends Filter {
+
+    private Vector3f lightPosition;
+    private Vector3f screenLightPos = new Vector3f();
+    private int nbSamples = 50;
+    private float blurStart = 0.02f;
+    private float blurWidth = 0.9f;
+    private float lightDensity = 1.4f;
+    private boolean adaptative = true;
+    Vector3f viewLightPos = new Vector3f();
+    private boolean display = true;
+    private float innerLightDensity;
+
+    /**
+     * creates a lightScaterring filter
+     */
+    public LightScatteringFilter() {
+        super("Light Scattering");
+    }
+
+    /**
+     * Creates a lightScatteringFilter
+     * @param lightPosition 
+     */
+    public LightScatteringFilter(Vector3f lightPosition) {
+        this();
+        this.lightPosition = lightPosition;
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return true;
+    }
+
+    @Override
+    protected Material getMaterial() {
+        material.setVector3("LightPosition", screenLightPos);
+        material.setInt("NbSamples", nbSamples);
+        material.setFloat("BlurStart", blurStart);
+        material.setFloat("BlurWidth", blurWidth);
+        material.setFloat("LightDensity", innerLightDensity);
+        material.setBoolean("Display", display);
+        return material;
+    }
+
+    @Override
+    protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+        getClipCoordinates(lightPosition, screenLightPos, viewPort.getCamera());
+        //  screenLightPos.x = screenLightPos.x / viewPort.getCamera().getWidth();
+        //  screenLightPos.y = screenLightPos.y / viewPort.getCamera().getHeight();
+
+        viewPort.getCamera().getViewMatrix().mult(lightPosition, viewLightPos);
+        //System.err.println("viewLightPos "+viewLightPos);
+        display = screenLightPos.x < 1.6f && screenLightPos.x > -0.6f && screenLightPos.y < 1.6f && screenLightPos.y > -0.6f && viewLightPos.z < 0;
+//System.err.println("camdir "+viewPort.getCamera().getDirection());
+//System.err.println("lightPos "+lightPosition);
+//System.err.println("screenLightPos "+screenLightPos);
+        if (adaptative) {
+            innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f);
+        } else {
+            innerLightDensity = lightDensity;
+        }
+    }
+
+    private Vector3f getClipCoordinates(Vector3f worldPosition, Vector3f store, Camera cam) {
+
+        float w = cam.getViewProjectionMatrix().multProj(worldPosition, store);
+        store.divideLocal(w);
+
+        store.x = ((store.x + 1f) * (cam.getViewPortRight() - cam.getViewPortLeft()) / 2f + cam.getViewPortLeft());
+        store.y = ((store.y + 1f) * (cam.getViewPortTop() - cam.getViewPortBottom()) / 2f + cam.getViewPortBottom());
+        store.z = (store.z + 1f) / 2f;
+
+        return store;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/LightScattering.j3md");
+    }
+
+    /**
+     * returns the blur start of the scattering 
+     * see {@link  setBlurStart(float blurStart)}
+     * @return 
+     */
+    public float getBlurStart() {
+        return blurStart;
+    }
+
+    /**
+     * sets the blur start<br>
+     * at which distance from the light source the effect starts default is 0.02
+     * @param blurStart 
+     */
+    public void setBlurStart(float blurStart) {
+        this.blurStart = blurStart;
+    }
+
+    /**
+     * returns the blur width<br>
+     * see {@link setBlurWidth(float blurWidth)}
+     * @return 
+     */
+    public float getBlurWidth() {
+        return blurWidth;
+    }
+
+    /**
+     * sets the blur width default is 0.9
+     * @param blurWidth 
+     */
+    public void setBlurWidth(float blurWidth) {
+        this.blurWidth = blurWidth;
+    }
+
+    /**
+     * retiurns the light density<br>
+     * see {@link setLightDensity(float lightDensity)}
+     * 
+     * @return 
+     */
+    public float getLightDensity() {
+        return lightDensity;
+    }
+
+    /**
+     * sets how much the effect is visible over the rendered scene default is 1.4
+     * @param lightDensity 
+     */
+    public void setLightDensity(float lightDensity) {
+        this.lightDensity = lightDensity;
+    }
+
+    /**
+     * returns the light position
+     * @return 
+     */
+    public Vector3f getLightPosition() {
+        return lightPosition;
+    }
+
+    /**
+     * sets the light position
+     * @param lightPosition 
+     */
+    public void setLightPosition(Vector3f lightPosition) {
+        this.lightPosition = lightPosition;
+    }
+
+    /**
+     * returns the nmber of samples for the radial blur
+     * @return 
+     */
+    public int getNbSamples() {
+        return nbSamples;
+    }
+
+    /**
+     * sets the number of samples for the radial blur default is 50
+     * the higher the value the higher the quality, but the slower the performances.
+     * @param nbSamples 
+     */
+    public void setNbSamples(int nbSamples) {
+        this.nbSamples = nbSamples;
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(lightPosition, "lightPosition", Vector3f.ZERO);
+        oc.write(nbSamples, "nbSamples", 50);
+        oc.write(blurStart, "blurStart", 0.02f);
+        oc.write(blurWidth, "blurWidth", 0.9f);
+        oc.write(lightDensity, "lightDensity", 1.4f);
+        oc.write(adaptative, "adaptative", true);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        lightPosition = (Vector3f) ic.readSavable("lightPosition", Vector3f.ZERO);
+        nbSamples = ic.readInt("nbSamples", 50);
+        blurStart = ic.readFloat("blurStart", 0.02f);
+        blurWidth = ic.readFloat("blurWidth", 0.9f);
+        lightDensity = ic.readFloat("lightDensity", 1.4f);
+        adaptative = ic.readBoolean("adaptative", true);
+    }
+}

+ 147 - 0
engine/src/core-effects/com/jme3/post/filters/PosterizationFilter.java

@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+
+/**
+ * A Post Processing filter to change colors appear with sharp edges as if the
+ * available amount of colors available was not enough to draw the true image.
+ * Possibly useful in cartoon styled games. Use the strength variable to lessen
+ * influence of this filter on the total result. Values from 0.2 to 0.7 appear
+ * to give nice results.
+ *
+ * Based on an article from Geeks3D:
+ *    <a href="http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/" rel="nofollow">http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/</a>
+ *
+ * @author: Roy Straver a.k.a. Baal Garnaal
+ */
+public class PosterizationFilter extends Filter {
+
+    private int numColors = 8;
+    private float gamma = 0.6f;
+    private float strength = 1.0f;
+
+    /**
+     * Creates a posterization Filter
+     */
+    public PosterizationFilter() {
+        super("PosterizationFilter");
+    }
+
+    /**
+     * Creates a posterization Filter with the given number of colors
+     * @param numColors 
+     */
+    public PosterizationFilter(int numColors) {
+        this();
+        this.numColors = numColors;
+    }
+
+    /**
+     * Creates a posterization Filter with the given number of colors and gamma
+     * @param numColors
+     * @param gamma 
+     */
+    public PosterizationFilter(int numColors, float gamma) {
+        this(numColors);
+        this.gamma = gamma;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Post/Posterization.j3md");
+        material.setInt("NumColors", numColors);
+        material.setFloat("Gamma", gamma);
+        material.setFloat("Strength", strength);
+    }
+
+    @Override
+    protected Material getMaterial() {
+        return material;
+    }
+
+    /**
+     * Sets number of color levels used to draw the screen
+     */
+    public void setNumColors(int numColors) {
+        this.numColors = numColors;
+        if (material != null) {
+            material.setInt("NumColors", numColors);
+        }
+    }
+
+    /**
+     * Sets gamma level used to enhange visual quality
+     */
+    public void setGamma(float gamma) {
+        this.gamma = gamma;
+        if (material != null) {
+            material.setFloat("Gamma", gamma);
+        }
+    }
+
+    /**
+     * Sets urrent strength value, i.e. influence on final image
+     */
+    public void setStrength(float strength) {
+        this.strength = strength;
+        if (material != null) {
+            material.setFloat("Strength", strength);
+        }
+    }
+
+    /**
+     * Returns number of color levels used
+     */
+    public int getNumColors() {
+        return numColors;
+    }
+
+    /**
+     * Returns current gamma value
+     */
+    public float getGamma() {
+        return gamma;
+    }
+
+    /**
+     * Returns current strength value, i.e. influence on final image
+     */
+    public float getStrength() {
+        return strength;
+    }
+}

+ 156 - 0
engine/src/core-effects/com/jme3/post/filters/RadialBlurFilter.java

@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.shader.VarType;
+import java.io.IOException;
+
+/**
+ * Radially blurs the scene from the center of it
+ * @author Rémy Bouquet aka Nehon
+ */
+public class RadialBlurFilter extends Filter {
+
+    private float sampleDist = 1.0f;
+    private float sampleStrength = 2.2f;
+    private float[] samples = {-0.08f, -0.05f, -0.03f, -0.02f, -0.01f, 0.01f, 0.02f, 0.03f, 0.05f, 0.08f};
+
+    /**
+     * Creates a RadialBlurFilter
+     */
+    public RadialBlurFilter() {
+        super("Radial blur");
+    }
+
+    /**
+     * Creates a RadialBlurFilter
+     * @param sampleDist the distance between samples
+     * @param sampleStrength the strenght of each sample
+     */
+    public RadialBlurFilter(float sampleDist, float sampleStrength) {
+        this();
+        this.sampleDist = sampleDist;
+        this.sampleStrength = sampleStrength;
+    }
+
+    @Override
+    protected Material getMaterial() {
+
+        material.setFloat("SampleDist", sampleDist);
+        material.setFloat("SampleStrength", sampleStrength);
+        material.setParam("Samples", VarType.FloatArray, samples);
+
+        return material;
+    }
+
+    /**
+     * return the sample distance
+     * @return 
+     */
+    public float getSampleDistance() {
+        return sampleDist;
+    }
+
+    /**
+     * sets the samples distances default is 1
+     * @param sampleDist 
+     */
+    public void setSampleDistance(float sampleDist) {
+        this.sampleDist = sampleDist;
+    }
+
+    /**
+     * 
+     * @return 
+     * @deprecated use {@link #getSampleDistance()}
+     */
+    @Deprecated
+    public float getSampleDist() {
+        return sampleDist;
+    }
+
+    /**
+     * 
+     * @param sampleDist
+     * @deprecated use {@link #setSampleDistance(float sampleDist)}
+     */
+    @Deprecated
+    public void setSampleDist(float sampleDist) {
+        this.sampleDist = sampleDist;
+    }
+
+    /**
+     * Returns the sample Strength
+     * @return 
+     */
+    public float getSampleStrength() {
+        return sampleStrength;
+    }
+
+    /**
+     * sets the sample streanght default is 2.2
+     * @param sampleStrength 
+     */
+    public void setSampleStrength(float sampleStrength) {
+        this.sampleStrength = sampleStrength;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        material = new Material(manager, "Common/MatDefs/Blur/RadialBlur.j3md");
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(sampleDist, "sampleDist", 1.0f);
+        oc.write(sampleStrength, "sampleStrength", 2.2f);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        sampleDist = ic.readFloat("sampleDist", 1.0f);
+        sampleStrength = ic.readFloat("sampleStrength", 2.2f);
+    }
+}

+ 80 - 0
engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java

@@ -0,0 +1,80 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.post.filters;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.post.Filter;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Texture2D;
+
+/**
+ * A filter to handle translucent objects when rendering a scene with filters that uses depth like WaterFilter and SSAOFilter
+ * just create a TranslucentBucketFilter and add it to the Filter list of a FilterPostPorcessor
+ * @author Nehon
+ */
+public final class TranslucentBucketFilter extends Filter {
+
+    private RenderManager renderManager;
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
+        this.renderManager = rm;
+        material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
+        material.setColor("Color", ColorRGBA.White);
+        Texture2D tex = processor.getFilterTexture();
+        material.setTexture("Texture", tex);
+        if (tex.getImage().getMultiSamples() > 1) {
+            material.setInt("NumSamples", tex.getImage().getMultiSamples());
+        } else {
+            material.clearParam("NumSamples");
+        }
+        renderManager.setHandleTranslucentBucket(false);
+    }
+
+    /**
+     * Override this method and return false if your Filter does not need the scene texture
+     * @return
+     */
+    @Override
+    protected boolean isRequiresSceneTexture() {
+        return false;
+    }
+
+    @Override
+    protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
+        renderManager.setCamera(viewPort.getCamera(), false);
+        if (prevFilterBuffer != sceneBuffer) {
+            renderManager.getRenderer().copyFrameBuffer(prevFilterBuffer, sceneBuffer, false);
+        }
+        renderManager.getRenderer().setFrameBuffer(sceneBuffer);
+        viewPort.getQueue().renderQueue(RenderQueue.Bucket.Translucent, renderManager, viewPort.getCamera());
+    }
+
+    @Override
+    protected void cleanUpFilter(Renderer r) {
+        if (renderManager != null) {
+            renderManager.setHandleTranslucentBucket(true);
+        }
+    }
+
+    @Override
+    protected Material getMaterial() {
+        return material;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        if (renderManager != null) {
+            renderManager.setHandleTranslucentBucket(!enabled);
+        }
+    }
+}

+ 324 - 0
engine/src/core-effects/com/jme3/post/ssao/SSAOFilter.java

@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.post.ssao;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.material.Material;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.shader.VarType;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * SSAO stands for screen space ambient occlusion
+ * It's a technique that fake ambient lighting by computing shadows that near by objects would casts on each others 
+ * under the effect of an ambient light
+ * more info on this in this blog post <a href="http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/">http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/</a>
+ * 
+ * @author Rémy Bouquet aka Nehon
+ */
+public class SSAOFilter extends Filter {
+
+    private Pass normalPass;
+    private Vector3f frustumCorner;
+    private Vector2f frustumNearFar;
+    private Vector2f[] samples = {new Vector2f(1.0f, 0.0f), new Vector2f(-1.0f, 0.0f), new Vector2f(0.0f, 1.0f), new Vector2f(0.0f, -1.0f)};
+    private float sampleRadius = 5.1f;
+    private float intensity = 1.5f;
+    private float scale = 0.2f;
+    private float bias = 0.1f;
+    private boolean useOnlyAo = false;
+    private boolean useAo = true;
+    private Material ssaoMat;
+    private Pass ssaoPass;
+//    private Material downSampleMat;
+//    private Pass downSamplePass;
+    private float downSampleFactor = 1f;
+
+    /**
+     * Create a Screen Space Ambient Occlusion Filter
+     */
+    public SSAOFilter() {
+        super("SSAOFilter");
+    }
+
+    /**
+     * Create a Screen Space Ambient Occlusion Filter
+     * @param sampleRadius The radius of the area where random samples will be picked. default 5.1f
+     * @param intensity intensity of the resulting AO. default 1.2f
+     * @param scale distance between occluders and occludee. default 0.2f
+     * @param bias the width of the occlusion cone considered by the occludee. default 0.1f
+     */
+    public SSAOFilter(float sampleRadius, float intensity, float scale, float bias) {
+        this();
+        this.sampleRadius = sampleRadius;
+        this.intensity = intensity;
+        this.scale = scale;
+        this.bias = bias;
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return true;
+    }
+
+    @Override
+    protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
+        Renderer r = renderManager.getRenderer();
+        r.setFrameBuffer(normalPass.getRenderFrameBuffer());
+        renderManager.getRenderer().clearBuffers(true, true, true);
+        renderManager.setForcedTechnique("PreNormalPass");
+        renderManager.renderViewPortQueues(viewPort, false);
+        renderManager.setForcedTechnique(null);
+        renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+    }
+
+    @Override
+    protected Material getMaterial() {
+        return material;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+        int screenWidth = w;
+        int screenHeight = h;
+        postRenderPasses = new ArrayList<Pass>();
+
+        normalPass = new Pass();
+        normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
+
+
+        frustumNearFar = new Vector2f();
+
+        float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar();
+        float farX = farY * ((float) screenWidth / (float) screenHeight);
+        frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar());
+        frustumNearFar.x = vp.getCamera().getFrustumNear();
+        frustumNearFar.y = vp.getCamera().getFrustumFar();
+
+
+
+
+
+        //ssao Pass
+        ssaoMat = new Material(manager, "Common/MatDefs/SSAO/ssao.j3md");
+        ssaoMat.setTexture("Normals", normalPass.getRenderedTexture());
+        Texture random = manager.loadTexture("Common/MatDefs/SSAO/Textures/random.png");
+        random.setWrap(Texture.WrapMode.Repeat);
+        ssaoMat.setTexture("RandomMap", random);
+
+        ssaoPass = new Pass() {
+
+            @Override
+            public boolean requiresDepthAsTexture() {
+                return true;
+            }
+        };
+
+        ssaoPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth, 1, ssaoMat);
+        ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
+        ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
+        postRenderPasses.add(ssaoPass);
+        material = new Material(manager, "Common/MatDefs/SSAO/ssaoBlur.j3md");
+        material.setTexture("SSAOMap", ssaoPass.getRenderedTexture());
+
+        ssaoMat.setVector3("FrustumCorner", frustumCorner);
+        ssaoMat.setFloat("SampleRadius", sampleRadius);
+        ssaoMat.setFloat("Intensity", intensity);
+        ssaoMat.setFloat("Scale", scale);
+        ssaoMat.setFloat("Bias", bias);
+        material.setBoolean("UseAo", useAo);
+        material.setBoolean("UseOnlyAo", useOnlyAo);
+        ssaoMat.setVector2("FrustumNearFar", frustumNearFar);
+        material.setVector2("FrustumNearFar", frustumNearFar);
+        ssaoMat.setParam("Samples", VarType.Vector2Array, samples);
+
+        float xScale = 1.0f / w;
+        float yScale = 1.0f / h;
+
+        float blurScale = 2f;
+        material.setFloat("XScale", blurScale * xScale);
+        material.setFloat("YScale", blurScale * yScale);
+
+    }
+
+    /**
+     * Return the bias<br>
+     * see {@link  #setBias(float bias)}
+     * @return 
+     */
+    public float getBias() {
+        return bias;
+    }
+
+    /**
+     * Sets the the width of the occlusion cone considered by the occludee default is 0.1f
+     * @param bias 
+     */
+    public void setBias(float bias) {
+        this.bias = bias;
+        if (ssaoMat != null) {
+            ssaoMat.setFloat("Bias", bias);
+        }
+    }
+
+    /**
+     * returns the ambient occlusion intensity
+     * @return 
+     */
+    public float getIntensity() {
+        return intensity;
+    }
+
+    /**
+     * Sets the Ambient occlusion intensity default is 1.2f
+     * @param intensity 
+     */
+    public void setIntensity(float intensity) {
+        this.intensity = intensity;
+        if (ssaoMat != null) {
+            ssaoMat.setFloat("Intensity", intensity);
+        }
+
+    }
+
+    /**
+     * returns the sample radius<br>
+     * see {link setSampleRadius(float sampleRadius)}
+     * @return 
+     */
+    public float getSampleRadius() {
+        return sampleRadius;
+    }
+
+    /**
+     * Sets the radius of the area where random samples will be picked dafault 5.1f     
+     * @param sampleRadius 
+     */
+    public void setSampleRadius(float sampleRadius) {
+        this.sampleRadius = sampleRadius;
+        if (ssaoMat != null) {
+            ssaoMat.setFloat("SampleRadius", sampleRadius);
+        }
+
+    }
+
+    /**
+     * returns the scale<br>
+     * see {@link #setScale(float scale)}
+     * @return 
+     */
+    public float getScale() {
+        return scale;
+    }
+
+    /**
+     * 
+     * Returns the distance between occluders and occludee. default 0.2f
+     * @param scale 
+     */
+    public void setScale(float scale) {
+        this.scale = scale;
+        if (ssaoMat != null) {
+            ssaoMat.setFloat("Scale", scale);
+        }
+    }
+
+    /**
+     * debugging only , will be removed
+     * @return 
+     */
+    public boolean isUseAo() {
+        return useAo;
+    }
+
+    /**
+     * debugging only , will be removed
+     */
+    public void setUseAo(boolean useAo) {
+        this.useAo = useAo;
+        if (material != null) {
+            material.setBoolean("UseAo", useAo);
+        }
+
+    }
+
+    /**
+     * debugging only , will be removed
+     * @return 
+     */
+    public boolean isUseOnlyAo() {
+        return useOnlyAo;
+    }
+
+    /**
+     * debugging only , will be removed
+     */
+    public void setUseOnlyAo(boolean useOnlyAo) {
+        this.useOnlyAo = useOnlyAo;
+        if (material != null) {
+            material.setBoolean("UseOnlyAo", useOnlyAo);
+        }
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(sampleRadius, "sampleRadius", 5.1f);
+        oc.write(intensity, "intensity", 1.5f);
+        oc.write(scale, "scale", 0.2f);
+        oc.write(bias, "bias", 0.1f);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        sampleRadius = ic.readFloat("sampleRadius", 5.1f);
+        intensity = ic.readFloat("intensity", 1.5f);
+        scale = ic.readFloat("scale", 0.2f);
+        bias = ic.readFloat("bias", 0.1f);
+    }
+}

+ 125 - 0
engine/src/core-effects/com/jme3/water/ReflectionProcessor.java

@@ -0,0 +1,125 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.water;
+
+import com.jme3.math.Plane;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+
+/**
+ * Reflection Processor
+ * Used to render the reflected scene in an off view port
+ */
+public class ReflectionProcessor implements SceneProcessor {
+
+    private RenderManager rm;
+    private ViewPort vp;
+    private Camera reflectionCam;
+    private FrameBuffer reflectionBuffer;
+    private Plane reflectionClipPlane;
+
+    /**
+     * Creates a ReflectionProcessor
+     * @param reflectionCam the cam to use for reflection
+     * @param reflectionBuffer the FrameBuffer to render to
+     * @param reflectionClipPlane the clipping plane
+     */
+    public ReflectionProcessor(Camera reflectionCam, FrameBuffer reflectionBuffer, Plane reflectionClipPlane) {
+        this.reflectionCam = reflectionCam;
+        this.reflectionBuffer = reflectionBuffer;
+        this.reflectionClipPlane = reflectionClipPlane;
+    }
+
+    public void initialize(RenderManager rm, ViewPort vp) {
+        this.rm = rm;
+        this.vp = vp;
+    }
+
+    public void reshape(ViewPort vp, int w, int h) {
+    }
+
+    public boolean isInitialized() {
+        return rm != null;
+    }
+
+    public void preFrame(float tpf) {
+    }
+
+    public void postQueue(RenderQueue rq) {
+        //we need special treatement for the sky because it must not be clipped
+        rm.getRenderer().setFrameBuffer(reflectionBuffer);
+        reflectionCam.setProjectionMatrix(null);
+        rm.setCamera(reflectionCam, false);
+        rm.getRenderer().clearBuffers(true, true, true);
+        //Rendering the sky whithout clipping
+        rm.getRenderer().setDepthRange(1, 1);
+        vp.getQueue().renderQueue(RenderQueue.Bucket.Sky, rm, reflectionCam, true);
+        rm.getRenderer().setDepthRange(0, 1);
+        //setting the clip plane to the cam
+        reflectionCam.setClipPlane(reflectionClipPlane, Plane.Side.Positive);//,1
+        rm.setCamera(reflectionCam, false);
+
+    }
+
+    public void postFrame(FrameBuffer out) {
+    }
+
+    public void cleanup() {
+    }
+
+    /**
+     * Internal use only<br>
+     * returns the frame buffer
+     * @return 
+     */
+    public FrameBuffer getReflectionBuffer() {
+        return reflectionBuffer;
+    }
+
+    /**
+     * Internal use only<br>
+     * sets the frame buffer
+     * @param reflectionBuffer 
+     */
+    public void setReflectionBuffer(FrameBuffer reflectionBuffer) {
+        this.reflectionBuffer = reflectionBuffer;
+    }
+
+    /**
+     * returns the reflection cam
+     * @return 
+     */
+    public Camera getReflectionCam() {
+        return reflectionCam;
+    }
+
+    /**
+     * sets the reflection cam
+     * @param reflectionCam 
+     */
+    public void setReflectionCam(Camera reflectionCam) {
+        this.reflectionCam = reflectionCam;
+    }
+
+    /**
+     * returns the reflection clip plane
+     * @return 
+     */
+    public Plane getReflectionClipPlane() {
+        return reflectionClipPlane;
+    }
+
+    /**
+     * Sets the reflection clip plane
+     * @param reflectionClipPlane 
+     */
+    public void setReflectionClipPlane(Plane reflectionClipPlane) {
+        this.reflectionClipPlane = reflectionClipPlane;
+    }
+}

+ 589 - 0
engine/src/core-effects/com/jme3/water/SimpleWaterProcessor.java

@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.water;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.shape.Quad;
+import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.ui.Picture;
+
+/**
+ *
+ * Simple Water renders a simple plane that use reflection and refraction to look like water.
+ * It's pretty basic, but much faster than the WaterFilter
+ * It's useful if you aim low specs hardware and still want a good looking water.
+ * Usage is : 
+ * <code>
+ *      SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
+ *      //setting the scene to use for reflection
+ *      waterProcessor.setReflectionScene(mainScene);
+ *      //setting the light position
+ *      waterProcessor.setLightPosition(lightPos);
+ *      
+ *      //setting the water plane
+ *      Vector3f waterLocation=new Vector3f(0,-20,0);
+ *      waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
+ *      //setting the water color 
+ *      waterProcessor.setWaterColor(ColorRGBA.Brown);
+ *
+ *      //creating a quad to render water to
+ *      Quad quad = new Quad(400,400);
+ *
+ *      //the texture coordinates define the general size of the waves
+ *      quad.scaleTextureCoordinates(new Vector2f(6f,6f));
+ *
+ *      //creating a geom to attach the water material 
+ *      Geometry water=new Geometry("water", quad);
+ *      water.setLocalTranslation(-200, -20, 250);
+ *      water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+ *      //finally setting the material
+ *      water.setMaterial(waterProcessor.getMaterial());
+ *    
+ *      //attaching the water to the root node
+ *      rootNode.attachChild(water);
+ * </code>
+ * @author Normen Hansen & Rémy Bouquet
+ */
+public class SimpleWaterProcessor implements SceneProcessor {
+
+    protected RenderManager rm;
+    protected ViewPort vp;
+    protected Spatial reflectionScene;
+    protected ViewPort reflectionView;
+    protected ViewPort refractionView;
+    protected FrameBuffer reflectionBuffer;
+    protected FrameBuffer refractionBuffer;
+    protected Camera reflectionCam;
+    protected Camera refractionCam;
+    protected Texture2D reflectionTexture;
+    protected Texture2D refractionTexture;
+    protected Texture2D depthTexture;
+    protected Texture2D normalTexture;
+    protected Texture2D dudvTexture;
+    protected int renderWidth = 512;
+    protected int renderHeight = 512;
+    protected Plane plane = new Plane(Vector3f.UNIT_Y, Vector3f.ZERO.dot(Vector3f.UNIT_Y));
+    protected float speed = 0.05f;
+    protected Ray ray = new Ray();
+    protected Vector3f targetLocation = new Vector3f();
+    protected AssetManager manager;
+    protected Material material;
+    protected float waterDepth = 1;
+    protected float waterTransparency = 0.4f;
+    protected boolean debug = false;
+    private Picture dispRefraction;
+    private Picture dispReflection;
+    private Picture dispDepth;
+    private Plane reflectionClipPlane;
+    private Plane refractionClipPlane;
+    private float refractionClippingOffset = 0.3f;
+    private float reflectionClippingOffset = -5f;
+    private Vector3f vect1 = new Vector3f();
+    private Vector3f vect2 = new Vector3f();
+    private Vector3f vect3 = new Vector3f();
+
+    /**
+     * Creates a SimpleWaterProcessor
+     * @param manager the asset manager
+     */
+    public SimpleWaterProcessor(AssetManager manager) {
+        this.manager = manager;
+        material = new Material(manager, "Common/MatDefs/Water/SimpleWater.j3md");
+        material.setFloat("waterDepth", waterDepth);
+        material.setFloat("waterTransparency", waterTransparency / 10);
+        material.setColor("waterColor", ColorRGBA.White);
+        material.setVector3("lightPos", new Vector3f(1, -1, 1));
+
+        material.setColor("distortionScale", new ColorRGBA(0.2f, 0.2f, 0.2f, 0.2f));
+        material.setColor("distortionMix", new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
+        material.setColor("texScale", new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
+        updateClipPlanes();
+
+    }
+
+    public void initialize(RenderManager rm, ViewPort vp) {
+        this.rm = rm;
+        this.vp = vp;
+
+        loadTextures(manager);
+        createTextures();
+        applyTextures(material);
+
+        createPreViews();
+
+        material.setVector2("FrustumNearFar", new Vector2f(vp.getCamera().getFrustumNear(), vp.getCamera().getFrustumFar()));
+
+        if (debug) {
+            dispRefraction = new Picture("dispRefraction");
+            dispRefraction.setTexture(manager, refractionTexture, false);
+            dispReflection = new Picture("dispRefraction");
+            dispReflection.setTexture(manager, reflectionTexture, false);
+            dispDepth = new Picture("depthTexture");
+            dispDepth.setTexture(manager, depthTexture, false);
+        }
+    }
+
+    public void reshape(ViewPort vp, int w, int h) {
+    }
+
+    public boolean isInitialized() {
+        return rm != null;
+    }
+    float time = 0;
+    float savedTpf = 0;
+
+    public void preFrame(float tpf) {
+        time = time + (tpf * speed);
+        if (time > 1f) {
+            time = 0;
+        }
+        material.setFloat("time", time);
+        savedTpf = tpf;
+    }
+
+    public void postQueue(RenderQueue rq) {
+        Camera sceneCam = rm.getCurrentCamera();
+
+        //update ray
+        ray.setOrigin(sceneCam.getLocation());
+        ray.setDirection(sceneCam.getDirection());
+
+        //update refraction cam
+        refractionCam.setLocation(sceneCam.getLocation());
+        refractionCam.setRotation(sceneCam.getRotation());
+        refractionCam.setFrustum(sceneCam.getFrustumNear(),
+                sceneCam.getFrustumFar(),
+                sceneCam.getFrustumLeft(),
+                sceneCam.getFrustumRight(),
+                sceneCam.getFrustumTop(),
+                sceneCam.getFrustumBottom());
+
+        //update reflection cam
+        boolean inv = false;
+        if (!ray.intersectsWherePlane(plane, targetLocation)) {
+            ray.setDirection(ray.getDirection().negateLocal());
+            ray.intersectsWherePlane(plane, targetLocation);
+            inv = true;
+        }
+        Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
+        reflectionCam.setLocation(loc);
+        reflectionCam.setFrustum(sceneCam.getFrustumNear(),
+                sceneCam.getFrustumFar(),
+                sceneCam.getFrustumLeft(),
+                sceneCam.getFrustumRight(),
+                sceneCam.getFrustumTop(),
+                sceneCam.getFrustumBottom());
+        // tempVec and calcVect are just temporary vector3f objects
+        vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
+        float planeDistance = plane.pseudoDistance(vect1);
+        vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
+        vect3.set(vect1.subtractLocal(vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
+        // now set the up vector
+        reflectionCam.lookAt(targetLocation, vect3);
+        if (inv) {
+            reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
+        }
+
+        //Rendering reflection and refraction
+        rm.renderViewPort(reflectionView, savedTpf);
+        rm.renderViewPort(refractionView, savedTpf);
+        rm.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
+        rm.setCamera(sceneCam, false);
+
+    }
+
+    public void postFrame(FrameBuffer out) {
+        if (debug) {
+            displayMap(rm.getRenderer(), dispRefraction, 64);
+            displayMap(rm.getRenderer(), dispReflection, 256);
+            displayMap(rm.getRenderer(), dispDepth, 448);
+        }
+    }
+
+    public void cleanup() {
+    }
+
+    //debug only : displays maps
+    protected void displayMap(Renderer r, Picture pic, int left) {
+        Camera cam = vp.getCamera();
+        rm.setCamera(cam, true);
+        int h = cam.getHeight();
+
+        pic.setPosition(left, h / 20f);
+
+        pic.setWidth(128);
+        pic.setHeight(128);
+        pic.updateGeometricState();
+        rm.renderGeometry(pic);
+        rm.setCamera(cam, false);
+    }
+
+    protected void loadTextures(AssetManager manager) {
+        normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+        dudvTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/dudv_map.jpg");
+        normalTexture.setWrap(WrapMode.Repeat);
+        dudvTexture.setWrap(WrapMode.Repeat);
+    }
+
+    protected void createTextures() {
+        reflectionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
+        refractionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
+        depthTexture = new Texture2D(renderWidth, renderHeight, Format.Depth);
+    }
+
+    protected void applyTextures(Material mat) {
+        mat.setTexture("water_reflection", reflectionTexture);
+        mat.setTexture("water_refraction", refractionTexture);
+        mat.setTexture("water_depthmap", depthTexture);
+        mat.setTexture("water_normalmap", normalTexture);
+        mat.setTexture("water_dudvmap", dudvTexture);
+    }
+
+    protected void createPreViews() {
+        reflectionCam = new Camera(renderWidth, renderHeight);
+        refractionCam = new Camera(renderWidth, renderHeight);
+
+        // create a pre-view. a view that is rendered before the main view
+        reflectionView = new ViewPort("Reflection View", reflectionCam);
+        reflectionView.setClearFlags(true, true, true);
+        reflectionView.setBackgroundColor(ColorRGBA.Black);
+        // create offscreen framebuffer
+        reflectionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
+        //setup framebuffer to use texture
+        reflectionBuffer.setDepthBuffer(Format.Depth);
+        reflectionBuffer.setColorTexture(reflectionTexture);
+
+        //set viewport to render to offscreen framebuffer
+        reflectionView.setOutputFrameBuffer(reflectionBuffer);
+        reflectionView.addProcessor(new ReflectionProcessor(reflectionCam, reflectionBuffer, reflectionClipPlane));
+        // attach the scene to the viewport to be rendered
+        reflectionView.attachScene(reflectionScene);
+
+        // create a pre-view. a view that is rendered before the main view
+        refractionView = new ViewPort("Refraction View", refractionCam);
+        refractionView.setClearFlags(true, true, true);
+        refractionView.setBackgroundColor(ColorRGBA.Black);
+        // create offscreen framebuffer
+        refractionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
+        //setup framebuffer to use texture
+        refractionBuffer.setDepthBuffer(Format.Depth);
+        refractionBuffer.setColorTexture(refractionTexture);
+        refractionBuffer.setDepthTexture(depthTexture);
+        //set viewport to render to offscreen framebuffer
+        refractionView.setOutputFrameBuffer(refractionBuffer);
+        refractionView.addProcessor(new RefractionProcessor());
+        // attach the scene to the viewport to be rendered
+        refractionView.attachScene(reflectionScene);
+    }
+
+    protected void destroyViews() {
+        //  rm.removePreView(reflectionView);
+        rm.removePreView(refractionView);
+    }
+
+    /**
+     * Get the water material from this processor, apply this to your water quad.
+     * @return
+     */
+    public Material getMaterial() {
+        return material;
+    }
+
+    /**
+     * Sets the reflected scene, should not include the water quad!
+     * Set before adding processor.
+     * @param spat
+     */
+    public void setReflectionScene(Spatial spat) {
+        reflectionScene = spat;
+    }
+
+    /**
+     * returns the width of the reflection and refraction textures
+     * @return 
+     */
+    public int getRenderWidth() {
+        return renderWidth;
+    }
+
+    /**
+     * returns the height of the reflection and refraction textures
+     * @return 
+     */
+    public int getRenderHeight() {
+        return renderHeight;
+    }
+
+    /**
+     * Set the reflection Texture render size,
+     * set before adding the processor!
+     * @param with
+     * @param height
+     */
+    public void setRenderSize(int width, int height) {
+        renderWidth = width;
+        renderHeight = height;
+    }
+
+    /**
+     * returns the water plane
+     * @return 
+     */
+    public Plane getPlane() {
+        return plane;
+    }
+
+    /**
+     * Set the water plane for this processor.
+     * @param plane
+     */
+    public void setPlane(Plane plane) {
+        this.plane.setConstant(plane.getConstant());
+        this.plane.setNormal(plane.getNormal());
+        updateClipPlanes();
+    }
+
+    /**
+     * Set the water plane using an origin (location) and a normal (reflection direction).
+     * @param origin Set to 0,-6,0 if your water quad is at that location for correct reflection
+     * @param normal Set to 0,1,0 (Vector3f.UNIT_Y) for normal planar water
+     */
+    public void setPlane(Vector3f origin, Vector3f normal) {
+        this.plane.setOriginNormal(origin, normal);
+        updateClipPlanes();
+    }
+
+    private void updateClipPlanes() {
+        reflectionClipPlane = plane.clone();
+        reflectionClipPlane.setConstant(reflectionClipPlane.getConstant() + reflectionClippingOffset);
+        refractionClipPlane = plane.clone();
+        refractionClipPlane.setConstant(refractionClipPlane.getConstant() + refractionClippingOffset);
+
+    }
+
+    /**
+     * Set the light Position for the processor
+     * @param position
+     */
+    //TODO maybe we should provide a convenient method to compute position from direction
+    public void setLightPosition(Vector3f position) {
+        material.setVector3("lightPos", position);
+    }
+
+    /**
+     * Set the color that will be added to the refraction texture.
+     * @param color
+     */
+    public void setWaterColor(ColorRGBA color) {
+        material.setColor("waterColor", color);
+    }
+
+    /**
+     * Higher values make the refraction texture shine through earlier.
+     * Default is 4
+     * @param depth
+     */
+    public void setWaterDepth(float depth) {
+        waterDepth = depth;
+        material.setFloat("waterDepth", depth);
+    }
+
+    /**
+     * return the water depth
+     * @return 
+     */
+    public float getWaterDepth() {
+        return waterDepth;
+    }
+
+    /**
+     * returns water transparency
+     * @return 
+     */
+    public float getWaterTransparency() {
+        return waterTransparency;
+    }
+
+    /**
+     * sets the water transparency default os 0.1f
+     * @param waterTransparency 
+     */
+    public void setWaterTransparency(float waterTransparency) {
+        this.waterTransparency = Math.max(0, waterTransparency);
+        material.setFloat("waterTransparency", waterTransparency / 10);
+    }
+
+    /**
+     * Sets the speed of the wave animation, default = 0.05f.
+     * @param speed
+     */
+    public void setWaveSpeed(float speed) {
+        this.speed = speed;
+    }
+
+    /**
+     * Sets the scale of distortion by the normal map, default = 0.2
+     */
+    public void setDistortionScale(float value) {
+        material.setColor("distortionScale", new ColorRGBA(value, value, value, value));
+    }
+
+    /**
+     * Sets how the normal and dudv map are mixed to create the wave effect, default = 0.5
+     */
+    public void setDistortionMix(float value) {
+        material.setColor("distortionMix", new ColorRGBA(value, value, value, value));
+    }
+
+    /**
+     * Sets the scale of the normal/dudv texture, default = 1.
+     * Note that the waves should be scaled by the texture coordinates of the quad to avoid animation artifacts,
+     * use mesh.scaleTextureCoordinates(Vector2f) for that.
+     */
+    public void setTexScale(float value) {
+        material.setColor("texScale", new ColorRGBA(value, value, value, value));
+    }
+
+    /**
+     * retruns true if the waterprocessor is in debug mode
+     * @return 
+     */
+    public boolean isDebug() {
+        return debug;
+    }
+
+    /**
+     * set to true to display reflection and refraction textures in the GUI for debug purpose
+     * @param debug 
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Creates a quad with the water material applied to it.
+     * @param width
+     * @param height
+     * @return
+     */
+    public Geometry createWaterGeometry(float width, float height) {
+        Quad quad = new Quad(width, height);
+        Geometry geom = new Geometry("WaterGeometry", quad);
+        geom.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
+        geom.setMaterial(material);
+        return geom;
+    }
+
+    /**
+     * returns the reflection clipping plane offset
+     * @return
+     */
+    public float getReflectionClippingOffset() {
+        return reflectionClippingOffset;
+    }
+
+    /**
+     * sets the reflection clipping plane offset
+     * set a nagetive value to lower the clipping plane for relection texture rendering.     
+     * @param reflectionClippingOffset
+     */
+    public void setReflectionClippingOffset(float reflectionClippingOffset) {
+        this.reflectionClippingOffset = reflectionClippingOffset;
+        updateClipPlanes();
+    }
+
+    /**
+     * returns the refraction clipping plane offset
+     * @return
+     */
+    public float getRefractionClippingOffset() {
+        return refractionClippingOffset;
+    }
+
+    /**
+     * Sets the refraction clipping plane offset
+     * set a positive value to raise the clipping plane for refraction texture rendering
+     * @param refractionClippingOffset
+     */
+    public void setRefractionClippingOffset(float refractionClippingOffset) {
+        this.refractionClippingOffset = refractionClippingOffset;
+        updateClipPlanes();
+    }
+
+    /**
+     * Refraction Processor
+     */
+    public class RefractionProcessor implements SceneProcessor {
+
+        RenderManager rm;
+        ViewPort vp;
+
+        public void initialize(RenderManager rm, ViewPort vp) {
+            this.rm = rm;
+            this.vp = vp;
+        }
+
+        public void reshape(ViewPort vp, int w, int h) {
+        }
+
+        public boolean isInitialized() {
+            return rm != null;
+        }
+
+        public void preFrame(float tpf) {
+            refractionCam.setClipPlane(refractionClipPlane, Plane.Side.Negative);//,-1
+
+        }
+
+        public void postQueue(RenderQueue rq) {
+        }
+
+        public void postFrame(FrameBuffer out) {
+        }
+
+        public void cleanup() {
+        }
+    }
+}

+ 1050 - 0
engine/src/core-effects/com/jme3/water/WaterFilter.java

@@ -0,0 +1,1050 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 AND CONTRIBUTORS
+ * "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.
+ */
+package com.jme3.water;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.light.DirectionalLight;
+import com.jme3.light.Light;
+import com.jme3.material.Material;
+import com.jme3.math.*;
+import com.jme3.post.Filter;
+import com.jme3.post.Filter.Pass;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
+import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture.WrapMode;
+import com.jme3.texture.Texture2D;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+
+/**
+ * The WaterFilter is a 2D post process that simulate water.
+ * It renders water above and under water.
+ * See this blog post for more info <a href="http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/">http://jmonkeyengine.org/2011/01/15/new-advanced-water-effect-for-jmonkeyengine-3/</a>
+ * 
+ * 
+ * @author Rémy Bouquet aka Nehon
+ */
+public class WaterFilter extends Filter {
+
+    private Pass reflectionPass;
+    protected Spatial reflectionScene;
+    protected ViewPort reflectionView;
+    private Texture2D normalTexture;
+    private Texture2D foamTexture;
+    private Texture2D causticsTexture;
+    private Texture2D heightTexture;
+    private Plane plane;
+    private Camera reflectionCam;
+    protected Ray ray = new Ray();
+    private Vector3f targetLocation = new Vector3f();
+    private ReflectionProcessor reflectionProcessor;
+    private Matrix4f biasMatrix = new Matrix4f(0.5f, 0.0f, 0.0f, 0.5f,
+            0.0f, 0.5f, 0.0f, 0.5f,
+            0.0f, 0.0f, 0.0f, 0.5f,
+            0.0f, 0.0f, 0.0f, 1.0f);
+    private Matrix4f textureProjMatrix = new Matrix4f();
+    private boolean underWater;
+    private RenderManager renderManager;
+    private ViewPort viewPort;
+    private float time = 0;
+    //properties
+    private float speed = 1;
+    private Vector3f lightDirection = new Vector3f(0, -1, 0);
+    private ColorRGBA lightColor = ColorRGBA.White;
+    private float waterHeight = 0.0f;
+    private ColorRGBA waterColor = new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f);
+    private ColorRGBA deepWaterColor = new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f);
+    private Vector3f colorExtinction = new Vector3f(5.0f, 20.0f, 30.0f);
+    private float waterTransparency = 0.1f;
+    private float maxAmplitude = 1.5f;
+    private float shoreHardness = 0.1f;
+    private boolean useFoam = true;
+    private float foamIntensity = 0.5f;
+    private float foamHardness = 1.0f;
+    private Vector3f foamExistence = new Vector3f(0.45f, 4.35f, 1.5f);
+    private float waveScale = 0.005f;
+    private float sunScale = 3.0f;
+    private float shininess = 0.7f;
+    private Vector2f windDirection = new Vector2f(0.0f, -1.0f);
+    private int reflectionMapSize = 512;
+    private boolean useRipples = true;
+    private float normalScale = 3.0f;
+    private boolean useHQShoreline = true;
+    private boolean useSpecular = true;
+    private boolean useRefraction = true;
+    private float refractionStrength = 0.0f;
+    private float refractionConstant = 0.5f;
+    private float reflectionDisplace = 30;
+    private float underWaterFogDistance = 120;
+    private boolean useCaustics = true;
+    private float causticsIntensity = 0.5f;
+
+    /**
+     * Create a Water Filter
+     */
+    public WaterFilter() {
+        super("WaterFilter");
+    }
+
+    public WaterFilter(Node reflectionScene, Vector3f lightDirection) {
+        super("WaterFilter");
+        this.reflectionScene = reflectionScene;
+        this.lightDirection = lightDirection;
+    }
+
+    @Override
+    protected boolean isRequiresDepthTexture() {
+        return true;
+    }
+
+    @Override
+    protected void preFrame(float tpf) {
+        time = time + (tpf * speed);
+        material.setFloat("Time", time);
+        Camera sceneCam = viewPort.getCamera();
+        biasMatrix.mult(sceneCam.getViewProjectionMatrix(), textureProjMatrix);
+        material.setMatrix4("TextureProjMatrix", textureProjMatrix);
+        material.setVector3("CameraPosition", sceneCam.getLocation());
+        material.setMatrix4("ViewProjectionMatrixInverse", sceneCam.getViewProjectionMatrix().invert());
+
+        material.setFloat("WaterHeight", waterHeight);
+
+        //update reflection cam
+        ray.setOrigin(sceneCam.getLocation());
+        ray.setDirection(sceneCam.getDirection());
+        plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
+        reflectionProcessor.setReflectionClipPlane(plane);
+        boolean inv = false;
+        if (!ray.intersectsWherePlane(plane, targetLocation)) {
+            ray.setDirection(ray.getDirection().negateLocal());
+            ray.intersectsWherePlane(plane, targetLocation);
+            inv = true;
+        }
+        Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
+        reflectionCam.setLocation(loc);
+        reflectionCam.setFrustum(sceneCam.getFrustumNear(),
+                sceneCam.getFrustumFar(),
+                sceneCam.getFrustumLeft(),
+                sceneCam.getFrustumRight(),
+                sceneCam.getFrustumTop(),
+                sceneCam.getFrustumBottom());
+        TempVars vars = TempVars.get();
+
+
+        vars.vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
+        float planeDistance = plane.pseudoDistance(vars.vect1);
+        vars.vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
+        vars.vect3.set(vars.vect1.subtractLocal(vars.vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
+
+        reflectionCam.lookAt(targetLocation, vars.vect3);
+        vars.release();
+
+        if (inv) {
+            reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
+        }
+
+        //if we're under water no need to compute reflection
+        if (sceneCam.getLocation().y >= waterHeight) {
+            boolean rtb = true;
+            if (!renderManager.isHandleTranslucentBucket()) {
+                renderManager.setHandleTranslucentBucket(true);
+                rtb = false;
+            }
+            renderManager.renderViewPort(reflectionView, tpf);
+            if (!rtb) {
+                renderManager.setHandleTranslucentBucket(false);
+            }
+            renderManager.setCamera(sceneCam, false);
+            renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+
+
+            underWater = false;
+        } else {
+            underWater = true;
+        }
+    }
+
+    @Override
+    protected Material getMaterial() {
+        return material;
+    }
+
+    private DirectionalLight findLight(Node node) {
+        for (Light light : node.getWorldLightList()) {    
+            if (light instanceof DirectionalLight) {
+                return (DirectionalLight) light;
+            }
+        }
+        for (Spatial child : node.getChildren()) {
+            if (child instanceof Node) {
+                return findLight((Node) child);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
+
+        if (reflectionScene == null) {
+            reflectionScene = vp.getScenes().get(0);
+            DirectionalLight l = findLight((Node) reflectionScene);
+            if (l != null) {
+                lightDirection = l.getDirection();
+            }
+
+        }
+
+        this.renderManager = renderManager;
+        this.viewPort = vp;
+        reflectionPass = new Pass();
+        reflectionPass.init(renderManager.getRenderer(), reflectionMapSize, reflectionMapSize, Format.RGBA8, Format.Depth);
+        reflectionCam = new Camera(reflectionMapSize, reflectionMapSize);
+        reflectionView = new ViewPort("reflectionView", reflectionCam);
+        reflectionView.setClearFlags(true, true, true);
+        reflectionView.attachScene(reflectionScene);
+        reflectionView.setOutputFrameBuffer(reflectionPass.getRenderFrameBuffer());
+        plane = new Plane(Vector3f.UNIT_Y, new Vector3f(0, waterHeight, 0).dot(Vector3f.UNIT_Y));
+        reflectionProcessor = new ReflectionProcessor(reflectionCam, reflectionPass.getRenderFrameBuffer(), plane);
+        reflectionView.addProcessor(reflectionProcessor);
+
+        normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
+        if (foamTexture == null) {
+            foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
+        }
+        if (causticsTexture == null) {
+            causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
+        }
+        heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
+
+        normalTexture.setWrap(WrapMode.Repeat);
+        foamTexture.setWrap(WrapMode.Repeat);
+        causticsTexture.setWrap(WrapMode.Repeat);
+        heightTexture.setWrap(WrapMode.Repeat);
+
+        material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
+        material.setTexture("HeightMap", heightTexture);
+        material.setTexture("CausticsMap", causticsTexture);
+        material.setTexture("FoamMap", foamTexture);
+        material.setTexture("NormalMap", normalTexture);
+        material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
+
+        material.setFloat("WaterTransparency", waterTransparency);
+        material.setFloat("NormalScale", normalScale);
+        material.setFloat("R0", refractionConstant);
+        material.setFloat("MaxAmplitude", maxAmplitude);
+        material.setVector3("LightDir", lightDirection);
+        material.setColor("LightColor", lightColor);
+        material.setFloat("ShoreHardness", shoreHardness);
+        material.setFloat("RefractionStrength", refractionStrength);
+        material.setFloat("WaveScale", waveScale);
+        material.setVector3("FoamExistence", foamExistence);
+        material.setFloat("SunScale", sunScale);
+        material.setVector3("ColorExtinction", colorExtinction);
+        material.setFloat("Shininess", shininess);
+        material.setColor("WaterColor", waterColor);
+        material.setColor("DeepWaterColor", deepWaterColor);
+        material.setVector2("WindDirection", windDirection);
+        material.setFloat("FoamHardness", foamHardness);
+        material.setBoolean("UseRipples", useRipples);
+        material.setBoolean("UseHQShoreline", useHQShoreline);
+        material.setBoolean("UseSpecular", useSpecular);
+        material.setBoolean("UseFoam", useFoam);
+        material.setBoolean("UseCaustics", useCaustics);
+        material.setBoolean("UseRefraction", useRefraction);
+        material.setFloat("ReflectionDisplace", reflectionDisplace);
+        material.setFloat("FoamIntensity", foamIntensity);
+        material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
+        material.setFloat("CausticsIntensity", causticsIntensity);
+
+
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+
+        oc.write(speed, "speed", 1f);
+        oc.write(lightDirection, "lightDirection", new Vector3f(0, -1, 0));
+        oc.write(lightColor, "lightColor", ColorRGBA.White);
+        oc.write(waterHeight, "waterHeight", 0.0f);
+        oc.write(waterColor, "waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
+        oc.write(deepWaterColor, "deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
+
+        oc.write(colorExtinction, "colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
+        oc.write(waterTransparency, "waterTransparency", 0.1f);
+        oc.write(maxAmplitude, "maxAmplitude", 1.5f);
+        oc.write(shoreHardness, "shoreHardness", 0.1f);
+        oc.write(useFoam, "useFoam", true);
+
+        oc.write(foamIntensity, "foamIntensity", 0.5f);
+        oc.write(foamHardness, "foamHardness", 1.0f);
+
+        oc.write(foamExistence, "foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
+        oc.write(waveScale, "waveScale", 0.005f);
+
+        oc.write(sunScale, "sunScale", 3.0f);
+        oc.write(shininess, "shininess", 0.7f);
+        oc.write(windDirection, "windDirection", new Vector2f(0.0f, -1.0f));
+        oc.write(reflectionMapSize, "reflectionMapSize", 512);
+        oc.write(useRipples, "useRipples", true);
+
+        oc.write(normalScale, "normalScale", 3.0f);
+        oc.write(useHQShoreline, "useHQShoreline", true);
+
+        oc.write(useSpecular, "useSpecular", true);
+
+        oc.write(useRefraction, "useRefraction", true);
+        oc.write(refractionStrength, "refractionStrength", 0.0f);
+        oc.write(refractionConstant, "refractionConstant", 0.5f);
+        oc.write(reflectionDisplace, "reflectionDisplace", 30f);
+        oc.write(underWaterFogDistance, "underWaterFogDistance", 120f);
+        oc.write(causticsIntensity, "causticsIntensity", 0.5f);
+
+        oc.write(useCaustics, "useCaustics", true);
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        speed = ic.readFloat("speed", 1f);
+        lightDirection = (Vector3f) ic.readSavable("lightDirection", new Vector3f(0, -1, 0));
+        lightColor = (ColorRGBA) ic.readSavable("lightColor", ColorRGBA.White);
+        waterHeight = ic.readFloat("waterHeight", 0.0f);
+        waterColor = (ColorRGBA) ic.readSavable("waterColor", new ColorRGBA(0.0078f, 0.3176f, 0.5f, 1.0f));
+        deepWaterColor = (ColorRGBA) ic.readSavable("deepWaterColor", new ColorRGBA(0.0039f, 0.00196f, 0.145f, 1.0f));
+
+        colorExtinction = (Vector3f) ic.readSavable("colorExtinction", new Vector3f(5.0f, 20.0f, 30.0f));
+        waterTransparency = ic.readFloat("waterTransparency", 0.1f);
+        maxAmplitude = ic.readFloat("maxAmplitude", 1.5f);
+        shoreHardness = ic.readFloat("shoreHardness", 0.1f);
+        useFoam = ic.readBoolean("useFoam", true);
+
+        foamIntensity = ic.readFloat("foamIntensity", 0.5f);
+        foamHardness = ic.readFloat("foamHardness", 1.0f);
+
+        foamExistence = (Vector3f) ic.readSavable("foamExistence", new Vector3f(0.45f, 4.35f, 1.5f));
+        waveScale = ic.readFloat("waveScale", 0.005f);
+
+        sunScale = ic.readFloat("sunScale", 3.0f);
+        shininess = ic.readFloat("shininess", 0.7f);
+        windDirection = (Vector2f) ic.readSavable("windDirection", new Vector2f(0.0f, -1.0f));
+        reflectionMapSize = ic.readInt("reflectionMapSize", 512);
+        useRipples = ic.readBoolean("useRipples", true);
+
+        normalScale = ic.readFloat("normalScale", 3.0f);
+        useHQShoreline = ic.readBoolean("useHQShoreline", true);
+
+        useSpecular = ic.readBoolean("useSpecular", true);
+
+        useRefraction = ic.readBoolean("useRefraction", true);
+        refractionStrength = ic.readFloat("refractionStrength", 0.0f);
+        refractionConstant = ic.readFloat("refractionConstant", 0.5f);
+        reflectionDisplace = ic.readFloat("reflectionDisplace", 30f);
+        underWaterFogDistance = ic.readFloat("underWaterFogDistance", 120f);
+        causticsIntensity = ic.readFloat("causticsIntensity", 0.5f);
+
+        useCaustics = ic.readBoolean("useCaustics", true);
+
+    }
+
+    /**
+     * gets the height of the water plane
+     * @return
+     */
+    public float getWaterHeight() {
+        return waterHeight;
+    }
+
+    /**
+     * Sets the height of the water plane
+     * default is 0.0
+     * @param waterHeight
+     */
+    public void setWaterHeight(float waterHeight) {
+        this.waterHeight = waterHeight;
+    }
+
+    /**
+     * sets the scene to render in the reflection map
+     * @param reflectionScene 
+     */
+    public void setReflectionScene(Spatial reflectionScene) {
+        this.reflectionScene = reflectionScene;
+    }
+
+    /**
+     * returns the waterTransparency value
+     * @return
+     */
+    public float getWaterTransparency() {
+        return waterTransparency;
+    }
+
+    /**
+     * Sets how fast will colours fade out. You can also think about this
+     * values as how clear water is. Therefore use smaller values (eg. 0.05)
+     * to have crystal clear water and bigger to achieve "muddy" water.
+     * default is 0.1f
+     * @param waterTransparency
+     */
+    public void setWaterTransparency(float waterTransparency) {
+        this.waterTransparency = waterTransparency;
+        if (material != null) {
+            material.setFloat("WaterTransparency", waterTransparency);
+        }
+    }
+
+    /**
+     * Returns the normal scales applied to the normal map
+     * @return
+     */
+    public float getNormalScale() {
+        return normalScale;
+    }
+
+    /**
+     * Sets the normal scaling factors to apply to the normal map.
+     * the higher the value the more small ripples will be visible on the waves.
+     * default is 1.0
+     * @param normalScale
+     */
+    public void setNormalScale(float normalScale) {
+        this.normalScale = normalScale;
+        if (material != null) {
+            material.setFloat("NormalScale", normalScale);
+        }
+    }
+
+    /**
+     * returns the refractoin constant
+     * @return 
+     */
+    public float getRefractionConstant() {
+        return refractionConstant;
+    }
+
+    /**
+     * This is a constant related to the index of refraction (IOR) used to compute the fresnel term.
+     * F = R0 + (1-R0)( 1 - N.V)^5
+     * where F is the fresnel term, R0 the constant, N the normal vector and V tne view vector.
+     * It usually depend on the material you are lookinh through (here water).
+     * Default value is 0.3f
+     * In practice, the lowest the value and the less the reflection can be seen on water
+     * @param refractionConstant
+     */
+    public void setRefractionConstant(float refractionConstant) {
+        this.refractionConstant = refractionConstant;
+        if (material != null) {
+            material.setFloat("R0", refractionConstant);
+        }
+    }
+
+    /**
+     * return the maximum wave amplitude
+     * @return 
+     */
+    public float getMaxAmplitude() {
+        return maxAmplitude;
+    }
+
+    /**
+     * Sets the maximum waves amplitude
+     * default is 1.0
+     * @param maxAmplitude
+     */
+    public void setMaxAmplitude(float maxAmplitude) {
+        this.maxAmplitude = maxAmplitude;
+        if (material != null) {
+            material.setFloat("MaxAmplitude", maxAmplitude);
+        }
+    }
+
+    /**
+     * gets the light direction
+     * @return
+     */
+    public Vector3f getLightDirection() {
+        return lightDirection;
+    }
+
+    /**
+     * Sets the light direction
+     * @param lightDirection
+     */
+    public void setLightDirection(Vector3f lightDirection) {
+        this.lightDirection = lightDirection;
+        if (material != null) {
+            material.setVector3("LightDir", lightDirection);
+        }
+    }
+
+    /**
+     * returns the light color
+     * @return
+     */
+    public ColorRGBA getLightColor() {
+        return lightColor;
+    }
+
+    /**
+     * Sets the light color to use
+     * default is white
+     * @param lightColor
+     */
+    public void setLightColor(ColorRGBA lightColor) {
+        this.lightColor = lightColor;
+        if (material != null) {
+            material.setColor("LightColor", lightColor);
+        }
+    }
+
+    /**
+     * Return the shoreHardeness
+     * @return
+     */
+    public float getShoreHardness() {
+        return shoreHardness;
+    }
+
+    /**
+     * The smaller this value is, the softer the transition between
+     * shore and water. If you want hard edges use very big value.
+     * Default is 0.1f.
+     * @param shoreHardness
+     */
+    public void setShoreHardness(float shoreHardness) {
+        this.shoreHardness = shoreHardness;
+        if (material != null) {
+            material.setFloat("ShoreHardness", shoreHardness);
+        }
+    }
+
+    /**
+     * returns the foam hardness
+     * @return
+     */
+    public float getFoamHardness() {
+        return foamHardness;
+    }
+
+    /**
+     * Sets the foam hardness : How much the foam will blend with the shore to avoid hard edged water plane.
+     * Default is 1.0
+     * @param foamHardness
+     */
+    public void setFoamHardness(float foamHardness) {
+        this.foamHardness = foamHardness;
+        if (material != null) {
+            material.setFloat("FoamHardness", foamHardness);
+        }
+    }
+
+    /**
+     * returns the refractionStrenght
+     * @return
+     */
+    public float getRefractionStrength() {
+        return refractionStrength;
+    }
+
+    /**
+     * This value modifies current fresnel term. If you want to weaken
+     * reflections use bigger value. If you want to empasize them use
+     * value smaller then 0. Default is 0.0f.
+     * @param refractionStrength
+     */
+    public void setRefractionStrength(float refractionStrength) {
+        this.refractionStrength = refractionStrength;
+        if (material != null) {
+            material.setFloat("RefractionStrength", refractionStrength);
+        }
+    }
+
+    /**
+     * returns the scale factor of the waves height map
+     * @return
+     */
+    public float getWaveScale() {
+        return waveScale;
+    }
+
+    /**
+     * Sets the scale factor of the waves height map
+     * the smaller the value the bigger the waves
+     * default is 0.005f
+     * @param waveScale
+     */
+    public void setWaveScale(float waveScale) {
+        this.waveScale = waveScale;
+        if (material != null) {
+            material.setFloat("WaveScale", waveScale);
+        }
+    }
+
+    /**
+     * returns the foam existance vector
+     * @return
+     */
+    public Vector3f getFoamExistence() {
+        return foamExistence;
+    }
+
+    /**
+     * Describes at what depth foam starts to fade out and
+     * at what it is completely invisible. The third value is at
+     * what height foam for waves appear (+ waterHeight).
+     * default is (0.45, 4.35, 1.0);
+     * @param foamExistence
+     */
+    public void setFoamExistence(Vector3f foamExistence) {
+        this.foamExistence = foamExistence;
+        if (material != null) {
+            material.setVector3("FoamExistence", foamExistence);
+        }
+    }
+
+    /**
+     * gets the scale of the sun
+     * @return
+     */
+    public float getSunScale() {
+        return sunScale;
+    }
+
+    /**
+     * Sets the scale of the sun for specular effect
+     * @param sunScale
+     */
+    public void setSunScale(float sunScale) {
+        this.sunScale = sunScale;
+        if (material != null) {
+            material.setFloat("SunScale", sunScale);
+        }
+    }
+
+    /**
+     * Returns the color exctinction vector of the water
+     * @return
+     */
+    public Vector3f getColorExtinction() {
+        return colorExtinction;
+    }
+
+    /**
+     * Return at what depth the refraction color extinct
+     * the first value is for red
+     * the second is for green
+     * the third is for blue
+     * Play with thos parameters to "trouble" the water
+     * default is (5.0, 20.0, 30.0f);
+     * @param colorExtinction
+     */
+    public void setColorExtinction(Vector3f colorExtinction) {
+        this.colorExtinction = colorExtinction;
+        if (material != null) {
+            material.setVector3("ColorExtinction", colorExtinction);
+        }
+    }
+
+    /**
+     * Sets the foam texture
+     * @param foamTexture
+     */
+    public void setFoamTexture(Texture2D foamTexture) {
+        this.foamTexture = foamTexture;
+        foamTexture.setWrap(WrapMode.Repeat);
+        if (material != null) {
+            material.setTexture("FoamMap", foamTexture);
+        }
+    }
+
+    /**
+     * Sets the height texture
+     * @param heightTexture
+     */
+    public void setHeightTexture(Texture2D heightTexture) {
+        this.heightTexture = heightTexture;
+        heightTexture.setWrap(WrapMode.Repeat);
+    }
+
+    /**
+     * Sets the normal Texture
+     * @param normalTexture
+     */
+    public void setNormalTexture(Texture2D normalTexture) {
+        this.normalTexture = normalTexture;
+        normalTexture.setWrap(WrapMode.Repeat);
+    }
+
+    /**
+     * return the shininess factor of the water
+     * @return
+     */
+    public float getShininess() {
+        return shininess;
+    }
+
+    /**
+     * Sets the shinines factor of the water
+     * default is 0.7f
+     * @param shininess
+     */
+    public void setShininess(float shininess) {
+        this.shininess = shininess;
+        if (material != null) {
+            material.setFloat("Shininess", shininess);
+        }
+    }
+
+    /**
+     * retruns the speed of the waves
+     * @return
+     */
+    public float getSpeed() {
+        return speed;
+    }
+
+    /**
+     * Set the speed of the waves (0.0 is still) default is 1.0
+     * @param speed
+     */
+    public void setSpeed(float speed) {
+        this.speed = speed;
+    }
+
+    /**
+     * returns the color of the water
+     *
+     * @return
+     */
+    public ColorRGBA getWaterColor() {
+        return waterColor;
+    }
+
+    /**
+     * Sets the color of the water
+     * see setDeepWaterColor for deep water color
+     * default is (0.0078f, 0.5176f, 0.5f,1.0f) (greenish blue)
+     * @param waterColor
+     */
+    public void setWaterColor(ColorRGBA waterColor) {
+        this.waterColor = waterColor;
+        if (material != null) {
+            material.setColor("WaterColor", waterColor);
+        }
+    }
+
+    /**
+     * returns the deep water color
+     * @return
+     */
+    public ColorRGBA getDeepWaterColor() {
+        return deepWaterColor;
+    }
+
+    /**
+     * sets the deep water color
+     * see setWaterColor for general color
+     * default is (0.0039f, 0.00196f, 0.145f,1.0f) (very dark blue)
+     * @param deepWaterColor
+     */
+    public void setDeepWaterColor(ColorRGBA deepWaterColor) {
+        this.deepWaterColor = deepWaterColor;
+        if (material != null) {
+            material.setColor("DeepWaterColor", deepWaterColor);
+        }
+    }
+
+    /**
+     * returns the wind direction
+     * @return
+     */
+    public Vector2f getWindDirection() {
+        return windDirection;
+    }
+
+    /**
+     * sets the wind direction
+     * the direction where the waves move
+     * default is (0.0f, -1.0f)
+     * @param windDirection
+     */
+    public void setWindDirection(Vector2f windDirection) {
+        this.windDirection = windDirection;
+        if (material != null) {
+            material.setVector2("WindDirection", windDirection);
+        }
+    }
+
+    /**
+     * returns the size of the reflection map
+     * @return
+     */
+    public int getReflectionMapSize() {
+        return reflectionMapSize;
+    }
+
+    /**
+     * Sets the size of the reflection map
+     * default is 512, the higher, the better quality, but the slower the effect.
+     * @param reflectionMapSize
+     */
+    public void setReflectionMapSize(int reflectionMapSize) {
+        this.reflectionMapSize = reflectionMapSize;
+    }
+
+    /**
+     * returns true if the water uses foam
+     * @return
+     */
+    public boolean isUseFoam() {
+        return useFoam;
+    }
+
+    /**
+     * set to true to use foam with water
+     * default true
+     * @param useFoam
+     */
+    public void setUseFoam(boolean useFoam) {
+        this.useFoam = useFoam;
+        if (material != null) {
+            material.setBoolean("UseFoam", useFoam);
+        }
+
+    }
+
+    /**
+     * sets the texture to use to render caustics on the ground underwater
+     * @param causticsTexture 
+     */
+    public void setCausticsTexture(Texture2D causticsTexture) {
+        this.causticsTexture = causticsTexture;
+        if (material != null) {
+            material.setTexture("causticsMap", causticsTexture);
+        }
+    }
+
+    /**
+     * returns true if caustics are rendered
+     * @return 
+     */
+    public boolean isUseCaustics() {
+        return useCaustics;
+    }
+
+    /**
+     * set to true if you want caustics to be rendered on the ground underwater, false otherwise
+     * @param useCaustics 
+     */
+    public void setUseCaustics(boolean useCaustics) {
+        this.useCaustics = useCaustics;
+        if (material != null) {
+            material.setBoolean("UseCaustics", useCaustics);
+        }
+    }
+
+    /**
+     * return true 
+     * @return
+     */
+    public boolean isUseHQShoreline() {
+        return useHQShoreline;
+    }
+
+    public void setUseHQShoreline(boolean useHQShoreline) {
+        this.useHQShoreline = useHQShoreline;
+        if (material != null) {
+            material.setBoolean("UseHQShoreline", useHQShoreline);
+        }
+
+    }
+
+    /**
+     * returns true if the water use the refraction
+     * @return 
+     */
+    public boolean isUseRefraction() {
+        return useRefraction;
+    }
+
+    /**
+     * set to true to use refraction (default is true)
+     * @param useRefraction 
+     */
+    public void setUseRefraction(boolean useRefraction) {
+        this.useRefraction = useRefraction;
+        if (material != null) {
+            material.setBoolean("UseRefraction", useRefraction);
+        }
+
+    }
+
+    /**
+     * returns true if the ater use ripples
+     * @return 
+     */
+    public boolean isUseRipples() {
+        return useRipples;
+    }
+
+    /**
+     * 
+     * Set to true tu use ripples
+     * @param useRipples 
+     */
+    public void setUseRipples(boolean useRipples) {
+        this.useRipples = useRipples;
+        if (material != null) {
+            material.setBoolean("UseRipples", useRipples);
+        }
+
+    }
+
+    /**
+     * returns true if the water use specular
+     * @return 
+     */
+    public boolean isUseSpecular() {
+        return useSpecular;
+    }
+
+    /**
+     * Set to true to use specular lightings on the water
+     * @param useSpecular 
+     */
+    public void setUseSpecular(boolean useSpecular) {
+        this.useSpecular = useSpecular;
+        if (material != null) {
+            material.setBoolean("UseSpecular", useSpecular);
+        }
+    }
+
+    /**
+     * returns the foam intensity
+     * @return 
+     */
+    public float getFoamIntensity() {
+        return foamIntensity;
+    }
+
+    /**
+     * sets the foam intensity default is 0.5f
+     * @param foamIntensity 
+     */
+    public void setFoamIntensity(float foamIntensity) {
+        this.foamIntensity = foamIntensity;
+        if (material != null) {
+            material.setFloat("FoamIntensity", foamIntensity);
+
+        }
+    }
+
+    /**
+     * returns the reflection displace
+     * see {@link setReflectionDisplace(float reflectionDisplace)}
+     * @return 
+     */
+    public float getReflectionDisplace() {
+        return reflectionDisplace;
+    }
+
+    /**
+     * Sets the reflection displace. define how troubled will look the reflection in the water. default is 30
+     * @param reflectionDisplace 
+     */
+    public void setReflectionDisplace(float reflectionDisplace) {
+        this.reflectionDisplace = reflectionDisplace;
+        if (material != null) {
+            material.setFloat("m_ReflectionDisplace", reflectionDisplace);
+        }
+    }
+
+    /**
+     * returns true if the camera is under the water level
+     * @return 
+     */
+    public boolean isUnderWater() {
+        return underWater;
+    }
+
+    /**
+     * returns the distance of the fog when under water
+     * @return 
+     */
+    public float getUnderWaterFogDistance() {
+        return underWaterFogDistance;
+    }
+
+    /**
+     * sets the distance of the fog when under water.
+     * default is 120 (120 world units) use a high value to raise the view range under water
+     * @param underWaterFogDistance 
+     */
+    public void setUnderWaterFogDistance(float underWaterFogDistance) {
+        this.underWaterFogDistance = underWaterFogDistance;
+        if (material != null) {
+            material.setFloat("UnderWaterFogDistance", underWaterFogDistance);
+        }
+    }
+
+    /**
+     * get the intensity of caustics under water
+     * @return 
+     */
+    public float getCausticsIntensity() {
+        return causticsIntensity;
+    }
+
+    /**
+     * sets the intensity of caustics under water. goes from 0 to 1, default is 0.5f
+     * @param causticsIntensity 
+     */
+    public void setCausticsIntensity(float causticsIntensity) {
+        this.causticsIntensity = causticsIntensity;
+        if (material != null) {
+            material.setFloat("CausticsIntensity", causticsIntensity);
+        }
+    }
+}