Browse Source

Merge pull request #178 from blackberry-gaming/next

Next
Sean Paul Taylor 13 years ago
parent
commit
af0201b8d7
100 changed files with 2963 additions and 3571 deletions
  1. 7 0
      CHANGES.md
  2. 3 6
      README.md
  3. 23 0
      gameplay-encoder/gameplay-encoder.sln
  4. 12 0
      gameplay-encoder/src/Base.cpp
  5. 10 0
      gameplay-encoder/src/Base.h
  6. 4 7
      gameplay-encoder/src/EncoderArguments.cpp
  7. 8 14
      gameplay-encoder/src/TTFFontEncoder.cpp
  8. 12 2
      gameplay-encoder/src/TTFFontEncoder.h
  9. 28 12
      gameplay-encoder/src/main.cpp
  10. 2 2
      gameplay-template/android/template.build.xml
  11. 2 2
      gameplay-template/gameplay-template.vcxproj.filters
  12. 2 2
      gameplay-template/res/box.material
  13. 35 0
      gameplay-template/res/colored.frag
  14. 0 111
      gameplay-template/res/colored.fsh
  15. 24 0
      gameplay-template/res/colored.vert
  16. 0 183
      gameplay-template/res/colored.vsh
  17. 17 2
      gameplay-template/src/TemplateGame.cpp
  18. 7 2
      gameplay-template/src/TemplateGame.h
  19. 1 1
      gameplay/android/jni/Android.mk
  20. 21 20
      gameplay/gameplay.vcxproj
  21. 66 60
      gameplay/gameplay.vcxproj.filters
  22. 12 0
      gameplay/gameplay.xcodeproj/project.pbxproj
  23. 0 124
      gameplay/res/shaders/bumped-specular.fsh
  24. 0 248
      gameplay/res/shaders/bumped-specular.vsh
  25. 68 0
      gameplay/res/shaders/bumped.frag
  26. 0 113
      gameplay/res/shaders/bumped.fsh
  27. 102 0
      gameplay/res/shaders/bumped.vert
  28. 0 236
      gameplay/res/shaders/bumped.vsh
  29. 0 132
      gameplay/res/shaders/colored-specular.fsh
  30. 0 203
      gameplay/res/shaders/colored-specular.vsh
  31. 37 0
      gameplay/res/shaders/colored-unlit.frag
  32. 39 0
      gameplay/res/shaders/colored-unlit.vert
  33. 70 0
      gameplay/res/shaders/colored.frag
  34. 0 111
      gameplay/res/shaders/colored.fsh
  35. 81 0
      gameplay/res/shaders/colored.vert
  36. 0 183
      gameplay/res/shaders/colored.vsh
  37. 0 124
      gameplay/res/shaders/diffuse-specular.fsh
  38. 0 194
      gameplay/res/shaders/diffuse-specular.vsh
  39. 0 111
      gameplay/res/shaders/diffuse.fsh
  40. 0 191
      gameplay/res/shaders/diffuse.vsh
  41. 93 0
      gameplay/res/shaders/lib/attributes-skinning.vert
  42. 27 0
      gameplay/res/shaders/lib/attributes.vert
  43. 41 0
      gameplay/res/shaders/lib/lighting-directional.frag
  44. 31 0
      gameplay/res/shaders/lib/lighting-directional.vert
  45. 46 0
      gameplay/res/shaders/lib/lighting-point.frag
  46. 53 0
      gameplay/res/shaders/lib/lighting-point.vert
  47. 63 0
      gameplay/res/shaders/lib/lighting-spot.frag
  48. 54 0
      gameplay/res/shaders/lib/lighting-spot.vert
  49. 46 0
      gameplay/res/shaders/lib/lighting.frag
  50. 0 175
      gameplay/res/shaders/parallax-specular.fsh
  51. 0 118
      gameplay/res/shaders/parallax-specular.vsh
  52. 0 167
      gameplay/res/shaders/parallax.fsh
  53. 0 118
      gameplay/res/shaders/parallax.vsh
  54. 0 18
      gameplay/res/shaders/solid.fsh
  55. 0 10
      gameplay/res/shaders/solid.vsh
  56. 36 0
      gameplay/res/shaders/textured-unlit.frag
  57. 48 0
      gameplay/res/shaders/textured-unlit.vert
  58. 67 0
      gameplay/res/shaders/textured.frag
  59. 0 22
      gameplay/res/shaders/textured.fsh
  60. 87 0
      gameplay/res/shaders/textured.vert
  61. 0 78
      gameplay/res/shaders/textured.vsh
  62. 33 46
      gameplay/src/Bundle.cpp
  63. 54 6
      gameplay/src/Button.cpp
  64. 21 1
      gameplay/src/Button.h
  65. 17 0
      gameplay/src/CheckBox.cpp
  66. 19 4
      gameplay/src/CheckBox.h
  67. 86 29
      gameplay/src/Container.cpp
  68. 20 3
      gameplay/src/Container.h
  69. 63 18
      gameplay/src/Control.cpp
  70. 56 6
      gameplay/src/Control.h
  71. 142 10
      gameplay/src/Effect.cpp
  72. 8 5
      gameplay/src/FileSystem.cpp
  73. 4 4
      gameplay/src/FileSystem.h
  74. 177 119
      gameplay/src/Form.cpp
  75. 31 32
      gameplay/src/Form.h
  76. 5 1
      gameplay/src/FrameBuffer.cpp
  77. 76 2
      gameplay/src/Game.cpp
  78. 34 1
      gameplay/src/Game.h
  79. 11 1
      gameplay/src/Game.inl
  80. 181 0
      gameplay/src/Gamepad.cpp
  81. 113 0
      gameplay/src/Gamepad.h
  82. 77 47
      gameplay/src/Joystick.cpp
  83. 17 1
      gameplay/src/Joystick.h
  84. 21 1
      gameplay/src/Label.cpp
  85. 16 1
      gameplay/src/Label.h
  86. 1 13
      gameplay/src/Material.cpp
  87. 0 1
      gameplay/src/MaterialParameter.cpp
  88. 1 1
      gameplay/src/PlatformWin32.cpp
  89. 18 1
      gameplay/src/RadioButton.cpp
  90. 17 1
      gameplay/src/RadioButton.h
  91. 16 15
      gameplay/src/RenderState.cpp
  92. 3 4
      gameplay/src/RenderState.h
  93. 74 2
      gameplay/src/Slider.cpp
  94. 29 0
      gameplay/src/Slider.h
  95. 24 49
      gameplay/src/SpriteBatch.cpp
  96. 60 25
      gameplay/src/TextBox.cpp
  97. 16 1
      gameplay/src/TextBox.h
  98. 3 1
      gameplay/src/Texture.h
  99. 29 17
      gameplay/src/Theme.h
  100. 5 0
      gameplay/src/ThemeStyle.cpp

+ 7 - 0
CHANGES.md

@@ -1,3 +1,10 @@
+## v1.4.0
+
+- Pre-built versions gameplay-encoder added to bin folder with TTF, DAE and FBX support built-in.
+- Improved modular shader library with support for #include in shaders.
+- Fixes to FrameBuffer, RenderTarget and DepthStencilTarget.
+- TODO
+
 ## v1.3.0
 
 - Portrait mode games on mobile platforms.

+ 3 - 6
README.md

@@ -1,4 +1,4 @@
-## gameplay v1.3.0
+## gameplay v1.4.0
 An open-source, cross-platform 3D native C++ game framework making it easy to learn and write mobile and desktop games. 
 
 ## Supported Mobile Platforms
@@ -11,12 +11,9 @@ An open-source, cross-platform 3D native C++ game framework making it easy to le
 - Apple MacOS X (using Apple XCode 4.3.2)
 
 ## Roadmap for 'next' branch
-- Lua script bindings
-- Gamepad support
-- Vehicle physics
+- PhysicsVehicle
 - Terrain
-- Lightmaps
-- Shadows
+- ShadowMap
 
 ## Licence
 The project is open sourced under the Apache 2.0 license.

+ 23 - 0
gameplay-encoder/gameplay-encoder.sln

@@ -0,0 +1,23 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		DebugMem|Win32 = DebugMem|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Debug|Win32.Build.0 = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.ActiveCfg = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.Build.0 = Debug|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.ActiveCfg = Release|Win32
+		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 12 - 0
gameplay-encoder/src/Base.cpp

@@ -11,4 +11,16 @@ void fillArray(float values[], float value, size_t length)
     }
 }
 
+std::string getBaseName(const std::string& filepath)
+{
+    size_t index1 = filepath.find_last_of('\\');
+    size_t index2 = filepath.find_last_of('/');
+    size_t index = (index1 != -1 && index1 > index2 ? index1 : index2);
+    size_t length = filepath.length();
+    std::string filename = filepath.substr(index + 1, length);
+    length = filename.length();
+    std::string output = filename.substr(0, (length-4));
+    return output;
+}
+
 }

+ 10 - 0
gameplay-encoder/src/Base.h

@@ -76,6 +76,16 @@ enum VertexUsage
 
 void fillArray(float values[], float value, size_t length);
 
+/**
+ * Returns the base name of the given path.
+ * Example: "c:/foo/bar/model.dae" returns "model.dae"
+ * 
+ * @param filepath File path.
+ * 
+ * @return Base file name.
+ */
+std::string getBaseName(const std::string& filepath);
+
 #define ISZERO(x) (fabs(x) < 0.000001f)
 
 // Object deletion macro

+ 4 - 7
gameplay-encoder/src/EncoderArguments.cpp

@@ -179,16 +179,13 @@ void EncoderArguments::printUsage() const
     fprintf(stderr,"COLLADA and FBX file options:\n");
     fprintf(stderr,"  -i <id>\t\tFilter by node ID.\n");
     fprintf(stderr,"  -t\t\t\tWrite text/xml.\n");
-    fprintf(stderr,"  -groupAnimations <node id> <animation id>\n" \
+    fprintf(stderr,"  -g <node id> <animation id>\n" \
         "\t\t\tGroup all animation channels targetting the nodes into a new animation.\n");
     fprintf(stderr,"  -heightmaps \"<node ids>\"\n" \
         "\t\t\tList of nodes to generate heightmaps for.\n" \
         "\t\t\tNode id list should be in quotes with a space between each id.\n" \
         "\t\t\tHeightmaps will be saved in files named <nodeid>.png.\n");
     fprintf(stderr,"\n");
-    fprintf(stderr,"COLLADA file options:\n");
-    fprintf(stderr,"  -dae <filepath>\tOutput optimized DAE.\n");
-    fprintf(stderr,"\n");
     fprintf(stderr,"TTF file options:\n");
     fprintf(stderr,"  -s <size of font>\tSize of the font.\n");
     fprintf(stderr,"  -p\t\t\tOutput font preview.\n");
@@ -284,12 +281,12 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
         }
         break;
     case 'g':
-        if (str.compare("-groupAnimations") == 0)
+        if (str.compare("-groupAnimations") == 0 || str.compare("-g") == 0)
         {
             // read two strings, make sure not to go out of bounds
             if ((*index + 2) >= options.size())
             {
-                fprintf(stderr, "Error: -groupAnimations requires 2 arguments.\n");
+                fprintf(stderr, "Error: -g requires 2 arguments.\n");
                 _parseError = true;
                 return;
             }
@@ -450,7 +447,7 @@ void unittestsEncoderArguments()
     exePath.append("/gameplay-encoder.exe");
     const char* exe = exePath.c_str();
     {
-        const char* argv[] = {exe, "-groupAnimations", "root", "movements", "C:\\Git\\gaming\\GamePlay\\gameplay-encoder\\res\\seymour.dae"};
+        const char* argv[] = {exe, "-g", "root", "movements", "C:\\Git\\gaming\\GamePlay\\gameplay-encoder\\res\\seymour.dae"};
         EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
         assert(equals(args.getAnimationId("root"), ("movements")));
         assert(equals(args.getGroupAnimationNodeId()[0], ("root")));

+ 8 - 14
gameplay-encoder/src/TTFFontEncoder.cpp

@@ -1,6 +1,7 @@
 #include "Base.h"
 #include "TTFFontEncoder.h"
 #include "GPBFile.h"
+#include "StringUtil.h"
 
 namespace gameplay
 {
@@ -33,7 +34,7 @@ static void writeString(FILE* fp, const char* str)
     }
 }
 
-int writeFont(const char* filename, unsigned int fontSize, const char* id, bool fontpreview = false)
+int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview = false)
 {
     Glyph glyphArray[END_INDEX - START_INDEX];
     
@@ -48,7 +49,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     
     // Initialize font face.
     FT_Face face;
-    error = FT_New_Face(library, filename, 0, &face);
+    error = FT_New_Face(library, inFilePath, 0, &face);
     if (error)
     {
         fprintf(stderr, "FT_New_Face error: %d \n", error);
@@ -249,15 +250,9 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
         penX += advance; // Move X to next glyph position
         i++;
     }
-    
-    unsigned int idlen = strlen(id);
 
-    // Write it to the id.gpb file.
-    char* fileName = (char*)malloc(idlen + 4);
-    strcpy(fileName, id);
-    strcat(fileName, ".gpb");
 
-    FILE *gpbFp = fopen(fileName, "wb");
+    FILE *gpbFp = fopen(outFilePath, "wb");
     
     // File header and version.
     char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
@@ -303,15 +298,14 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     // Close file.
     fclose(gpbFp);
 
-    printf("%s.gpb created successfully! \n", id);
+    printf("%s.gpb created successfully. \n", getBaseName(outFilePath).c_str());
 
     if (fontpreview)
     {
         // Write out font map to an image.
-        strcpy(fileName, id);
-        strcat(fileName, ".pgm");
-
-        FILE *imageFp = fopen(fileName, "wb");
+        std::string pgmFilePath = getFilenameNoExt(outFilePath);
+        pgmFilePath.append(".pgm");
+        FILE *imageFp = fopen(pgmFilePath.c_str(), "wb");
         fprintf(imageFp, "P5 %d %d 255\n", imageWidth, imageHeight);
         fwrite((const char *)imageBuffer, sizeof(unsigned char), imageWidth * imageHeight, imageFp);
         fclose(imageFp);

+ 12 - 2
gameplay-encoder/src/TTFFontEncoder.h

@@ -3,7 +3,6 @@
 
 #define START_INDEX     32
 #define END_INDEX       127
-
 #define GLYPH_PADDING   4
 
 namespace gameplay
@@ -18,6 +17,17 @@ public:
     float uvCoords[4];
 };
 
-int writeFont(const char* filename, unsigned int fontSize, const char* id, bool fontpreview);
+/**
+ * Writes the font gpb file.
+ * 
+ * @param inFilePath Input file path to the tiff file.
+ * @param outFilePath Output file path to write the gpb to.
+ * @param fontSize Size of the font.
+ * @param id ID string of the font in the ref table.
+ * @param fontpreview True if the pgm font preview file should be written. (For debugging)
+ * 
+ * @return 0 if successful, -1 if error.
+ */
+int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview);
 
 }

+ 28 - 12
gameplay-encoder/src/main.cpp

@@ -7,16 +7,28 @@
 
 using namespace gameplay;
 
-static std::string getFileName(const std::string& filepath)
+/**
+ * Prompts the user for a font size until a valid font size is entered.
+ * 
+ * @return A valid font size.
+ */
+static unsigned int promptUserFontSize()
 {
-    size_t index1 = filepath.find_last_of('\\');
-    size_t index2 = filepath.find_last_of('/');
-    size_t index = (index1 != -1 && index1 > index2 ? index1 : index2);
-    size_t length = filepath.length();
-    std::string filename = filepath.substr(index + 1, length);
-    length = filename.length();
-    std::string output = filename.substr(0, (length-4));
-    return output;
+    static const int lowerBound = 8;
+    static const int upperBound = 500;
+    unsigned int fontSize = 0;
+    char buffer[80];
+    do
+    {
+        printf("Enter font size (between %d and %d):\n", lowerBound, upperBound);
+        std::cin.getline(buffer, 80);
+        int i = atoi(buffer);
+        if (i >= lowerBound && i <= upperBound)
+        {
+            fontSize = (unsigned int)i;
+        }
+    } while (fontSize == 0);
+    return fontSize;
 }
 
 /**
@@ -74,9 +86,13 @@ int main(int argc, const char** argv)
         }
     case EncoderArguments::FILEFORMAT_TTF:
         {
-            std::string realpath(arguments.getFilePath());
-            std::string id = getFileName(realpath);
-            writeFont(realpath.c_str(), arguments.getFontSize(), id.c_str(), arguments.fontPreviewEnabled());
+            unsigned int fontSize = arguments.getFontSize();
+            if (fontSize == 0)
+            {
+                fontSize = promptUserFontSize();
+            }
+            std::string id = getBaseName(arguments.getFilePath());
+            writeFont(arguments.getFilePath().c_str(), arguments.getOutputFilePath().c_str(), fontSize, id.c_str(), arguments.fontPreviewEnabled());
             break;
         }
     case EncoderArguments::FILEFORMAT_GPB:

+ 2 - 2
gameplay-template/android/template.build.xml

@@ -64,8 +64,8 @@
     <target name="-post-compile">
         <copy file="../res/box.gpb" tofile="assets/res/box.gpb"/>
         <copy file="../res/box.material" tofile="assets/res/box.material"/>
-        <copy file="../res/colored.vsh" tofile="assets/res/colored.vsh"/>
-        <copy file="../res/colored.fsh" tofile="assets/res/colored.fsh"/>
+        <copy file="../res/colored.vert" tofile="assets/res/colored.vert"/>
+        <copy file="../res/colored.frag" tofile="assets/res/colored.frag"/>
     </target>
 
     <!-- Import the actual build file.

+ 2 - 2
gameplay-template/gameplay-template.vcxproj.filters

@@ -18,10 +18,10 @@
     <None Include="res\box.material">
       <Filter>res</Filter>
     </None>
-    <None Include="res\colored.fsh">
+    <None Include="res\colored.frag">
       <Filter>res</Filter>
     </None>
-    <None Include="res\colored.vsh">
+    <None Include="res\colored.vert">
       <Filter>res</Filter>
     </None>
   </ItemGroup>

+ 2 - 2
gameplay-template/res/box.material

@@ -5,8 +5,8 @@ material box
         pass
         {
             // shaders
-            vertexShader = res/colored.vsh
-            fragmentShader = res/colored.fsh
+            vertexShader = res/colored.vert
+            fragmentShader = res/colored.frag
             
             // uniforms
             u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX

+ 35 - 0
gameplay-template/res/colored.frag

@@ -0,0 +1,35 @@
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+// Uniforms
+uniform vec4 u_diffuseColor;                    // Diffuse color
+uniform vec3 u_ambientColor;                    // Ambient color
+uniform vec3 u_lightColor;                      // Light color
+uniform vec3 u_lightDirection;       	        // Light direction
+
+// Inputs
+varying vec3 v_normalVector;                    // Normal vector in view space.
+
+void main()
+{
+	// Base color
+    vec4 baseColor = u_diffuseColor;
+
+    // Normalize the vectors.
+    vec3 lightDirection = normalize(u_lightDirection);
+    vec3 normalVector = normalize(v_normalVector);
+
+    // Ambient
+    vec3 ambientColor = baseColor.rgb * u_ambientColor;
+
+    // Diffuse
+	float attenuation = 1.0;
+    float ddot = dot(normalVector, lightDirection);
+    float intensity =  max(0.0, attenuation * ddot);
+    vec3 diffuseColor = u_lightColor * baseColor.rgb * intensity;
+
+    // Light the pixel
+    gl_FragColor.a = baseColor.a;
+    gl_FragColor.rgb = ambientColor + diffuseColor;
+}

+ 0 - 111
gameplay-template/res/colored.fsh

@@ -1,111 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color
-uniform vec3 u_ambientColor;                    // Ambient color
-uniform vec4 u_diffuseColor;                    // Diffuse color
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec3 v_normalVector;                    // NormalVector in view space.
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-
-void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float ddot = dot(normalVector, lightDirection);
-    float diffuseIntensity = attenuation * ddot;
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec4 v_vertexToPointLightDirection;     // Light direction w.r.t current vertex.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection.xyz);
-    
-    // Fetch point light attenuation.
-    float pointLightAttenuation = v_vertexToPointLightDirection.w;
-    lighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightDirection;              // Direction of the spot light.
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_vertexToSpotLightDirection;      // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 spotLightDirection = u_spotLightDirection; 
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" is used because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-uniform vec3 u_lightDirection;       	        // Light direction
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 lightDirection = normalize(u_lightDirection);
-
-    lighting(normalVector, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Fetch diffuse color from texture.
-    _baseColor = u_diffuseColor;
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 24 - 0
gameplay-template/res/colored.vert

@@ -0,0 +1,24 @@
+// Inputs
+attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
+attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
+
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
+uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
+
+// Outputs
+varying vec3 v_normalVector;                        // Normal vector in view space.
+
+void main()
+{
+	// Vertex attributes
+    vec4 position = a_position;
+    vec3 normal = a_normal;
+        
+    // Transform position to clip space.
+    gl_Position = u_worldViewProjectionMatrix * position;
+
+    // Transform normal to view space.
+    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    v_normalVector = inverseTransposeWorldViewMatrix * normal;
+}

+ 0 - 183
gameplay-template/res/colored.vsh

@@ -1,183 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-
-// Outputs
-varying vec3 v_normalVector;                        // NormalVector in view space.
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinNormal(float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(a_normal, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(a_normal, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(a_normal, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getNormal()
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-#endif
-
-#if defined(POINT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRangeInverse;             // Inverse of light range.
-varying vec4 v_vertexToPointLightDirection;         // Light direction w.r.t current vertex.
-
-void applyLight(vec4 position)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-    
-    // Compute the light direction.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    vec4 vertexToPointLightDirection;
-    vertexToPointLightDirection.xyz = lightDirection;
-    
-    // Attenuation.
-    vertexToPointLightDirection.w = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-varying vec3 v_vertexToSpotLightDirection;          // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(vec4 position)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-
-    // Compute the light direction.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-void applyLight(vec4 position)
-{
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-        
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    v_normalVector = inverseTransposeWorldViewMatrix * normal;
-
-    // Apply light.
-    applyLight(position);
-}

+ 17 - 2
gameplay-template/src/TemplateGame.cpp

@@ -26,6 +26,8 @@ void TemplateGame::initialize()
     Node* boxNode = _scene->findNode("box");
     Model* boxModel = boxNode->getModel();
     Material* boxMaterial = boxModel->setMaterial("res/box.material");
+	boxMaterial->getParameter("u_ambientColor")->setValue(_scene->getAmbientColor());
+	boxMaterial->getParameter("u_ambientColor")->setValue(_scene->getAmbientColor());
     boxMaterial->getParameter("u_lightColor")->setValue(light->getColor());
     boxMaterial->getParameter("u_lightDirection")->setValue(lightNode->getForwardVectorView());
 }
@@ -35,13 +37,13 @@ void TemplateGame::finalize()
     SAFE_RELEASE(_scene);
 }
 
-void TemplateGame::update(long elapsedTime)
+void TemplateGame::update(float elapsedTime)
 {
     // Rotate model
     _scene->findNode("box")->rotateY(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f));
 }
 
-void TemplateGame::render(long elapsedTime)
+void TemplateGame::render(float elapsedTime)
 {
     // Clear the color and depth buffers
     clear(CLEAR_COLOR_DEPTH, Vector4::zero(), 1.0f, 0);
@@ -61,6 +63,19 @@ bool TemplateGame::drawScene(Node* node)
     return true;
 }
 
+void TemplateGame::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+    if (evt == Keyboard::KEY_PRESS)
+    {
+        switch (key)
+        {
+        case Keyboard::KEY_ESCAPE:
+            exit();
+            break;
+        }
+    }
+}
+
 void TemplateGame::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     switch (evt)

+ 7 - 2
gameplay-template/src/TemplateGame.h

@@ -17,6 +17,11 @@ public:
      */
     TemplateGame();
 
+    /**
+     * @see Game::keyEvent
+     */
+	void keyEvent(Keyboard::KeyEvent evt, int key);
+	
     /**
      * @see Game::touchEvent
      */
@@ -37,12 +42,12 @@ protected:
     /**
      * @see Game::update
      */
-    void update(long elapsedTime);
+    void update(float elapsedTime);
 
     /**
      * @see Game::render
      */
-    void render(long elapsedTime);
+    void render(float elapsedTime);
 
 private:
 

+ 1 - 1
gameplay/android/jni/Android.mk

@@ -16,7 +16,7 @@ LOCAL_PATH := $(call my-dir)/../../src
 
 include $(CLEAR_VARS)
 LOCAL_MODULE    := libgameplay
-LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Bundle.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp FlowLayout.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp Image.cpp Joint.cpp Joystick.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
+LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Bundle.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp FlowLayout.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp Gamepad.cpp gameplay-main-android.cpp Image.cpp Joint.cpp Joystick.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
 LOCAL_CFLAGS := -D__ANDROID__ -I"../../external-deps/bullet/include" -I"../../external-deps/libpng/include" -I"../../external-deps/oggvorbis/include" -I"../../external-deps/openal/include"
 LOCAL_STATIC_LIBRARIES := android_native_app_glue
 

+ 21 - 20
gameplay/gameplay.vcxproj

@@ -43,6 +43,7 @@
     <ClCompile Include="src\FrameBuffer.cpp" />
     <ClCompile Include="src\Frustum.cpp" />
     <ClCompile Include="src\Game.cpp" />
+    <ClCompile Include="src\Gamepad.cpp" />
     <ClCompile Include="src\gameplay-main-android.cpp" />
     <ClCompile Include="src\gameplay-main-qnx.cpp" />
     <ClCompile Include="src\gameplay-main-win32.cpp" />
@@ -135,6 +136,7 @@
     <ClInclude Include="src\FrameBuffer.h" />
     <ClInclude Include="src\Frustum.h" />
     <ClInclude Include="src\Game.h" />
+    <ClInclude Include="src\Gamepad.h" />
     <ClInclude Include="src\gameplay.h" />
     <ClInclude Include="src\Image.h" />
     <ClInclude Include="src\Joint.h" />
@@ -204,26 +206,25 @@
     <None Include="res\logo_powered_black.png" />
     <None Include="res\logo_powered_white.png" />
     <None Include="res\logo_white.png" />
-    <None Include="res\shaders\bumped-specular.fsh" />
-    <None Include="res\shaders\bumped-specular.vsh" />
-    <None Include="res\shaders\bumped.fsh" />
-    <None Include="res\shaders\bumped.vsh" />
-    <None Include="res\shaders\colored-specular.fsh" />
-    <None Include="res\shaders\colored-specular.vsh" />
-    <None Include="res\shaders\colored.fsh" />
-    <None Include="res\shaders\colored.vsh" />
-    <None Include="res\shaders\diffuse-specular.fsh" />
-    <None Include="res\shaders\diffuse-specular.vsh" />
-    <None Include="res\shaders\diffuse.fsh" />
-    <None Include="res\shaders\diffuse.vsh" />
-    <None Include="res\shaders\parallax-specular.fsh" />
-    <None Include="res\shaders\parallax-specular.vsh" />
-    <None Include="res\shaders\parallax.fsh" />
-    <None Include="res\shaders\parallax.vsh" />
-    <None Include="res\shaders\solid.fsh" />
-    <None Include="res\shaders\solid.vsh" />
-    <None Include="res\shaders\textured.fsh" />
-    <None Include="res\shaders\textured.vsh" />
+    <None Include="res\shaders\bumped.frag" />
+    <None Include="res\shaders\bumped.vert" />
+    <None Include="res\shaders\colored-unlit.frag" />
+    <None Include="res\shaders\colored-unlit.vert" />
+    <None Include="res\shaders\colored.frag" />
+    <None Include="res\shaders\colored.vert" />
+    <None Include="res\shaders\lib\attributes-skinning.vert" />
+    <None Include="res\shaders\lib\attributes.vert" />
+    <None Include="res\shaders\lib\lighting-directional.frag" />
+    <None Include="res\shaders\lib\lighting-directional.vert" />
+    <None Include="res\shaders\lib\lighting-point.frag" />
+    <None Include="res\shaders\lib\lighting-point.vert" />
+    <None Include="res\shaders\lib\lighting-spot.frag" />
+    <None Include="res\shaders\lib\lighting-spot.vert" />
+    <None Include="res\shaders\lib\lighting.frag" />
+    <None Include="res\shaders\textured-unlit.frag" />
+    <None Include="res\shaders\textured-unlit.vert" />
+    <None Include="res\shaders\textured.frag" />
+    <None Include="res\shaders\textured.vert" />
     <None Include="src\BoundingBox.inl" />
     <None Include="src\BoundingSphere.inl" />
     <None Include="src\Curve.inl" />

+ 66 - 60
gameplay/gameplay.vcxproj.filters

@@ -10,6 +10,9 @@
     <Filter Include="res\shaders">
       <UniqueIdentifier>{be0b36f1-49ed-4a06-9f1f-57c654a554fe}</UniqueIdentifier>
     </Filter>
+    <Filter Include="res\shaders\lib">
+      <UniqueIdentifier>{ab587dd0-fd08-4b5e-a38d-7b3a706ab53b}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\Animation.cpp">
@@ -279,6 +282,9 @@
     <ClCompile Include="src\Joystick.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\Gamepad.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -557,68 +563,11 @@
     <ClInclude Include="src\MathUtil.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Gamepad.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <None Include="res\shaders\bumped-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\solid.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\solid.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\textured.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\textured.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
     <None Include="src\gameplay-main-macosx.mm">
       <Filter>src</Filter>
     </None>
@@ -664,6 +613,63 @@
     <None Include="src\Joystick.inl">
       <Filter>src</Filter>
     </None>
+    <None Include="res\shaders\textured.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\textured.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\textured-unlit.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\textured-unlit.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\colored.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\colored.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\colored-unlit.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\colored-unlit.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\bumped.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\bumped.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting.frag">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting-spot.vert">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting-spot.frag">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting-point.vert">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting-point.frag">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting-directional.vert">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\lighting-directional.frag">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\attributes.vert">
+      <Filter>res\shaders\lib</Filter>
+    </None>
+    <None Include="res\shaders\lib\attributes-skinning.vert">
+      <Filter>res\shaders\lib</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\PhysicsFixedConstraint.inl">

+ 12 - 0
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -171,6 +171,10 @@
 		42CD0EC8147D8FF60000361E /* VertexAttributeBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */; };
 		42CD0EC9147D8FF60000361E /* VertexFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E42147D8FF50000361E /* VertexFormat.cpp */; };
 		42CD0ECA147D8FF60000361E /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
+		42F4B7D715994CED00B5A78D /* Gamepad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42F4B7D515994CED00B5A78D /* Gamepad.cpp */; };
+		42F4B7D815994CED00B5A78D /* Gamepad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42F4B7D515994CED00B5A78D /* Gamepad.cpp */; };
+		42F4B7D915994CED00B5A78D /* Gamepad.h in Headers */ = {isa = PBXBuildFile; fileRef = 42F4B7D615994CED00B5A78D /* Gamepad.h */; };
+		42F4B7DA15994CED00B5A78D /* Gamepad.h in Headers */ = {isa = PBXBuildFile; fileRef = 42F4B7D615994CED00B5A78D /* Gamepad.h */; };
 		5B04C52D14BFCFE100EB0071 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB1147D8FF50000361E /* Animation.cpp */; };
 		5B04C52E14BFCFE100EB0071 /* AnimationClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB3147D8FF50000361E /* AnimationClip.cpp */; };
 		5B04C52F14BFCFE100EB0071 /* AnimationController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB5147D8FF50000361E /* AnimationController.cpp */; };
@@ -565,6 +569,8 @@
 		42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexAttributeBinding.h; path = src/VertexAttributeBinding.h; sourceTree = SOURCE_ROOT; };
 		42CD0E42147D8FF50000361E /* VertexFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VertexFormat.cpp; path = src/VertexFormat.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0E43147D8FF50000361E /* VertexFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexFormat.h; path = src/VertexFormat.h; sourceTree = SOURCE_ROOT; };
+		42F4B7D515994CED00B5A78D /* Gamepad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Gamepad.cpp; path = src/Gamepad.cpp; sourceTree = SOURCE_ROOT; };
+		42F4B7D615994CED00B5A78D /* Gamepad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Gamepad.h; path = src/Gamepad.h; sourceTree = SOURCE_ROOT; };
 		5B04C5CA14BFCFE100EB0071 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
 		5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformiOS.mm; path = src/PlatformiOS.mm; sourceTree = SOURCE_ROOT; };
@@ -755,6 +761,8 @@
 				42CD0DDC147D8FF50000361E /* Game.cpp */,
 				42CD0DDD147D8FF50000361E /* Game.h */,
 				42C932AF14919FD10098216A /* Game.inl */,
+				42F4B7D515994CED00B5A78D /* Gamepad.cpp */,
+				42F4B7D615994CED00B5A78D /* Gamepad.h */,
 				5BD5266A150F8257004C9099 /* gameplay.dox */,
 				42CD0DE1147D8FF50000361E /* gameplay.h */,
 				5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */,
@@ -1075,6 +1083,7 @@
 				426878AE153F4BB300844500 /* FlowLayout.h in Headers */,
 				4239DDEE157545A1005EA3F6 /* Joystick.h in Headers */,
 				4239DDF4157545C1005EA3F6 /* MathUtil.h in Headers */,
+				42F4B7D915994CED00B5A78D /* Gamepad.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1173,6 +1182,7 @@
 				426878AF153F4BB300844500 /* FlowLayout.h in Headers */,
 				4239DDEF157545A1005EA3F6 /* Joystick.h in Headers */,
 				4239DDF5157545C1005EA3F6 /* MathUtil.h in Headers */,
+				42F4B7DA15994CED00B5A78D /* Gamepad.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1329,6 +1339,7 @@
 				422260D61537790F0011E3AB /* Bundle.cpp in Sources */,
 				426878AC153F4BB300844500 /* FlowLayout.cpp in Sources */,
 				4239DDEC157545A1005EA3F6 /* Joystick.cpp in Sources */,
+				42F4B7D715994CED00B5A78D /* Gamepad.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1421,6 +1432,7 @@
 				422260D71537790F0011E3AB /* Bundle.cpp in Sources */,
 				426878AD153F4BB300844500 /* FlowLayout.cpp in Sources */,
 				4239DDED157545A1005EA3F6 /* Joystick.cpp in Sources */,
+				42F4B7D815994CED00B5A78D /* Gamepad.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 0 - 124
gameplay/res/shaders/bumped-specular.fsh

@@ -1,124 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                  // Light color.
-uniform vec3 u_ambientColor;                // Ambient color.
-uniform float u_specularExponent;           // Specular exponent or shininess property.
-uniform sampler2D u_diffuseTexture;         // Diffuse texture.
-uniform sampler2D u_normalMapTexture;       // Normal map texture.
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec2 v_texCoord;                    // Texture Coordinate.
-varying vec3 v_cameraDirection;             // Direction the camera is looking at in tangent space.
-
-// Global variables
-vec4 _baseColor;                            // Base color
-vec3 _ambientColor;                         // Ambient Color
-vec3 _diffuseColor;                         // Diffuse Color
-vec3 _specularColor;                        // Specular color
-
-void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-
-    // Specular
-    vec3 halfVector = normalize(cameraDirection + lightDirection);
-    float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
-    specularIntensity = max(0.0, specularIntensity);
-    _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec3 v_vertexToPointLightDirection;   // Light direction w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;        // Attenuation of point light.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    // Fetch normals from the normal map.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection);
-    
-    float pointLightAttenuation = clamp(v_pointLightAttenuation, 0.0, 1.0);
-    
-    lighting(normalVector, cameraDirection, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform float u_spotLightInnerAngleCos;       // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;       // The soft outer part [0.0 - 1.0]
-varying vec3 v_spotLightDirection;            // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;    // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;         // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Fetch normals from the normal map.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 spotLightDirection = normalize(v_spotLightDirection);
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-    
-    // "-lightDirection" because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-    
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, cameraDirection, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-varying vec3 v_lightDirection;                 // Direction of light in tangent space.
-
-void applyLight()
-{
-    // Fetch normals from the normal map
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(v_lightDirection);
-
-    lighting(normalVector, cameraDirection, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 248
gameplay/res/shaders/bumped-specular.vsh

@@ -1,248 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-uniform vec3 u_cameraPosition;                      // Position of the camera.
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                          // Vertex Texture Coordinate (u, v)
-attribute vec3 a_tangent;                           // Vertex Tangent (x, y, z)
-attribute vec3 a_binormal;                          // Vertex Binormal (actually Bi-tangent) (x, y, z)
-
-// Outputs
-varying vec2 v_texCoord;                            // Texture Coordinate (u,v)
-varying vec3 v_cameraDirection;                     // Direction the camera is looking at in tangent space.
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinTangentSpaceVector(vec3 vector, float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(vector, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(vector, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(vector, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getTangentSpaceVector(vec3 vector)
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-vec3 getNormal()
-{
-    return getTangentSpaceVector(a_normal);
-}
-
-vec3 getTangent()
-{
-    return getTangentSpaceVector(a_tangent);
-}
-
-vec3 getBinormal()
-{
-    return getTangentSpaceVector(a_binormal);
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-vec3 getTangent()
-{
-    return a_tangent;
-}
-
-vec3 getBinormal()
-{
-    return a_binormal;
-}
-
-#endif
-
-#if defined(POINT_LIGHT)
-
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRangeInverse;             // Inverse of light range 
-varying vec3 v_vertexToPointLightDirection;         // Direction of point light w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;              // Attenuation of point light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-    
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    vec3 vertexToPointLightDirection = tangentSpaceTransformMatrix * lightDirection;
-
-    // Attenuation
-    v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-uniform vec3 u_spotLightDirection;                  // Direction
-varying vec3 v_spotLightDirection;                  // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;          // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-
-    // Transform spot light direction to tangent space.
-    v_spotLightDirection = tangentSpaceTransformMatrix * u_spotLightDirection;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    lightDirection = tangentSpaceTransformMatrix * lightDirection;
-    
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-uniform vec3 u_lightDirection;                      // Direction
-varying vec3 v_lightDirection;                      // Direction of light in tangent space.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-    
-    // Transform light direction to tangent space.
-    v_lightDirection = tangentSpaceTransformMatrix * u_lightDirection;
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-    vec3 tangent = getTangent();
-    vec3 binormal = getBinormal();
-    
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform the normal, tangent and binormals to  view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    vec3 tangentVector  = normalize(inverseTransposeWorldViewMatrix * tangent);
-    vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);
-    vec3 binormalVector = normalize(inverseTransposeWorldViewMatrix * binormal);
-
-    // Create a transform to convert a vector to tangent space.
-    mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x,
-                                            tangentVector.y, binormalVector.y, normalVector.y,
-                                            tangentVector.z, binormalVector.z, normalVector.z);
-    // Apply light.
-    applyLight(tangentSpaceTransformMatrix);
-
-    // Pass on the texture coordinates to Fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 68 - 0
gameplay/res/shaders/bumped.frag

@@ -0,0 +1,68 @@
+#define LIGHTING
+#define BUMPED
+
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+// Inputs
+varying vec3 v_normalVector;					// Normal vector in view space
+varying vec2 v_texCoord;						// Texture Coordinate
+#if defined(POINT_LIGHT)
+varying vec3 v_vertexToPointLightDirection;		// Light direction w.r.t current vertex in tangent space.
+varying float v_pointLightAttenuation;			// Attenuation of point light.
+#elif defined(SPOT_LIGHT)
+varying vec3 v_spotLightDirection;				// Direction of spot light in tangent space.
+varying vec3 v_vertexToSpotLightDirection;		// Direction of the spot light w.r.t current vertex in tangent space.
+varying float v_spotLightAttenuation;			// Attenuation of spot light.
+#else
+varying vec3 v_lightDirection;					// Direction of light in tangent space.
+#endif
+#if defined(SPECULAR)
+varying vec3 v_cameraDirection;                 // Camera direction
+#endif
+
+// Uniforms
+uniform sampler2D u_diffuseTexture;        		// Diffuse map texture
+uniform sampler2D u_normalmapTexture;       	// Normalmap texture
+uniform vec3 u_ambientColor;                    // Ambient color
+uniform vec3 u_lightColor;                      // Light color
+uniform vec3 u_lightDirection;					// Light direction
+#if defined(SPECULAR)
+uniform float u_specularExponent;				// Specular exponent.
+#endif
+#if defined(MODULATE_COLOR)
+uniform vec4 u_modulateColor;					// Modulation color
+#endif
+#if defined(MODULATE_ALPHA)
+uniform float u_modulateAlpha;					// Modulation alpha
+#endif
+#include "lib/lighting.frag"
+#if defined(POINT_LIGHT)
+#include "lib/lighting-point.frag"
+#elif defined(SPOT_LIGHT)
+uniform float u_spotLightInnerAngleCos;			// The bright spot [0.0 - 1.0]
+uniform float u_spotLightOuterAngleCos;			// The soft outer part [0.0 - 1.0]
+#include "lib/lighting-spot.frag"
+#else
+#include "lib/lighting-directional.frag"
+#endif
+
+// Fragment program
+void main()
+{
+    // Fetch diffuse color from texture.
+    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
+
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = getLitPixel();
+
+	// Global color modulation
+	#if defined(MODULATE_COLOR)
+	gl_FragColor *= u_modulateColor;
+	#endif
+	#if defined(MODULATE_ALPHA)
+    gl_FragColor.a *= u_modulateAlpha;
+    #endif
+}

+ 0 - 113
gameplay/res/shaders/bumped.fsh

@@ -1,113 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                   // Light color.
-uniform vec3 u_ambientColor;                 // Ambient color.
-uniform sampler2D u_diffuseTexture;          // Diffuse texture.
-uniform sampler2D u_normalMapTexture;        // Normal map texture.
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec2 v_texCoord;                     // Texture Coordinate.
-
-// Common colors
-vec4 _baseColor;                             // Base color
-vec3 _ambientColor;                          // Ambient Color
-vec3 _diffuseColor;                          // Diffuse Color
-
-void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec3 v_vertexToPointLightDirection;  // Light direction w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;       // Attenuation of point light.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    // Fetch normals from the normal map.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0);
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection);
-    float pointLightAttenuation = clamp(v_pointLightAttenuation, 0.0, 1.0);
-    
-    // Fetch point light attenuation.
-    lighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform float u_spotLightInnerAngleCos;       // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;       // The soft outer part [0.0 - 1.0]
-varying vec3 v_spotLightDirection;            // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;    // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;         // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Fetch normals from the normal map.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).xyz * 2.0 - 1.0);
-    vec3 spotLightDirection =normalize(v_spotLightDirection);
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-    
-    // "-lightDirection" because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-    
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-varying vec3 v_lightDirection;                  // Direction of light in tangent space.
-
-void applyLight()
-{
-    // Normalize vectors.
-    // Fetch normals from the normal map
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).xyz * 2.0 - 1.0);
-    vec3 lightDirection = normalize(v_lightDirection);
-
-    lighting(normalVector, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 102 - 0
gameplay/res/shaders/bumped.vert

@@ -0,0 +1,102 @@
+#define LIGHTING
+#define BUMPED
+
+// Inputs
+attribute vec4 a_position;									// Vertex Position							(x, y, z, w)
+attribute vec3 a_normal;									// Vertex Normal							(x, y, z)
+attribute vec2 a_texCoord;									// Vertex Texture Coordinate				(u, v)
+attribute vec3 a_tangent;									// Vertex Tangent							(x, y, z)
+attribute vec3 a_binormal;									// Vertex Binormal/Bitangent				(x, y, z)
+#if defined(SKINNING)
+attribute vec4 a_blendWeights;								// Vertex blend weight, up to 4				(0, 1, 2, 3) 
+attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette	(0, 1, 2, 3)
+#endif
+
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
+uniform mat4 u_inverseTransposeWorldViewMatrix;				// Matrix to transform a normal to view space
+#if defined(SKINNING)
+uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
+#endif
+#if defined(SPECULAR)
+uniform mat4 u_worldViewMatrix;								// Matrix to tranform a position to view space
+uniform vec3 u_cameraPosition;                 				// Position of the camera in view space
+#endif
+#if defined(TEXTURE_REPEAT)
+uniform vec2 u_textureRepeat;
+#endif
+#if defined(TEXTURE_OFFSET)
+uniform vec2 u_textureOffset;
+#endif
+#if defined(POINT_LIGHT)
+uniform vec3 u_pointLightPosition;							// Position of light
+uniform float u_pointLightRangeInverse;						// Inverse of light range
+#elif defined(SPOT_LIGHT)
+uniform vec3 u_spotLightPosition;							// Position of light
+uniform float u_spotLightRangeInverse;						// Inverse of light range
+uniform vec3 u_spotLightDirection;							// Direction of light
+#else
+uniform vec3 u_lightDirection;								// Direction of light
+#endif
+
+// Outputs
+varying vec3 v_normalVector;								// Normal vector in view space
+varying vec2 v_texCoord;									// Texture Coordinate
+#if defined(SPECULAR)
+varying vec3 v_cameraDirection;								// Direction the camera is looking at in tangent space
+#endif
+// Lighting
+#if defined(POINT_LIGHT)
+varying vec3 v_vertexToPointLightDirection;					// Direction of point light w.r.t current vertex in tangent space
+varying float v_pointLightAttenuation;						// Attenuation of point light
+#include "lib/lighting-point.vert"
+#elif defined(SPOT_LIGHT)
+varying vec3 v_vertexToSpotLightDirection;					// Direction of the spot light w.r.t current vertex in tangent space
+varying float v_spotLightAttenuation;						// Attenuation of spot light
+varying vec3 v_spotLightDirection;							// Direction of spot light in tangent space
+#include "lib/lighting-spot.vert"
+#else
+uniform vec3 v_lightDirection;								// Direction of light
+#include "lib/lighting-directional.vert"
+#endif
+
+// Vertex Attribute Accessors
+#if defined(SKINNING)
+#include "lib/attributes-skinning.vert"
+#else
+#include "lib/attributes.vert" 
+#endif
+
+// Vertex program
+void main()
+{
+    // Get the position, normal, tangents and binormals.
+    vec4 position = getPosition();
+    vec3 normal = getNormal();
+    vec3 tangent = getTangent();
+    vec3 binormal = getBinormal();
+    
+    // Transform position to clip space.
+    gl_Position = u_worldViewProjectionMatrix * position;
+
+    // Transform the normal, tangent and binormals to view space.
+    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);
+    
+    // Create a transform to convert a vector to tangent space.
+    vec3 tangentVector  = normalize(inverseTransposeWorldViewMatrix * tangent);
+    vec3 binormalVector = normalize(inverseTransposeWorldViewMatrix * binormal);
+    mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x, tangentVector.y, binormalVector.y, normalVector.y, tangentVector.z, binormalVector.z, normalVector.z);
+    
+    // Apply light.
+    applyLight(tangentSpaceTransformMatrix);
+    
+    // Texture transformation.
+    v_texCoord = a_texCoord;
+    #if defined(TEXTURE_REPEAT)
+    v_texCoord *= u_textureRepeat;
+    #endif
+    #if defined(TEXTURE_OFFSET)
+    v_texCoord += u_textureOffset;
+    #endif
+}

+ 0 - 236
gameplay/res/shaders/bumped.vsh

@@ -1,236 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;       // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix; // Matrix to transform a normal to view space.
-
-// Inputs
-attribute vec4 a_position;                      // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                        // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                      // Vertex Texture Coordinate (u, v)
-attribute vec3 a_tangent;                       // Vertex Tangent (x, y, z)
-attribute vec3 a_binormal;                      // Vertex Binormal (actually Bi-tangent) (x, y, z)
-
-// Outputs
-varying vec2 v_texCoord;                        // Texture Coordinate (u,v)
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinTangentSpaceVector(vec3 vector, float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(vector, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(vector, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(vector, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getTangentSpaceVector(vec3 vector)
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-vec3 getNormal()
-{
-    return getTangentSpaceVector(a_normal);
-}
-
-vec3 getTangent()
-{
-    return getTangentSpaceVector(a_tangent);
-}
-
-vec3 getBinormal()
-{
-    return getTangentSpaceVector(a_binormal);
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-vec3 getTangent()
-{
-    return a_tangent;
-}
-
-vec3 getBinormal()
-{
-    return a_binormal;
-}
-
-#endif
-
-#if defined(POINT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                 // Matrix to tranform a position to view space.
-uniform vec3 u_pointLightPosition;              // Position
-uniform float u_pointLightRangeInverse;         // Inverse of light range.
-varying vec3 v_vertexToPointLightDirection;     // Direction of point light w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;          // Attenuation of point light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    // World space position.
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    vec3 vertexToSpotLightDirection = tangentSpaceTransformMatrix * lightDirection;
-
-    // Attenuation
-    v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToSpotLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                 // Matrix to tranform a position to view space.
-uniform vec3 u_spotLightPosition;               // Position
-uniform float u_spotLightRangeInverse;          // Inverse of light range.
-uniform vec3 u_spotLightDirection;              // Direction
-varying vec3 v_spotLightDirection;              // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;      // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-
-    // Transform spot light direction to tangent space.
-    v_spotLightDirection = tangentSpaceTransformMatrix * u_spotLightDirection;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    lightDirection = tangentSpaceTransformMatrix * lightDirection;
-    
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-uniform vec3 u_lightDirection;                  // Direction
-varying vec3 v_lightDirection;                  // Direction of light in tangent space.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    // Transform light direction to tangent space.
-    v_lightDirection = tangentSpaceTransformMatrix * u_lightDirection;
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-    vec3 tangent = getTangent();
-    vec3 binormal = getBinormal();
-    
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform the normal, tangent and binormals to  view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix);
-    vec3 tangentVector  = normalize(inverseTransposeWorldViewMatrix * tangent);
-    vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);
-    vec3 binormalVector = normalize(inverseTransposeWorldViewMatrix * binormal);
-
-    // Create a transform to convert a vector to tangent space.
-    mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x,
-                                            tangentVector.y, binormalVector.y, normalVector.y,
-                                            tangentVector.z, binormalVector.z, normalVector.z);
-
-    // Apply light.
-    applyLight(tangentSpaceTransformMatrix);
-
-    // Pass on the texture coordinates to Fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 0 - 132
gameplay/res/shaders/colored-specular.fsh

@@ -1,132 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color
-uniform vec3 u_ambientColor;                    // Ambient color
-uniform float u_specularExponent;               // Specular exponent or shininess property
-#if !defined(VERTEX_COLOR)
-uniform vec4 u_diffuseColor;                    // Diffuse color
-#endif
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec3 v_normalVector;                    // NormalVector in view space
-varying vec3 v_cameraDirection;                 // Camera direction
-#if defined(VERTEX_COLOR)
-varying vec4 v_color;							// Vertex color
-#endif
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-vec3 _specularColor;                            // Specular color
-
-void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float ddot = abs(dot(normalVector, lightDirection));
-    float diffuseIntensity = attenuation * ddot;
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-
-    // Specular
-    vec3 halfVector = normalize(cameraDirection + lightDirection);
-    float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
-    specularIntensity = max(0.0, specularIntensity);
-    _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec4 v_vertexToPointLightDirection;      // Light direction w.r.t current vertex.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection.xyz);
-
-    // Fetch point light attenuation.
-    float pointLightAttenuation = v_vertexToPointLightDirection.w;
-    lighting(normalVector, cameraDirection, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightDirection;              // Direction of the spot light.
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_vertexToSpotLightDirection;      // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 spotLightDirection = normalize(u_spotLightDirection); 
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" is used because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, cameraDirection, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-uniform vec3 u_lightDirection;                  // Light direction
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(u_lightDirection);
-
-    lighting(normalVector, cameraDirection, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Set base diffuse color
-#if defined(VERTEX_COLOR)
-	_baseColor = v_color;
-#else
-	_baseColor = u_diffuseColor;
-#endif
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 203
gameplay/res/shaders/colored-specular.vsh

@@ -1,203 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-uniform mat4 u_worldMatrix;                         // Matrix to tranform a position to world space.
-uniform vec3 u_cameraPosition;                      // Position of the camera.
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-#if defined(VERTEX_COLOR)
-attribute vec4 a_color;
-#endif
-
-// Outputs
-varying vec3 v_normalVector;                        // NormalVector in view space
-varying vec3 v_cameraDirection;                     // Camera direction
-#if defined(VERTEX_COLOR)
-varying vec4 v_color;								// Vertex color
-#endif
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinNormal(float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(a_normal, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(a_normal, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(a_normal, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getNormal()
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-#endif
-
-
-#if defined(POINT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRangeInverse;             // Inverse of light range. 
-varying vec4 v_vertexToPointLightDirection;         // Light direction w.r.t current vertex.
-
-void applyLight(vec4 position)
-{
-    // World space position.
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-    
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    vec4 vertexToPointLightDirection;
-    vertexToPointLightDirection.xyz = lightDirection;
-    
-    // Attenuation
-    vertexToPointLightDirection.w = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-varying vec3 v_vertexToSpotLightDirection;          // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(vec4 position)
-{
-    // World space position.
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Compute the light direction with light position and the vertex position.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-void applyLight(vec4 position)
-{
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    v_normalVector = inverseTransposeWorldViewMatrix * normal;
-
-    // Compute the camera direction.
-    vec4 positionWorldSpace = u_worldMatrix * position;
-    v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
-
-#if defined(VERTEX_COLOR)
-	v_color = a_color;
-#endif
-
-    // Apply light.
-    applyLight(position);
-}

+ 37 - 0
gameplay/res/shaders/colored-unlit.frag

@@ -0,0 +1,37 @@
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+// Inputs
+#if defined(VERTEX_COLOR)
+varying vec3 v_color;						// Input Vertex color ( r g b )
+#endif
+
+uniform vec4 u_diffuseColor;               	// Diffuse color
+
+// Uniforms
+#if defined(MODULATE_COLOR)
+uniform vec4 u_modulateColor;               // Modulation color
+#endif
+#if defined(MODULTE_ALPHA)
+uniform float u_modulateAlpha;              // Modulation alpha
+#endif
+
+// Fragment program
+void main()
+{
+    // Set base diffuse color
+    #if defined(VERTEX_COLOR)
+	gl_FragColor.rgb = v_color;
+	#else
+	gl_FragColor = u_diffuseColor;
+    #endif
+	
+	// Global color modulation
+	#if defined(MODULATE_COLOR)
+	gl_FragColor *= u_modulateColor;
+	#endif
+	#if defined(MODULTE_ALPHA)
+    gl_FragColor.a *= u_modulateAlpha;
+    #endif
+}

+ 39 - 0
gameplay/res/shaders/colored-unlit.vert

@@ -0,0 +1,39 @@
+// Inputs
+attribute vec4 a_position;									// Vertex Position							(x, y, z, w)
+#if defined(SKINNING)
+attribute vec4 a_blendWeights;								// Vertex blend weight, up to 4				(0, 1, 2, 3) 
+attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette	(0, 1, 2, 3)
+#endif
+#if defined(VERTEX_COLOR)
+attribute vec3 a_color;										// Vertex Color								(r, g, b)
+varying vec3 v_color;										// Output Vertex color						(r, g, b)
+#endif
+
+
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space.
+#if defined(SKINNING)
+uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices as an array of floats
+#endif
+
+// Attribute accessor
+#if defined(SKINNING)
+#include "lib/attributes-skinning.vert"
+#else
+#include "lib/attributes.vert" 
+#endif
+
+// Vertex Program
+void main()
+{
+    // Get the vertex position
+    vec4 position = getPosition();
+    
+    // Transform position to clip space.a
+    gl_Position = u_worldViewProjectionMatrix *  position;
+    
+     // Pass on vertex color to fragment shader
+    #if defined(VERTEX_COLOR)
+	v_color = a_color;
+    #endif
+}

+ 70 - 0
gameplay/res/shaders/colored.frag

@@ -0,0 +1,70 @@
+#define LIGHTING
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+// Inputs
+varying vec3 v_normalVector;					// Normal vector in view space
+#if defined(VERTEX_COLOR)
+varying vec3 v_color;							// Vertex color
+#endif
+#if defined(POINT_LIGHT)
+varying vec3 v_vertexToPointLightDirection;		// Light direction w.r.t current vertex in tangent space
+varying float v_pointLightAttenuation;			// Attenuation of point light
+#elif defined(SPOT_LIGHT)
+varying vec3 v_spotLightDirection;				// Direction of spot light in tangent space.
+varying vec3 v_vertexToSpotLightDirection;		// Direction of the spot light w.r.t current vertex in tangent space
+varying float v_spotLightAttenuation;			// Attenuation of spot light
+#else
+varying vec3 v_lightDirection;					// Direction of light in tangent space
+#endif
+#if defined(SPECULAR)
+varying vec3 v_cameraDirection;                 // Camera direction
+#endif
+
+// Uniforms
+uniform vec4 u_diffuseColor;               		// Diffuse color
+uniform vec3 u_ambientColor;                    // Ambient color
+uniform vec3 u_lightColor;                      // Light color
+uniform vec3 u_lightDirection;					// Light direction
+#if defined(SPECULAR)
+uniform float u_specularExponent;				// Specular exponent
+#endif
+#if defined(MODULATE_COLOR)
+uniform vec4 u_modulateColor;					// Modulation color
+#endif
+#if defined(MODULATE_ALPHA)
+uniform float u_modulateAlpha;					// Modulation alpha
+#endif
+#include "lib/lighting.frag"
+#if defined(POINT_LIGHT)
+#include "lib/lighting-point.frag"
+#elif defined(SPOT_LIGHT)
+uniform float u_spotLightInnerAngleCos;			// The bright spot [0.0 - 1.0]
+uniform float u_spotLightOuterAngleCos;			// The soft outer part [0.0 - 1.0]
+#include "lib/lighting-spot.frag"
+#else
+#include "lib/lighting-directional.frag"
+#endif
+
+// Fragment program
+void main()
+{
+    // Set base diffuse color
+    #if defined(VERTEX_COLOR)
+	_baseColor.rgb = v_color;
+	#else
+	_baseColor = u_diffuseColor;
+	#endif
+
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = getLitPixel();
+    
+	#if defined(MODULATE_COLOR)
+    gl_FragColor.a *= u_modulateColor;
+    #endif
+	#if defined(MODULATE_ALPHA)
+    gl_FragColor.a *= u_modulateAlpha;
+    #endif
+}

+ 0 - 111
gameplay/res/shaders/colored.fsh

@@ -1,111 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color
-uniform vec3 u_ambientColor;                    // Ambient color
-uniform vec4 u_diffuseColor;                    // Diffuse color
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec3 v_normalVector;                    // NormalVector in view space.
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-
-void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float ddot = dot(normalVector, lightDirection);
-    float diffuseIntensity = attenuation * ddot;
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec4 v_vertexToPointLightDirection;     // Light direction w.r.t current vertex.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection.xyz);
-    
-    // Fetch point light attenuation.
-    float pointLightAttenuation = v_vertexToPointLightDirection.w;
-    lighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightDirection;              // Direction of the spot light.
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_vertexToSpotLightDirection;      // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 spotLightDirection = u_spotLightDirection; 
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" is used because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-uniform vec3 u_lightDirection;       	        // Light direction
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 lightDirection = normalize(u_lightDirection);
-
-    lighting(normalVector, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Fetch diffuse color from texture.
-    _baseColor = u_diffuseColor;
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 81 - 0
gameplay/res/shaders/colored.vert

@@ -0,0 +1,81 @@
+#define LIGHTING
+
+// Inputs
+attribute vec4 a_position;									// Vertex Position							(x, y, z, w)
+attribute vec3 a_normal;									// Vertex Normal							(x, y, z)
+#if defined(SKINNING)
+attribute vec4 a_blendWeights;								// Vertex blend weight, up to 4				(0, 1, 2, 3) 
+attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette	(0, 1, 2, 3)
+#endif
+#if defined(VERTEX_COLOR)
+attribute vec3 a_color;										// Output Vertex Color
+varying vec3 v_color;										// Output Vertex Color 
+#endif
+
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space.
+uniform mat4 u_inverseTransposeWorldViewMatrix;				// Matrix to transform a normal to view space.
+#if defined(SKINNING)
+uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
+#endif
+#if defined(SPECULAR)
+uniform mat4 u_worldViewMatrix;								// Matrix to tranform a position to view space.
+uniform vec3 u_cameraPosition;                 				// Position of the camera in view space.
+#endif
+#if defined(POINT_LIGHT)
+uniform vec3 u_pointLightPosition;							// Position of light
+uniform float u_pointLightRangeInverse;						// Inverse of light range 
+#elif defined(SPOT_LIGHT)
+uniform vec3 u_spotLightPosition;							// Position of light
+uniform float u_spotLightRangeInverse;						// Inverse of light range.
+#else
+#endif
+
+// Outputs
+varying vec3 v_normalVector;								// Normal vector in view space.
+#if defined(SPECULAR)
+varying vec3 v_cameraDirection;								// Direction the camera is looking at in tangent space.
+#endif
+// Lighting
+#if defined(POINT_LIGHT)
+varying vec3 v_vertexToPointLightDirection;					// Direction of point light w.r.t current vertex in tangent space.
+varying float v_pointLightAttenuation;						// Attenuation of point light.
+#include "lib/lighting-point.vert"
+#elif defined(SPOT_LIGHT)
+varying vec3 v_vertexToSpotLightDirection;					// Direction of the spot light w.r.t current vertex in tangent space.
+varying float v_spotLightAttenuation;						// Attenuation of spot light.
+#include "lib/lighting-spot.vert"
+#else
+uniform vec3 u_lightDirection;								// Direction of light
+#include "lib/lighting-directional.vert"
+#endif
+
+// Vertex attribute accessors
+#if defined(SKINNING)
+#include "lib/attributes-skinning.vert"
+#else
+#include "lib/attributes.vert" 
+#endif
+
+// Vertex program
+void main()
+{
+    // Get the position and normal
+    vec4 position = getPosition();
+    vec3 normal = getNormal();
+
+    // Transform position to clip space.
+    gl_Position = u_worldViewProjectionMatrix * position;
+
+    // Transform normal to view space.
+    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    v_normalVector = inverseTransposeWorldViewMatrix * normal;
+
+    // Apply light.
+    applyLight(position);
+    
+    // Pass the vertex color to fragment shader
+    #if defined(VERTEX_COLOR)
+	v_color = a_color;
+    #endif
+}

+ 0 - 183
gameplay/res/shaders/colored.vsh

@@ -1,183 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-
-// Outputs
-varying vec3 v_normalVector;                        // NormalVector in view space.
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinNormal(float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(a_normal, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(a_normal, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(a_normal, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getNormal()
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-#endif
-
-#if defined(POINT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRangeInverse;             // Inverse of light range.
-varying vec4 v_vertexToPointLightDirection;         // Light direction w.r.t current vertex.
-
-void applyLight(vec4 position)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-    
-    // Compute the light direction.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    vec4 vertexToPointLightDirection;
-    vertexToPointLightDirection.xyz = lightDirection;
-    
-    // Attenuation.
-    vertexToPointLightDirection.w = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-varying vec3 v_vertexToSpotLightDirection;          // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(vec4 position)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-
-    // Compute the light direction.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-void applyLight(vec4 position)
-{
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-        
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    v_normalVector = inverseTransposeWorldViewMatrix * normal;
-
-    // Apply light.
-    applyLight(position);
-}

+ 0 - 124
gameplay/res/shaders/diffuse-specular.fsh

@@ -1,124 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color
-uniform vec3 u_ambientColor;                    // Ambient color
-uniform float u_specularExponent;               // Specular exponent or shininess property.
-uniform sampler2D u_diffuseTexture;             // Diffuse texture.
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec3 v_normalVector;                    // NormalVector in view space.
-varying vec2 v_texCoord;                        // Texture coordinate (u, v).
-varying vec3 v_cameraDirection;                 // Camera direction
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-vec3 _specularColor;                            // Specular color
-
-void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float ddot = dot(normalVector, lightDirection);
-    float diffuseIntensity = attenuation * ddot;
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-
-    // Specular
-    vec3 halfVector = normalize(lightDirection + cameraDirection);
-    float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
-    specularIntensity = max(0.0, specularIntensity);
-    _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec4 v_vertexToPointLightDirection;      // Light direction w.r.t current vertex.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection.xyz);
-    
-    // Fetch point light attenuation.
-    float pointLightAttenuation = v_vertexToPointLightDirection.w;
-    lighting(normalVector, cameraDirection, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightDirection;              // Direction of the spot light.
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_vertexToSpotLightDirection;      // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 spotLightDirection = normalize(u_spotLightDirection); 
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" is used because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-    
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, cameraDirection, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-uniform vec3 u_lightDirection;                  // Light direction
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(u_lightDirection);
-
-    lighting(normalVector, cameraDirection, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 194
gameplay/res/shaders/diffuse-specular.vsh

@@ -1,194 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_cameraPosition;                      // Position of the camera in view space.
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                          // Vertex Texture Coordinate (u, v)
-
-// Outputs
-varying vec3 v_normalVector;                        // NormalVector in view space.
-varying vec2 v_texCoord;                            // Texture coordinate (u, v).
-varying vec3 v_cameraDirection;                     // Camera direction
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinNormal(float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(a_normal, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(a_normal, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(a_normal, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getNormal()
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-#endif
-
-#if defined(POINT_LIGHT)
-
-uniform vec3 u_pointLightPosition;                      // Position
-uniform float u_pointLightRangeInverse;                 // Inverse of light range.
-varying vec4 v_vertexToPointLightDirection;             // Light direction w.r.t current vertex.
-
-void applyLight(vec4 position)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-    
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-
-    vec4 vertexToPointLightDirection;
-    vertexToPointLightDirection.xyz = lightDirection;
-
-    // Attenuation
-    vertexToPointLightDirection.w = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightPosition;                       // Position
-uniform float u_spotLightRangeInverse;                  // Inverse of light range.
-varying vec3 v_vertexToSpotLightDirection;              // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;                   // Attenuation of spot light.
-
-void applyLight(vec4 position)
-{
-    // World space position.
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Compute the light direction with light position and the vertex position.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-void applyLight(vec4 position)
-{
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform normal to view space.
-    mat3 normalMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                             u_inverseTransposeWorldViewMatrix[1].xyz,
-                             u_inverseTransposeWorldViewMatrix[2].xyz);
-    v_normalVector = normalMatrix * normal;
-
-    // Compute the camera direction.
-    vec4 positionWorldSpace = u_worldViewMatrix * position;
-    v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
-
-    // Apply light.
-    applyLight(position);
-
-	// Pass on the texture coordinates to Fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 0 - 111
gameplay/res/shaders/diffuse.fsh

@@ -1,111 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color
-uniform vec3 u_ambientColor;                    // Ambient color
-uniform sampler2D u_diffuseTexture;             // Diffuse texture.
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec3 v_normalVector;                    // NormalVector in view space.
-varying vec2 v_texCoord;                        // Texture coordinate (u, v).
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-
-void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-	float ddot = dot(normalVector, lightDirection);
-    float diffuseIntensity = attenuation * ddot;
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec4 v_vertexToPointLightDirection;     // Light direction w.r.t current vertex.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection.xyz);
-    
-    // Fetch point light attenuation.
-    float pointLightAttenuation = v_vertexToPointLightDirection.w;
-    lighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightDirection;              // Direction of the spot light.
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_vertexToSpotLightDirection;      // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 spotLightDirection =normalize(u_spotLightDirection); 
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" is used because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-uniform vec3 u_lightDirection;                  // Light direction
-
-void applyLight()
-{
-    vec3 normalVector = normalize(v_normalVector);
-    vec3 lightDirection = normalize(u_lightDirection);
-
-    lighting(normalVector, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
-
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 191
gameplay/res/shaders/diffuse.vsh

@@ -1,191 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                          // Vertex Texture Coordinate (u, v)
-
-// Outputs
-varying vec3 v_normalVector;                        // NormalVector in view space.
-varying vec2 v_texCoord;                            // Texture coordinate (u, v).
-varying vec3 v_cameraDirection;                     // Camera direction
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-vec3 _skinnedNormal;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-void skinNormal(float blendWeight, int matrixIndex)
-{
-    vec3 tmp;
-
-    tmp.x = dot(a_normal, u_matrixPalette[matrixIndex].xyz);
-    tmp.y = dot(a_normal, u_matrixPalette[matrixIndex + 1].xyz);
-    tmp.z = dot(a_normal, u_matrixPalette[matrixIndex + 2].xyz);
-
-    _skinnedNormal += blendWeight * tmp;
-}
-
-vec3 getNormal()
-{
-    _skinnedNormal = vec3(0.0);
-
-    // Transform normal to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinNormal(blendWeight, matrixIndex);
-
-    return _skinnedNormal;
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-vec3 getNormal()
-{
-    return a_normal;
-}
-
-#endif
-
-#if defined(POINT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRange;                    // Inverse of light range.
-varying vec4 v_vertexToPointLightDirection;         // Light direction w.r.t current vertex.
-
-void applyLight(vec4 position)
-{
-    // World space position.
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-    
-    // Compute the light direction.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    vec4 vertexToPointLightDirection;
-    vertexToPointLightDirection.xyz = lightDirection;
-    
-    // Attenuation
-    vertexToPointLightDirection.w = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-varying vec3 v_vertexToSpotLightDirection;          // Light direction w.r.t current vertex.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(vec4 position)
-{
-    // World space position.
-    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-void applyLight(vec4 position)
-{
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-    vec3 normal = getNormal();
-    
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    v_normalVector = inverseTransposeWorldViewMatrix * normal;
-
-    // Apply light.
-    applyLight(position);
-
-    // Pass on the texture coordinates to Fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 93 - 0
gameplay/res/shaders/lib/attributes-skinning.vert

@@ -0,0 +1,93 @@
+vec4 _skinnedPosition;
+#if defined(LIGHTING)
+vec3 _skinnedNormal;
+#endif
+
+void skinPosition(float blendWeight, int matrixIndex)
+{
+    vec4 tmp;
+    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
+    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
+    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
+    tmp.w = a_position.w;
+    _skinnedPosition += blendWeight * tmp;
+}
+
+vec4 getPosition()
+{
+    _skinnedPosition = vec4(0.0);
+
+    // Transform position to view space using matrix palette with four matrices used to transform a vertex.
+    float blendWeight = a_blendWeights[0];
+    int matrixIndex = int (a_blendIndices[0]) * 3;
+    skinPosition(blendWeight, matrixIndex);
+
+    blendWeight = a_blendWeights[1];
+    matrixIndex = int(a_blendIndices[1]) * 3;
+    skinPosition(blendWeight, matrixIndex);
+
+    blendWeight = a_blendWeights[2];
+    matrixIndex = int(a_blendIndices[2]) * 3;
+    skinPosition(blendWeight, matrixIndex);
+
+    blendWeight = a_blendWeights[3];
+    matrixIndex = int(a_blendIndices[3]) * 3;
+    skinPosition(blendWeight, matrixIndex);
+
+    return _skinnedPosition;    
+}
+
+void skinTangentSpaceVector(vec3 vector, float blendWeight, int matrixIndex)
+{
+    vec3 tmp;
+    tmp.x = dot(vector, u_matrixPalette[matrixIndex].xyz);
+    tmp.y = dot(vector, u_matrixPalette[matrixIndex + 1].xyz);
+    tmp.z = dot(vector, u_matrixPalette[matrixIndex + 2].xyz);
+    _skinnedNormal += blendWeight * tmp;
+}
+
+vec3 getTangentSpaceVector(vec3 vector)
+{
+    _skinnedNormal = vec3(0.0);
+
+    // Transform normal to view space using matrix palette with four matrices used to transform a vertex.
+    float blendWeight = a_blendWeights[0];
+    int matrixIndex = int (a_blendIndices[0]) * 3;
+    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
+
+    blendWeight = a_blendWeights[1];
+    matrixIndex = int(a_blendIndices[1]) * 3;
+    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
+
+    blendWeight = a_blendWeights[2];
+    matrixIndex = int(a_blendIndices[2]) * 3;
+    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
+
+    blendWeight = a_blendWeights[3];
+    matrixIndex = int(a_blendIndices[3]) * 3;
+    skinTangentSpaceVector(vector, blendWeight, matrixIndex);
+
+    return _skinnedNormal;
+}
+
+#if defined(LIGHTING)
+
+vec3 getNormal()
+{
+    return getTangentSpaceVector(a_normal);
+}
+
+#if defined(BUMPED)
+
+vec3 getTangent()
+{
+    return getTangentSpaceVector(a_tangent);
+}
+
+vec3 getBinormal()
+{
+    return getTangentSpaceVector(a_binormal);
+}
+
+#endif
+#endif

+ 27 - 0
gameplay/res/shaders/lib/attributes.vert

@@ -0,0 +1,27 @@
+vec4 getPosition()
+{
+    return a_position;    
+}
+
+#if defined(LIGHTING)
+
+vec3 getNormal()
+{
+    return a_normal;
+}
+
+#if defined(BUMPED)
+
+vec3 getTangent()
+{
+    return a_tangent;
+}
+
+vec3 getBinormal()
+{
+    return a_binormal;
+}
+
+#endif
+
+#endif

+ 41 - 0
gameplay/res/shaders/lib/lighting-directional.frag

@@ -0,0 +1,41 @@
+#if defined(BUMPED)
+
+vec3 getLitPixel()
+{
+    // Fetch normals from the normal map
+    vec3 normalVector = normalize(texture2D(u_normalmapTexture, v_texCoord).rgb * 2.0 - 1.0);
+    vec3 lightDirection = normalize(v_lightDirection);
+    
+    #if defined(SPECULAR)
+    
+    vec3 cameraDirection = normalize(v_cameraDirection);
+    return computeLighting(normalVector, -lightDirection, 1.0, cameraDirection);
+    
+    #else
+    
+    return computeLighting(normalVector, -lightDirection, 1.0);
+    
+    #endif
+}
+
+#else
+
+vec3 getLitPixel()
+{
+    // Normalize the vectors.
+    vec3 normalVector = normalize(v_normalVector);
+    vec3 lightDirection = normalize(u_lightDirection);
+
+    #if defined(SPECULAR)
+    
+    vec3 cameraDirection = normalize(v_cameraDirection);
+    return computeLighting(normalVector, -lightDirection, 1.0, cameraDirection);
+    
+    #else
+    
+    return computeLighting(normalVector, -lightDirection, 1.0);
+    
+    #endif
+}
+
+#endif

+ 31 - 0
gameplay/res/shaders/lib/lighting-directional.vert

@@ -0,0 +1,31 @@
+#if defined(BUMPED)
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    // Transform light direction to tangent space
+    v_lightDirection = tangentSpaceTransformMatrix * u_lightDirection;
+    
+    #if defined(SPECULAR)
+
+    // Compute the camera direction for specular lighting
+    vec4 positionWorldSpace = u_worldViewMatrix * a_position;
+    v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
+    
+    #endif
+}
+
+#else
+
+void applyLight(vec4 position)
+{
+    
+    #if defined(SPECULAR)
+
+    // Compute the camera direction for specular lighting
+    vec4 positionWorldSpace = u_worldViewMatrix * position;
+    v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
+
+    #endif
+}
+
+#endif

+ 46 - 0
gameplay/res/shaders/lib/lighting-point.frag

@@ -0,0 +1,46 @@
+#if defined(BUMPED)
+
+vec3 getLitPixel()
+{
+    // Fetch normals from the normal map and normalize the vectors
+    vec3 normalVector = normalize(texture2D(u_normalmapTexture, v_texCoord).rgb * 2.0 - 1.0);
+    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection);
+    
+    float pointLightAttenuation = clamp(v_pointLightAttenuation, 0.0, 1.0);
+    
+    #if defined(SPECULAR)
+    
+    vec3 cameraDirection = normalize(v_cameraDirection);
+    return computeLighting(normalVector, vertexToPointLightDirection, pointLightAttenuation, cameraDirection);
+    
+    #else
+    
+    return computeLighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
+    
+    #endif
+}
+
+#else
+
+vec3 getLitPixel()
+{
+    // Normalize the vectors.
+    vec3 normalVector = normalize(v_normalVector);    
+    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection);
+    
+    // Fetch point light attenuation.
+    float pointLightAttenuation = v_pointLightAttenuation;
+    
+    #if defined (SPECULAR)
+    
+    vec3 cameraDirection = normalize(v_cameraDirection);    
+    return computeLighting(normalVector, vertexToPointLightDirection, pointLightAttenuation, cameraDirection);
+    
+    #else
+    
+    return computeLighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
+    
+    #endif
+}
+
+#endif

+ 53 - 0
gameplay/res/shaders/lib/lighting-point.vert

@@ -0,0 +1,53 @@
+#if defined(BUMPED)
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
+    
+    // Compute the light direction with light position and the vertex position.
+    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
+    
+    // Transform current light direction to tangent space.
+    vec3 vertexToPointLightDirection = tangentSpaceTransformMatrix * lightDirection;
+
+    // Attenuation
+    v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
+
+    // Output light direction.
+    v_vertexToPointLightDirection =  vertexToPointLightDirection;
+    
+    #if defined (SPECULAR)
+ 
+    // Compute camera direction and transform it to tangent space.
+    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
+    
+    #endif
+}
+
+#else
+
+void applyLight(vec4 position)
+{
+    // World space position.
+    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
+    
+    // Compute the light direction.
+    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
+   
+    vec4 vertexToPointLightDirection;
+    vertexToPointLightDirection.xyz = lightDirection;
+   
+    // Attenuation
+    v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
+
+    // Output light direction.
+    v_vertexToPointLightDirection =  vertexToPointLightDirection;
+   
+    #if defined (SPECULAR)
+   
+    vec3 cameraDirection = normalize(v_cameraDirection);
+
+    #endif
+}
+
+#endif

+ 63 - 0
gameplay/res/shaders/lib/lighting-spot.frag

@@ -0,0 +1,63 @@
+float lerpstep( float lower, float upper, float s)
+{
+    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
+}
+
+#if defined(BUMPED)
+
+vec3 getLitPixel()
+{
+    // Fetch normals from the normal map.
+    vec3 normalVector = normalize(texture2D(u_normalmapTexture, v_texCoord).rgb * 2.0 - 1.0);
+    vec3 spotLightDirection = normalize(v_spotLightDirection);
+    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
+    
+    // "-lightDirection" because light direction points in opposite direction to to spot direction.
+    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
+    
+    // Intensity of spot depends on the spot light attenuation and the part of the cone vertexToSpotLightDirection points to (inner or outer).
+    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
+    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
+
+    #if defined(SPECULAR)
+    
+    vec3 cameraDirection = normalize(v_cameraDirection);
+    return computeLighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation, cameraDirection);
+    
+    #else
+    
+    return computeLighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
+    
+    #endif
+}
+
+#else
+
+vec3 getLitPixel()
+{
+    // Normalize the vectors.
+    vec3 normalVector = normalize(v_normalVector);
+    vec3 spotLightDirection = normalize(u_spotLightDirection); 
+    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
+
+    // "-lightDirection" is used because light direction points in opposite direction to to spot direction.
+    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
+    
+    // Intensity of spot depends on the spot light attenuation and the 
+    // part of the cone vertexToSpotLightDirection points to (inner or outer).
+    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
+    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
+
+    #if defined(SPECULAR)
+    
+    vec3 cameraDirection = normalize(v_cameraDirection);
+    return computeLighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation, cameraDirection);
+    
+    #else
+    
+    return computeLighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
+    
+    #endif
+}
+
+#endif

+ 54 - 0
gameplay/res/shaders/lib/lighting-spot.vert

@@ -0,0 +1,54 @@
+#if defined(BUMPED)
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
+
+    // Transform spot light direction to tangent space.
+    v_spotLightDirection = tangentSpaceTransformMatrix * u_spotLightDirection;
+
+    // Compute the light direction with light position and the vertex position.
+    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
+    
+    // Transform current light direction to tangent space.
+    lightDirection = tangentSpaceTransformMatrix * lightDirection;
+    
+    // Attenuation
+    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
+
+    // Output light direction.
+    v_vertexToSpotLightDirection = lightDirection;
+    
+    #if defined(SPECULAR)
+    
+    // Compute camera direction and transform it to tangent space.
+    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
+    
+    #endif
+}
+
+#else
+
+void applyLight(vec4 position)
+{
+    // World space position.
+    vec4 positionWorldViewSpace = u_worldViewMatrix * position;
+
+    // Compute the light direction with light position and the vertex position.
+    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
+
+    // Attenuation
+    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
+
+    // Output light direction.
+    v_vertexToSpotLightDirection = lightDirection;
+    
+    #if defined(SPECULAR)
+    
+    // Compute camera direction and transform it to tangent space.
+    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
+    
+    #endif
+}
+
+#endif

+ 46 - 0
gameplay/res/shaders/lib/lighting.frag

@@ -0,0 +1,46 @@
+vec4 _baseColor;
+vec3 _ambientColor;
+vec3 _diffuseColor;
+
+#if defined(SPECULAR)
+
+vec3 _specularColor;
+
+vec3 computeLighting(vec3 normalVector, vec3 lightDirection, float attenuation, vec3 cameraDirection)
+{
+    // Ambient
+    _ambientColor = _baseColor.rgb * u_ambientColor;
+
+    // Diffuse
+    float ddot = dot(normalVector, lightDirection);
+    float diffuseIntensity = attenuation * ddot;
+    diffuseIntensity = max(0.0, diffuseIntensity);
+    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
+
+    // Specular
+    vec3 halfVector = normalize(lightDirection + cameraDirection);
+    float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
+    specularIntensity = max(0.0, specularIntensity);
+    _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
+	
+	return _ambientColor + _diffuseColor + _specularColor;
+}
+
+#else
+
+vec3 computeLighting(vec3 normalVector, vec3 lightDirection, float attenuation)
+{
+    // Ambient
+    _ambientColor = _baseColor.rgb * u_ambientColor;
+
+    // Diffuse
+	float ddot = dot(normalVector, lightDirection);
+    float diffuseIntensity = attenuation * ddot;
+    diffuseIntensity = max(0.0, diffuseIntensity);
+    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
+	
+	return _ambientColor + _diffuseColor;
+}
+
+#endif
+

+ 0 - 175
gameplay/res/shaders/parallax-specular.fsh

@@ -1,175 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color.
-uniform vec3 u_ambientColor;                    // Ambient color.
-uniform float u_specularExponent;               // Specular exponent or shininess property.
-uniform sampler2D u_diffuseTexture;             // Diffuse texture.
-uniform sampler2D u_bumpMapTexture;             // Height map texture
-uniform sampler2D u_normalMapTexture;           // Normal map texture.
-uniform float u_parallaxHeight;                 // Parallax height
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec2 v_texCoord;                        // Texture Coordinate.
-varying vec3 v_cameraDirection;                 // Direction the camera is looking at in tangent space.
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-vec3 _specularColor;                            // Specular color
-
-void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-
-    // Specular
-    vec3 halfVector = normalize(cameraDirection + lightDirection);
-    float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
-    specularIntensity = max(0.0, specularIntensity);
-    _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec3 v_vertexToPointLightDirection;     // Light direction w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;          // Attenuation of point light.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection);
-    
-    float pointLightAttenuation = clamp(v_pointLightAttenuation, 0.0, 1.0);
-
-    // Get the height in the bumpmap texture.
-    float height = texture2D(u_bumpMapTexture, v_texCoord).r;
-
-    // Compute offset within the range (-parallax height to +parallax height).
-    float offset = u_parallaxHeight * (2.0 * height - 1.0);
-    vec2 parallaxTexCoord = v_texCoord + (cameraDirection.xy * offset);
-
-    // Compute offset again with the new texture coordinates to get better precision.
-    // Find out the mean height.
-    height += texture2D(u_bumpMapTexture, parallaxTexCoord).r;
-    offset = u_parallaxHeight * (height - 1.0);
-    parallaxTexCoord = v_texCoord + ( cameraDirection.xy * offset);
-
-    // Fetch normals from the normal map with the modified texture coordinates.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, parallaxTexCoord).xyz * 2.0 - 1.0);
-
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, parallaxTexCoord);
-    
-    lighting(normalVector, cameraDirection, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_spotLightDirection;              // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;      // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 spotLightDirection = normalize(v_spotLightDirection);
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-    
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    // Get the height in the bumpmap texture.
-    float height = texture2D(u_bumpMapTexture, v_texCoord).r;
-
-    // Compute offset within the range (-parallax height to +parallax height).
-    float offset = u_parallaxHeight * (2.0 * height - 1.0);
-    vec2 parallaxTexCoord = v_texCoord + (cameraDirection.xy * offset);
-
-    // Compute offset again with the new texture coordinates to get better precision.
-    // Find out the mean height.
-    height += texture2D(u_bumpMapTexture, parallaxTexCoord).r;
-    offset = u_parallaxHeight * (height - 1.0);
-    parallaxTexCoord = v_texCoord + ( cameraDirection.xy * offset);
-
-    // Fetch normals from the normal map with the modified texture coordinates.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, parallaxTexCoord).xyz * 2.0 - 1.0);
-
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, parallaxTexCoord);
-
-    lighting(normalVector, cameraDirection, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-varying vec3 v_lightDirection;                  // Direction of light in tangent space.
-
-void applyLight()
-{
-    // Normalize vectors.
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(v_lightDirection);
-
-    // Get the height in the bumpmap texture.
-    float height = texture2D(u_bumpMapTexture, v_texCoord).r;
-
-    // Compute offset within the range (-parallax height to +parallax height).
-    float offset = u_parallaxHeight * (2.0 * height - 1.0);
-    vec2 parallaxTexCoord = v_texCoord + (cameraDirection.xy * offset);
-
-    // Compute offset again with the new texture coordinates to get better precision.
-    // Find out the mean height.
-    height += texture2D(u_bumpMapTexture, parallaxTexCoord).r;
-    offset = u_parallaxHeight * (height - 1.0);
-    parallaxTexCoord = v_texCoord + ( cameraDirection.xy * offset);
-
-    // Fetch normals from the normal map with the modified texture coordinates.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, parallaxTexCoord).xyz * 2.0 - 1.0);
-
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, parallaxTexCoord);
-
-    lighting(normalVector, cameraDirection, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 118
gameplay/res/shaders/parallax-specular.vsh

@@ -1,118 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewMatrix;                     // Matrix to transform a position to view space.
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-uniform vec3 u_cameraPosition;                      // Position of the camera.
-
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                          // Vertex Texture Coordinate (u, v)
-attribute vec3 a_tangent;                           // Vertex Tangent (x, y, z)
-attribute vec3 a_binormal;                          // Vertex Binormal (actually Bi-tangent) (x, y, z)
-
-// Outputs
-varying vec2 v_texCoord;                            // Texture Coordinate (u,v)
-varying vec3 v_cameraDirection;                     // Direction the camera is looking at in tangent space.
-
-#if defined(POINT_LIGHT)
-
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRangeInverse;             // Inverse of light range 
-varying vec3 v_vertexToPointLightDirection;         // Direction of point light w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;              // Attenuation of point light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-    
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    vec3 vertexToPointLightDirection = tangentSpaceTransformMatrix * lightDirection;
-
-    // Attenuation
-    v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-uniform vec3 u_spotLightDirection;                  // Direction
-varying vec3 v_spotLightDirection;                  // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;          // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-
-    // Transform spot light direction to tangent space.
-    v_spotLightDirection = tangentSpaceTransformMatrix * u_spotLightDirection;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    lightDirection = tangentSpaceTransformMatrix * lightDirection;
-    
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-uniform vec3 u_lightDirection;                      // Direction
-varying vec3 v_lightDirection;                      // Direction of light in tangent space.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-    
-    // Transform light direction to tangent space.
-    v_lightDirection = tangentSpaceTransformMatrix * u_lightDirection;
-}
-
-#endif
-
-void main()
-{
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * a_position;
-
-    // Transform the normal, tangent and binormals to  view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    vec3 tangentVector  = normalize(inverseTransposeWorldViewMatrix * a_tangent);
-    vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * a_normal);
-    vec3 binormalVector = normalize(inverseTransposeWorldViewMatrix * a_binormal);
-
-    // Create a transform to convert a vector to tangent space.
-    mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x,
-                                            tangentVector.y, binormalVector.y, normalVector.y,
-                                            tangentVector.z, binormalVector.z, normalVector.z);
-    // Apply light.
-    applyLight(tangentSpaceTransformMatrix);
-
-    // Pass on the texture coordinates to Fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 0 - 167
gameplay/res/shaders/parallax.fsh

@@ -1,167 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_lightColor;                      // Light color.
-uniform vec3 u_ambientColor;                    // Ambient color.
-uniform sampler2D u_diffuseTexture;             // Diffuse texture.
-uniform sampler2D u_bumpMapTexture;             // Height map texture
-uniform sampler2D u_normalMapTexture;           // Normal map texture.
-uniform float u_parallaxHeight;                 // Parallax height
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;                    // Global alpha value
-#endif
-
-// Inputs
-varying vec2 v_texCoord;                        // Texture Coordinate.
-varying vec3 v_cameraDirection;                 // Direction the camera is looking at in tangent space.
-
-// Global variables
-vec4 _baseColor;                                // Base color
-vec3 _ambientColor;                             // Ambient Color
-vec3 _diffuseColor;                             // Diffuse Color
-
-void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
-{
-    // Ambient
-    _ambientColor = _baseColor.rgb * u_ambientColor;
-
-    // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
-    diffuseIntensity = max(0.0, diffuseIntensity);
-    _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
-}
-
-#if defined(POINT_LIGHT)
-
-varying vec3 v_vertexToPointLightDirection;     // Light direction w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;          // Attenuation of point light.
-
-void applyLight()
-{
-    // Normalize the vectors.
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 vertexToPointLightDirection = normalize(v_vertexToPointLightDirection);
-    
-    float pointLightAttenuation = clamp(v_pointLightAttenuation, 0.0, 1.0);
-
-    // Get the height in the bumpmap texture.
-    float height = texture2D(u_bumpMapTexture, v_texCoord).r;
-
-    // Compute offset within the range (-parallax height to +parallax height).
-    float offset = u_parallaxHeight * (2.0 * height - 1.0);
-    vec2 parallaxTexCoord = v_texCoord + (cameraDirection.xy * offset);
-
-    // Compute offset again with the new texture coordinates to get better precision.
-    // Find out the mean height.
-    height += texture2D(u_bumpMapTexture, parallaxTexCoord).r;
-    offset = u_parallaxHeight * (height - 1.0);
-    parallaxTexCoord = v_texCoord + ( cameraDirection.xy * offset);
-
-    // Fetch normals from the normal map with the modified texture coordinates.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, parallaxTexCoord).xyz * 2.0 - 1.0);
-
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, parallaxTexCoord);
-    
-    lighting(normalVector, vertexToPointLightDirection, pointLightAttenuation);
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform float u_spotLightInnerAngleCos;         // The bright spot [0.0 - 1.0]
-uniform float u_spotLightOuterAngleCos;         // The soft outer part [0.0 - 1.0]
-varying vec3 v_spotLightDirection;              // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;      // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;           // Attenuation of spot light.
-
-float lerpstep( float lower, float upper, float s)
-{
-    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
-}
-
-void applyLight()
-{
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 spotLightDirection = normalize(v_spotLightDirection);
-    vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection);
-
-    // "-lightDirection" because light direction points in opposite direction to
-    // to spot direction.
-    // Calculate spot light effect.
-    float spotCurrentAngleCos = max(0.0, dot(spotLightDirection, -vertexToSpotLightDirection));
-    
-    // Intensity of spot depends on the spot light attenuation and the 
-    // part of the cone vertexToSpotLightDirection points to (inner or outer).
-    float spotLightAttenuation = clamp(v_spotLightAttenuation, 0.0, 1.0);
-    spotLightAttenuation *= lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
-
-    // Get the height in the bumpmap texture.
-    float height = texture2D(u_bumpMapTexture, v_texCoord).r;
-
-    // Compute offset within the range (-parallax height to +parallax height).
-    float offset = u_parallaxHeight * (2.0 * height - 1.0);
-    vec2 parallaxTexCoord = v_texCoord + (cameraDirection.xy * offset);
-
-    // Compute offset again with the new texture coordinates to get better precision.
-    // Find out the mean height.
-    height += texture2D(u_bumpMapTexture, parallaxTexCoord).r;
-    offset = u_parallaxHeight * (height - 1.0);
-    parallaxTexCoord = v_texCoord + ( cameraDirection.xy * offset);
-
-    // Fetch normals from the normal map with the modified texture coordinates.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, parallaxTexCoord).xyz * 2.0 - 1.0);
-
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, parallaxTexCoord);
-
-    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
-}
-
-#else
-
-varying vec3 v_lightDirection;                      // Direction of light in tangent space.
-
-void applyLight()
-{
-    // Normalize vectors.
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(v_lightDirection);
-
-    // Get the height in the bumpmap texture.
-    float height = texture2D(u_bumpMapTexture, v_texCoord).r;
-
-    // Compute offset within the range (-parallax height to +parallax height).
-    float offset = u_parallaxHeight * (2.0 * height - 1.0);
-    vec2 parallaxTexCoord = v_texCoord + (cameraDirection.xy * offset);
-
-    // Compute offset again with the new texture coordinates to get better precision.
-    // Find out the mean height.
-    height += texture2D(u_bumpMapTexture, parallaxTexCoord).r;
-    offset = u_parallaxHeight * (height - 1.0);
-    parallaxTexCoord = v_texCoord + ( cameraDirection.xy * offset);
-
-    // Fetch normals from the normal map with the modified texture coordinates.
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, parallaxTexCoord).xyz * 2.0 - 1.0);
-
-    // Fetch diffuse color from texture.
-    _baseColor = texture2D(u_diffuseTexture, parallaxTexCoord);
-
-    lighting(normalVector, -lightDirection, 1.0);
-}
-#endif
-
-void main()
-{
-    // Apply light
-    applyLight();
-
-    // Light the pixel
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = _ambientColor + _diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 118
gameplay/res/shaders/parallax.vsh

@@ -1,118 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewMatrix;                     // Matrix to transform a position to view space.
-uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-uniform vec3 u_cameraPosition;                      // Position of the camera.
-
-
-// Inputs
-attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                          // Vertex Texture Coordinate (u, v)
-attribute vec3 a_tangent;                           // Vertex Tangent (x, y, z)
-attribute vec3 a_binormal;                          // Vertex Binormal (actually Bi-tangent) (x, y, z)
-
-// Outputs
-varying vec2 v_texCoord;                            // Texture Coordinate (u,v)
-varying vec3 v_cameraDirection;                     // Direction the camera is looking at in tangent space.
-
-#if defined(POINT_LIGHT)
-
-uniform vec3 u_pointLightPosition;                  // Position
-uniform float u_pointLightRangeInverse;             // Inverse of light range 
-varying vec3 v_vertexToPointLightDirection;         // Direction of point light w.r.t current vertex in tangent space.
-varying float v_pointLightAttenuation;              // Attenuation of point light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-    
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    vec3 vertexToPointLightDirection = tangentSpaceTransformMatrix * lightDirection;
-
-    // Attenuation
-    v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
-}
-
-#elif defined(SPOT_LIGHT)
-
-uniform vec3 u_spotLightPosition;                   // Position
-uniform float u_spotLightRangeInverse;              // Inverse of light range.
-uniform vec3 u_spotLightDirection;                  // Direction
-varying vec3 v_spotLightDirection;                  // Direction of spot light in tangent space.
-varying vec3 v_vertexToSpotLightDirection;          // Direction of the spot light w.r.t current vertex in tangent space.
-varying float v_spotLightAttenuation;               // Attenuation of spot light.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-
-    // Transform spot light direction to tangent space.
-    v_spotLightDirection = tangentSpaceTransformMatrix * u_spotLightDirection;
-
-    // Compute the light direction with light position and the vertex position.
-    vec3 lightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
-    
-    // Transform current light direction to tangent space.
-    lightDirection = tangentSpaceTransformMatrix * lightDirection;
-    
-    // Attenuation
-    v_spotLightAttenuation = 1.0 - dot(lightDirection * u_spotLightRangeInverse, lightDirection * u_spotLightRangeInverse);
-
-    // Output light direction.
-    v_vertexToSpotLightDirection = lightDirection;
-}
-
-#else
-
-uniform vec3 u_lightDirection;                      // Direction
-varying vec3 v_lightDirection;                      // Direction of light in tangent space.
-
-void applyLight(mat3 tangentSpaceTransformMatrix)
-{
-    vec4 positionWorldViewSpace = u_worldViewMatrix * a_position;
-    
-    // Compute camera direction and transform it to tangent space.
-    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldViewSpace.xyz);
-    
-    // Transform light direction to tangent space.
-    v_lightDirection = tangentSpaceTransformMatrix * u_lightDirection;
-}
-
-#endif
-
-void main()
-{
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * a_position;
-
-    // Transform the normal, tangent and binormals to  view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    vec3 tangentVector  = normalize(inverseTransposeWorldViewMatrix * a_tangent);
-    vec3 normalVector = inverseTransposeWorldViewMatrix * a_normal;
-    vec3 binormalVector = inverseTransposeWorldViewMatrix * a_binormal;
-
-    // Create a transform to convert a vector to tangent space.
-    mat3 tangentSpaceTransformMatrix = mat3(tangentVector.x, binormalVector.x, normalVector.x,
-                                            tangentVector.y, binormalVector.y, normalVector.y,
-                                            tangentVector.z, binormalVector.z, normalVector.z);
-    // Apply light.
-    applyLight(tangentSpaceTransformMatrix);
-
-    // Pass on the texture coordinates to Fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 0 - 18
gameplay/res/shaders/solid.fsh

@@ -1,18 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec4 u_diffuseColor;        // Diffuse color
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;        // Global alpha value
-#endif
-
-void main()
-{
-    gl_FragColor = u_diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 0 - 10
gameplay/res/shaders/solid.vsh

@@ -1,10 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;        // Matrix to transform a position to clip space.
-
-// Inputs
-attribute vec4 a_position;                        // Vertex Position (x, y, z, w)
-
-void main()
-{
-    gl_Position = u_worldViewProjectionMatrix *  a_position;
-}

+ 36 - 0
gameplay/res/shaders/textured-unlit.frag

@@ -0,0 +1,36 @@
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+// Uniforms
+uniform sampler2D u_diffuseTexture;     	// Diffuse texture
+#if defined(TEXTURE_LIGHT)
+uniform sampler2D u_lightmapTexture;     	// Lightmap texture
+#endif
+#if defined(MODULATE_COLOR)
+uniform vec4 u_modulateColor;               // Modulation color
+#endif
+#if defined(MODULATE_ALPHA)
+uniform float u_modulateAlpha;              // Modulation alpha
+#endif
+
+// Inputs
+varying vec2 v_texCoord;                	// Texture coordinate(u, v)
+
+// Fragment Program
+void main()
+{
+    // Sample the texture for the color
+    gl_FragColor = texture2D(u_diffuseTexture, v_texCoord);
+	#if defined(TEXTURE_LIGHT)
+	vec4 lightColor = texture2D(u_lightTexture, v_texCoord);
+	gl_FragColor.a *= lightColor.a;
+	#endif
+	// Global color modulation
+	#if defined(MODULATE_COLOR)
+	gl_FragColor *= u_modulateColor;
+	#endif
+	#if defined(MODULATE_ALPHA)
+    gl_FragColor.a *= u_modulateAlpha;
+    #endif
+}

+ 48 - 0
gameplay/res/shaders/textured-unlit.vert

@@ -0,0 +1,48 @@
+// Inputs
+attribute vec4 a_position;									// Vertex Position							(x, y, z, w)
+attribute vec2 a_texCoord;									// Vertex Texture Coordinate				(u, v)
+#if defined(SKINNING)
+attribute vec4 a_blendWeights;								// Vertex blend weight, up to 4				(0, 1, 2, 3) 
+attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette	(0, 1, 2, 3)
+#endif
+
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
+#if defined(SKINNING)
+uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
+#endif
+#if defined(TEXTURE_REPEAT)
+uniform vec2 u_textureRepeat;								// Texture repeat for tiling
+#endif
+#if defined(TEXTURE_OFFSET)
+uniform vec2 u_textureOffset;								// Texture offset
+#endif
+
+// Outputs
+varying vec2 v_texCoord;									// Texture Coordinate
+
+// Vertex attribute accessors
+#if defined(SKINNING)
+#include "lib/attributes-skinning.vert"
+#else
+#include "lib/attributes.vert" 
+#endif
+
+// Vertex Program
+void main()
+{
+    // Get the vertex position
+    vec4 position = getPosition();
+
+    // Transform position to clip space.
+    gl_Position = u_worldViewProjectionMatrix * position;
+
+    // Texture transformation.
+    v_texCoord = a_texCoord;
+    #if defined(TEXTURE_REPEAT)
+    v_texCoord *= u_textureRepeat;
+    #endif
+    #if defined(TEXTURE_OFFSET)
+    v_texCoord += u_textureOffset;
+    #endif
+}

+ 67 - 0
gameplay/res/shaders/textured.frag

@@ -0,0 +1,67 @@
+#define LIGHTING
+
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+// Inputs
+varying vec3 v_normalVector;                    // Normal vector in view space
+varying vec2 v_texCoord;                        // Texture coordinate
+#if defined(POINT_LIGHT)
+varying vec3 v_vertexToPointLightDirection;		// Light direction w.r.t current vertex in tangent space.
+varying float v_pointLightAttenuation;			// Attenuation of point light.
+#elif defined(SPOT_LIGHT)
+varying vec3 v_spotLightDirection;				// Direction of spot light in tangent space.
+varying vec3 v_vertexToSpotLightDirection;		// Direction of the spot light w.r.t current vertex in tangent space.
+varying float v_spotLightAttenuation;			// Attenuation of spot light.
+#else
+varying vec3 v_lightDirection;					// Direction of light in tangent space.
+#endif
+#if defined(SPECULAR)
+varying vec3 v_cameraDirection;                 // Camera direction
+#endif
+
+// Uniforms
+uniform sampler2D u_diffuseTexture;             // Diffuse map texture
+uniform vec3 u_ambientColor;                    // Ambient color
+uniform vec3 u_lightColor;                      // Light color
+uniform vec3 u_lightDirection;					// Light direction
+
+#if defined(SPECULAR)
+uniform float u_specularExponent;				// Specular exponent
+#endif
+#if defined(MODULATE_COLOR)
+uniform vec4 u_modulateColor;               	// Modulation color
+#endif
+#if defined(MODULATE_ALPHA)
+uniform float u_modulateAlpha;              	// Modulation alpha
+#endif
+#include "/lib/lighting.frag"
+#if defined(POINT_LIGHT)
+#include "lib/lighting-point.frag"
+#elif defined(SPOT_LIGHT)
+uniform float u_spotLightInnerAngleCos;			// The bright spot [0.0 - 1.0]
+uniform float u_spotLightOuterAngleCos;			// The soft outer part [0.0 - 1.0]
+#include "lib/lighting-spot.frag"
+#else
+#include "lib/lighting-directional.frag"
+#endif
+
+// Fragment Program
+void main()
+{
+    // Sample the diffuse texture for base color
+    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
+
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = getLitPixel();
+	
+	// Global color modulation
+	#if defined(MODULATE_COLOR)
+	gl_FragColor *= u_modulateColor;
+	#endif
+	#if defined(MODULATE_ALPHA)
+    gl_FragColor.a *= u_modulateAlpha;
+    #endif
+}

+ 0 - 22
gameplay/res/shaders/textured.fsh

@@ -1,22 +0,0 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform sampler2D u_diffuseTexture;     // Diffuse texture
-uniform vec4 u_diffuseColor;            // Diffuse color/tint
-#if defined(GLOBAL_ALPHA)
-uniform float u_globalAlpha;            // Global alpha value
-#endif
-
-// Inputs
-varying vec2 v_texCoord;                // Texture coordinate (u, v).
-
-void main()
-{
-    gl_FragColor = texture2D(u_diffuseTexture, v_texCoord) * u_diffuseColor;
-
-#if defined(GLOBAL_ALPHA)
-    gl_FragColor.a *= u_globalAlpha;
-#endif
-}

+ 87 - 0
gameplay/res/shaders/textured.vert

@@ -0,0 +1,87 @@
+#define LIGHTING
+
+// Inputs
+attribute vec4 a_position;									// Vertex position							(x, y, z, w)
+attribute vec3 a_normal;									// Vertex normal							(x, y, z)
+attribute vec2 a_texCoord;									// Vertex texture coordinate				(u, v)
+#if defined(SKINNING)
+attribute vec4 a_blendWeights;								// Vertex blend weight, up to 4				(0, 1, 2, 3) 
+attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette	(0, 1, 2, 3)
+#endif
+
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
+uniform mat4 u_inverseTransposeWorldViewMatrix;				// Matrix to transform a normal to view space
+#if defined(SKINNING)
+uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
+#endif
+#if defined(SPECULAR)
+uniform mat4 u_worldViewMatrix;								// Matrix to tranform a position to view space
+uniform vec3 u_cameraPosition;                 				// Position of the camera in view space
+#endif
+#if defined(TEXTURE_REPEAT)
+uniform vec2 u_textureRepeat;								// Texture repeat for tiling
+#endif
+#if defined(TEXTURE_OFFSET)
+uniform vec2 u_textureOffset;								// Texture offset
+#endif
+#if defined(POINT_LIGHT)
+uniform vec3 u_pointLightPosition;							// Position of light
+uniform float u_pointLightRangeInverse;						// Inverse of light range 
+#elif defined(SPOT_LIGHT)
+uniform vec3 u_spotLightPosition;							// Position of light
+uniform float u_spotLightRangeInverse;						// Inverse of light range
+#else
+#endif
+
+// Outputs
+varying vec3 v_normalVector;								// Normal vector in view space
+varying vec2 v_texCoord;									// Texture coordinate
+#if defined(SPECULAR)
+varying vec3 v_cameraDirection;								// Direction the camera is looking at in tangent space
+#endif
+#if defined(POINT_LIGHT)
+varying vec3 v_vertexToPointLightDirection;					// Direction of point light w.r.t current vertex in tangent space
+varying float v_pointLightAttenuation;						// Attenuation of point light
+#include "lib/lighting-point.vert"
+#elif defined(SPOT_LIGHT)
+varying vec3 v_vertexToSpotLightDirection;					// Direction of the spot light w.r.t current vertex in tangent space
+varying float v_spotLightAttenuation;						// Attenuation of spot light
+#include "lib/lighting-spot.vert"
+#else
+#include "lib/lighting-directional.vert"
+#endif
+
+// Vertex attribute accessors
+#if defined(SKINNING)
+#include "lib/attributes-skinning.vert"
+#else
+#include "lib/attributes.vert" 
+#endif
+
+// Vertex Program
+void main()
+{
+    // Get the position and normal from attribute accessors
+    vec4 position = getPosition();
+    vec3 normal = getNormal();
+
+    // Transform position to clip space.
+    gl_Position = u_worldViewProjectionMatrix * position;
+
+    // Transform normal to view space.
+    mat3 normalMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    v_normalVector = normalMatrix * normal;
+
+    // Apply light.
+    applyLight(position);
+    
+    // Texture transformation
+    v_texCoord = a_texCoord;
+    #if defined(TEXTURE_REPEAT)
+    v_texCoord *= u_textureRepeat;
+    #endif
+    #if defined(TEXTURE_OFFSET)
+    v_texCoord += u_textureOffset;
+    #endif
+}

+ 0 - 78
gameplay/res/shaders/textured.vsh

@@ -1,78 +0,0 @@
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;       // Matrix to transform a position to clip space.
-
-// Inputs
-attribute vec4 a_position;                      // Vertex Position (x, y, z, w).
-attribute vec2 a_texCoord;                      // Vertex Texture Coordinate (u, v).
-
-// Outputs
-varying vec2 v_texCoord;                        // Texture coordinate (u, v).
-
-#if defined(SKINNING)
-
-attribute vec4 a_blendWeights;
-attribute vec4 a_blendIndices;
-
-// 32 4x3 matrices as an array of floats
-uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];
-
-// Common vectors.
-vec4 _skinnedPosition;
-
-void skinPosition(float blendWeight, int matrixIndex)
-{
-    vec4 tmp;
-
-    tmp.x = dot(a_position, u_matrixPalette[matrixIndex]);
-    tmp.y = dot(a_position, u_matrixPalette[matrixIndex + 1]);
-    tmp.z = dot(a_position, u_matrixPalette[matrixIndex + 2]);
-    tmp.w = a_position.w;
-
-    _skinnedPosition += blendWeight * tmp;
-}
-
-vec4 getPosition()
-{
-    _skinnedPosition = vec4(0.0);
-
-    // Transform position to view space using 
-    // matrix palette with four matrices used to transform a vertex.
-
-    float blendWeight = a_blendWeights[0];
-    int matrixIndex = int (a_blendIndices[0]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[1];
-    matrixIndex = int(a_blendIndices[1]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[2];
-    matrixIndex = int(a_blendIndices[2]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[3]) * 3;
-    skinPosition(blendWeight, matrixIndex);
-
-    return _skinnedPosition;    
-}
-
-#else
-
-vec4 getPosition()
-{
-    return a_position;    
-}
-
-#endif
-
-void main()
-{
-    vec4 position = getPosition();
-
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * position;
-
-    // Pass on texture coordinate to fragment shader.
-    v_texCoord = a_texCoord;
-}

+ 33 - 46
gameplay/src/Bundle.cpp

@@ -601,7 +601,7 @@ Node* Bundle::loadNode(const char* id, Scene* sceneContext, Node* nodeContext)
         if (node)
             node->addRef();
     }
-    else if (nodeContext)
+    if (node == NULL && nodeContext)
     {
         node = nodeContext->findNode(id, true);
         if (node)
@@ -675,6 +675,21 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
     GP_ASSERT(id);
     GP_ASSERT(_file);
 
+    // If we are tracking nodes and it's not in the set yet, add it.
+    if (_trackedNodes)
+    {
+        std::map<std::string, Node*>::iterator iter = _trackedNodes->find(id);
+        if (iter != _trackedNodes->end())
+        {
+            // Skip over this node since we previously read it
+            if (!skipNode())
+                return NULL;
+
+            iter->second->addRef();
+            return iter->second;
+        }
+    }
+
     // Read node type.
     unsigned int nodeType;
     if (!read(&nodeType))
@@ -696,43 +711,10 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
         return NULL;
     }
 
-    // If we are tracking nodes and it's not in the set yet, add it.
     if (_trackedNodes)
     {
-        std::map<std::string, Node*>::iterator iter = _trackedNodes->find(id);
-        if (iter != _trackedNodes->end())
-        {
-            SAFE_RELEASE(node);
-
-            // Skip over the node's transform and parent ID.
-            if (fseek(_file, sizeof(float) * 16, SEEK_CUR) != 0)
-            {
-                GP_ERROR("Failed to skip over node transform for node '%s'.", id);
-                return NULL;
-            }
-            readString(_file);
-
-            // Skip over the node's children.
-            unsigned int childrenCount;
-            if (!read(&childrenCount))
-            {
-                GP_ERROR("Failed to skip over node's children count for node '%s'.", id);
-                return NULL;
-            }
-            else if (childrenCount > 0)
-            {
-                for (unsigned int i = 0; i < childrenCount; i++)
-                {
-                    if (!skipNode())
-                        return NULL;
-                }
-            }
-
-            iter->second->addRef();
-            return iter->second;
-        }
-        else
-            _trackedNodes->insert(std::make_pair(id, node));
+        // Add the new node to the list of tracked nodes
+        _trackedNodes->insert(std::make_pair(id, node));
     }
 
     // If no loading context is set, set this node as the loading context.
@@ -751,7 +733,7 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
     }
     setTransform(transform, node);
 
-    // Skip over the parent ID.
+    // Skip the parent ID.
     readString(_file);
 
     // Read children.
@@ -771,23 +753,25 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
             // if we've already loaded this child node during this load session.
             Node* child = NULL;
             id = getIdFromOffset();
+            GP_ASSERT(id);
 
             if (sceneContext)
             {
                 child = sceneContext->findNode(id, true);
             }
-            else if (nodeContext)
+            if (child == NULL && nodeContext)
             {
                 child = nodeContext->findNode(id, true);
             }
-            
-            // If the child node wasn't already loaded, load it.
-            if (!child)
-                child = readNode(sceneContext, nodeContext);
+
+            // If the child was already loaded, skip it, otherwise read it
+            if (child)
+            {
+                skipNode();
+            }
             else
             {
-                // Otherwise, skip over its data in the file.
-                readNode(NULL, NULL);
+                child = readNode(sceneContext, nodeContext);
             }
 
             if (child)
@@ -1142,6 +1126,9 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
                 }
                 else
                 {
+                    // No parent currently set for this joint.
+                    // Lookup its parentID in case it references a node that was not yet loaded as part
+                    // of the mesh skin's joint list.
                     std::string nodeID = node->getId();
 
                     while (true)
@@ -1165,7 +1152,7 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
                         }
                         std::string parentID = readString(_file);
                         
-                        if (parentID.size() > 0)
+                        if (!parentID.empty())
                             nodeID = parentID;
                         else
                             break;
@@ -1180,7 +1167,7 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
 
             skinData->skin->setRootJoint(rootJoint);
 
-            // Release all the nodes that we loaded since the nodes are now owned by the mesh skin.
+            // Release all the nodes that we loaded since the nodes are now owned by the mesh skin/joints.
             for (unsigned int i = 0; i < loadedNodes.size(); i++)
             {
                 SAFE_RELEASE(loadedNodes[i]);

+ 54 - 6
gameplay/src/Button.cpp

@@ -5,11 +5,24 @@ namespace gameplay
 {
 
 Button::Button()
+    : _gamepadButtonIndex(NULL)
 {
 }
 
 Button::~Button()
 {
+    if (_gamepadButtonIndex)
+        SAFE_DELETE(_gamepadButtonIndex);
+}
+
+Button* Button::create(const char* id, Theme::Style* style)
+{
+    Button* button = new Button();
+
+    button->_id = id;
+    button->_style = style;
+
+    return button;
 }
 
 Button* Button::create(Theme::Style* style, Properties* properties)
@@ -23,21 +36,56 @@ Button* Button::create(Theme::Style* style, Properties* properties)
 bool Button::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     if (!isEnabled())
-    {
         return false;
-    }
 
     switch (evt)
     {
     case Touch::TOUCH_PRESS:
-        setState(Control::ACTIVE);
+        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
+        {
+            _contactIndex = (int) contactIndex;
+
+            setState(Control::ACTIVE);
+
+            notifyListeners(Listener::PRESS);
+
+            return _consumeInputEvents;
+        }
+        else
+        {
+            setState(Control::NORMAL);
+        }
         break;
+
     case Touch::TOUCH_RELEASE:
-        setState(Control::NORMAL);
+        _contactIndex = INVALID_CONTACT_INDEX;
+        notifyListeners(Listener::RELEASE);
+        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
+        {
+            setState(Control::FOCUS);
+
+            notifyListeners(Listener::CLICK);
+
+            return _consumeInputEvents;
+        }
+        else
+        {
+            setState(Control::NORMAL);
+        }
         break;
+
+    case Touch::TOUCH_MOVE:
+        return _consumeInputEvents;
     }
 
-    return Control::touchEvent(evt, x, y, contactIndex);
+    return false;
 }
 
-}
+const char* Button::getType() const
+{
+    return "button";
+}
+
+}

+ 21 - 1
gameplay/src/Button.h

@@ -32,6 +32,19 @@ namespace gameplay
 class Button : public Label
 {
     friend class Container;
+    friend class Gamepad;
+
+public:
+
+    /**
+     * Create a new button control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new button.
+     */
+    static Button* create(const char* id, Theme::Style* style);
 
 protected:
 
@@ -69,14 +82,21 @@ protected:
      */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
 private:
 
     /**
      * Constructor.
      */
     Button(const Button& copy);
+
+    int* _gamepadButtonIndex;
 };
 
 }
 
-#endif
+#endif

+ 17 - 0
gameplay/src/CheckBox.cpp

@@ -19,6 +19,18 @@ CheckBox::~CheckBox()
 
 }
 
+CheckBox* CheckBox::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    CheckBox* checkBox = new CheckBox();
+    if (id)
+        checkBox->_id = id;
+    checkBox->setStyle(style);
+
+    return checkBox;
+}
+
 CheckBox* CheckBox::create(Theme::Style* style, Properties* properties)
 {
     GP_ASSERT(properties);
@@ -159,4 +171,9 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
 }
 
+const char* CheckBox::getType() const
+{
+    return "checkBox";
+}
+
 }

+ 19 - 4
gameplay/src/CheckBox.h

@@ -37,6 +37,16 @@ class CheckBox : public Button
 
 public:
 
+    /**
+     * Create a new check box control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new check box.
+     */
+    static CheckBox* create(const char* id, Theme::Style* style);
+
     /**
      * Gets whether this checkbox is checked.
      *
@@ -66,6 +76,11 @@ public:
      */
     const Vector2& getImageSize() const;
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -130,7 +145,7 @@ protected:
      * @param clip The container position this control is relative to.
      */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
-
+
     /**
      * Whether this checkbox is currently checked.
      */
@@ -140,11 +155,11 @@ protected:
      * The size to draw the checkbox icon, if different from its size in the texture.
      */
     Vector2 _imageSize;
-
+
     /**
      * The Theme::ThemeImage to display for the checkbox.
      */
-    Theme::ThemeImage* _image;
+    Theme::ThemeImage* _image;
 
 private:
 
@@ -156,4 +171,4 @@ private:
 
 }
 
-#endif
+#endif

+ 86 - 29
gameplay/src/Container.cpp

@@ -31,7 +31,7 @@ Container::Container()
       _scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f),
       _scrollingRight(false), _scrollingDown(false),
       _scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
-      _scrollBarOpacityClip(NULL), _zIndexDefault(0), _totalWidth(0), _totalHeight(0)
+      _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0), _totalWidth(0), _totalHeight(0)
 {
 }
 
@@ -49,6 +49,17 @@ Container::~Container()
     SAFE_RELEASE(_layout);
 }
 
+Container* Container::create(const char* id, Theme::Style* style, Layout::Type layoutType)
+{
+    GP_ASSERT(style);
+
+    Container* container = Container::create(layoutType);
+    if (id)
+        container->_id = id;
+    container->_style = style;
+    return container;
+}
+
 Container* Container::create(Layout::Type type)
 {
     Layout* layout = NULL;
@@ -160,6 +171,15 @@ void Container::addControls(Theme* theme, Properties* properties)
             {
                 control->setZIndex(_zIndexDefault++);
             }
+
+            if (control->getFocusIndex() == -1)
+            {
+                control->setFocusIndex(_focusIndexDefault++);
+            }
+
+            int focusIndex = control->getFocusIndex();
+            if (focusIndex > _focusIndexMax)
+                _focusIndexMax = focusIndex;
         }
 
         // Get the next control.
@@ -251,7 +271,6 @@ Control* Container::getControl(const char* id) const
             }
         }
     }
-
     return NULL;
 }
 
@@ -313,6 +332,11 @@ Animation* Container::getAnimation(const char* id) const
     return NULL;
 }
 
+const char* Container::getType() const
+{
+    return "container";
+}
+
 void Container::update(const Control* container, const Vector2& offset)
 {
     // Update this container's viewport.
@@ -356,13 +380,10 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
     if (needsClear)
     {
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
-        GL_ASSERT( glClearColor(0, 0, 0, 0) );
         float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
-        GL_ASSERT( glScissor(_clearBounds.x, clearY,
-            _clearBounds.width, _clearBounds.height) );
-        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
+        GL_ASSERT( glScissor(_clearBounds.x, clearY, _clearBounds.width, _clearBounds.height) );
+        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
-
         needsClear = false;
         cleared = true;
     }
@@ -395,7 +416,8 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
 
         spriteBatch->begin();
 
-        if (_scrollBarBounds.height > 0)
+        if (_scrollBarBounds.height > 0 &&
+            ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL))
         {
             const Rectangle& topRegion = _scrollBarTopCap->getRegion();
             const Theme::UVs& topUVs = _scrollBarTopCap->getUVs();
@@ -414,9 +436,7 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
 
             clipRegion.width += verticalRegion.width;
 
-            Rectangle bounds(_viewportBounds.x + _viewportBounds.width - verticalRegion.width,
-                             _viewportBounds.y + _scrollBarBounds.y,
-                             topRegion.width, topRegion.height);
+            Rectangle bounds(_viewportBounds.x + _viewportBounds.width - verticalRegion.width, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
 
             bounds.y += topRegion.height;
@@ -428,7 +448,8 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, bottomUVs.u1, bottomUVs.v1, bottomUVs.u2, bottomUVs.v2, bottomColor, clipRegion);
         }
 
-        if (_scrollBarBounds.width > 0)
+        if (_scrollBarBounds.width > 0 &&
+            ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL))
         {
             const Rectangle& leftRegion = _scrollBarLeftCap->getRegion();
             const Theme::UVs& leftUVs = _scrollBarLeftCap->getUVs();
@@ -447,9 +468,7 @@ void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needs
 
             clipRegion.height += horizontalRegion.height;
         
-            Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x,
-                             _viewportBounds.y + _viewportBounds.height - horizontalRegion.height,
-                             leftRegion.width, leftRegion.height);
+            Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.y + _viewportBounds.height - horizontalRegion.height, leftRegion.width, leftRegion.height);
             spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
 
             bounds.x += leftRegion.width;
@@ -518,17 +537,40 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
             continue;
         }
 
-        if (control->isContainer() || control->getState() == Control::FOCUS)
+        if (control->getState() == Control::FOCUS)
         {
             if (control->keyEvent(evt, key))
+            {
                 return _consumeInputEvents;
+            }
+            else if (evt == Keyboard::KEY_CHAR && key == Keyboard::KEY_TAB)
+            {
+                // Shift focus to next control.
+                int focusIndex = control->getFocusIndex() + 1; // Index to search for.
+                if (focusIndex > _focusIndexMax)
+                {
+                    focusIndex = 0;
+                }
+                control->setState(Control::NORMAL);
+
+                std::vector<Control*>::const_iterator itt;
+                for (itt = _controls.begin(); itt < _controls.end(); itt++)
+                {
+                    Control* nextControl = *itt;
+                    if (nextControl->getFocusIndex() == focusIndex)
+                    {
+                        nextControl->setState(Control::FOCUS);
+                        return _consumeInputEvents;
+                    }
+                }
+            }
         }
     }
 
     return false;
 }
 
-bool Container::isContainer()
+bool Container::isContainer() const
 {
     return true;
 }
@@ -873,6 +915,12 @@ bool Container::mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelD
 
         case Mouse::MOUSE_WHEEL:
             _scrollPosition.y += (_totalHeight / 10.0f) * wheelDelta;
+            if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
+            {
+                _scrollBarOpacityClip->stop();
+                _scrollBarOpacityClip = NULL;
+            }
+            _scrollBarOpacity = 1.0f;
             return _consumeInputEvents;
     }
 
@@ -917,7 +965,9 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
             boundsY += offset->y;
         }
 
-        if (control->getState() != Control::NORMAL ||
+        Control::State currentState = control->getState();
+        if ((control->isContainer() && currentState == Control::FOCUS) ||
+            (currentState != Control::NORMAL && control->_contactIndex == data) ||
             ((evt == Touch::TOUCH_PRESS ||
               evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
               evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
@@ -941,25 +991,32 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         return (_consumeInputEvents | eventConsumed);
     }
 
-    switch (evt)
-    {
-    case Touch::TOUCH_PRESS:
-        setState(Control::FOCUS);
-        break;
-    case Touch::TOUCH_RELEASE:
-        setState(Control::NORMAL);
-        break;
-    }
-
     if (!eventConsumed && _scroll != SCROLL_NONE)
     {
-        if (mouse && mouseEventScroll((Mouse::MouseEvent)evt, x - xPos, y - yPos, data) ||
+        if ((mouse && mouseEventScroll((Mouse::MouseEvent)evt, x - xPos, y - yPos, data)) ||
             (!mouse && touchEventScroll((Touch::TouchEvent)evt, x - xPos, y - yPos, (unsigned int)data)))
         {
             _dirty = true;
+            eventConsumed = true;
         }
     }
 
+    switch (evt)
+    {
+    case Touch::TOUCH_PRESS:
+        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
+        {
+            setState(Control::FOCUS);
+        }
+        else
+        {
+            setState(Control::NORMAL);
+            return false;
+        }
+        break;
+    }
+
     return (_consumeInputEvents | eventConsumed);
 }
 

+ 20 - 3
gameplay/src/Container.h

@@ -45,7 +45,6 @@ namespace gameplay
  */
 class Container : public Control
 {
-    friend class DropDownList;
 
 public:
 
@@ -65,6 +64,17 @@ public:
         SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL
     };
 
+    /**
+     * Create a new container.
+     *
+     * @param id The container's ID.
+     * @param style The container's style.
+     * @param layoutType The container's layout type.
+     *
+     * @return The new container.
+     */
+    static Container* create(const char* id, Theme::Style* style, Layout::Type layoutType = Layout::LAYOUT_ABSOLUTE);
+
     /**
      * Get this container's layout.
      *
@@ -167,6 +177,11 @@ public:
      */
     Animation* getAnimation(const char* id = NULL) const;
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
     /**
      * @see AnimationTarget#getAnimationPropertyComponentCount
      */
@@ -274,10 +289,10 @@ protected:
 
     /**
      * Returns whether this control is a container.
-     * 
+     *
      * @return true if this is a container, false if not.
      */
-    bool isContainer();
+    bool isContainer() const;
 
     /**
      * Returns whether this container or any of its controls have been modified and require an update.
@@ -458,6 +473,8 @@ private:
 
     AnimationClip* _scrollBarOpacityClip;
     int _zIndexDefault;
+    int _focusIndexDefault;
+    int _focusIndexMax;
 
     float _totalWidth;
     float _totalHeight;

+ 63 - 18
gameplay/src/Control.cpp

@@ -6,8 +6,9 @@ namespace gameplay
 {
 
 Control::Control()
-    : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
-    _dirty(true), _consumeInputEvents(true), _listeners(NULL), _styleOverridden(false), _skin(NULL), _clearBounds(Rectangle::empty())
+    : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
+    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _listeners(NULL), _contactIndex(INVALID_CONTACT_INDEX),
+    _styleOverridden(false), _skin(NULL)
 {
 }
 
@@ -52,6 +53,15 @@ void Control::initialize(Theme::Style* style, Properties* properties)
         _zIndex = -1;
     }
 
+    if (properties->exists("focusIndex"))
+    {
+        _focusIndex = properties->getInt("focusIndex");
+    }
+    else
+    {
+        _focusIndex = -1;
+    }
+
     Vector2 position;
     Vector2 size;
     if (properties->exists("position"))
@@ -75,8 +85,6 @@ void Control::initialize(Theme::Style* style, Properties* properties)
     }
     setBounds(Rectangle(position.x, position.y, size.x, size.y));
 
-    _state = Control::getState(properties->getString("state"));
-
     const char* id = properties->getId();
     if (id)
         _id = id;
@@ -121,6 +129,11 @@ void Control::initialize(Theme::Style* style, Properties* properties)
     }
 }
 
+void initialize(const char* id, Theme::Style* style, const Vector2& position, const Vector2& size)
+{
+
+}
+
 const char* Control::getID() const
 {
     return _id.c_str();
@@ -631,6 +644,16 @@ void Control::setZIndex(int zIndex)
     }
 }
 
+int Control::getFocusIndex() const
+{
+    return _focusIndex;
+}
+
+void Control::setFocusIndex(int focusIndex)
+{
+    _focusIndex = focusIndex;
+}
+
 void Control::addListener(Control::Listener* listener, int eventFlags)
 {
     GP_ASSERT(listener);
@@ -684,26 +707,46 @@ void Control::addSpecificListener(Control::Listener* listener, Listener::EventTy
 bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     if (!isEnabled())
-    {
         return false;
-    }
 
     switch (evt)
     {
     case Touch::TOUCH_PRESS:
-        notifyListeners(Listener::PRESS);
-        return _consumeInputEvents;
+        // Controls that don't have an ACTIVE state go to the FOCUS state when pressed.
+        // (Other controls, such as buttons and sliders, become ACTIVE when pressed and go to the FOCUS state on release.)
+        // Labels are never any state other than NORMAL.
+        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
+        {
+            _contactIndex = (int) contactIndex;
+
+            notifyListeners(Listener::PRESS);
+
+            return _consumeInputEvents;
+        }
+        else
+        {
+            // If this control was in focus, it's not any more.
+            _state = NORMAL;
+            _contactIndex = INVALID_CONTACT_INDEX;
+        }
+        break;
             
     case Touch::TOUCH_RELEASE:
+
+        _contactIndex = INVALID_CONTACT_INDEX;
+
         // Always trigger Listener::RELEASE
         notifyListeners(Listener::RELEASE);
 
         // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
-        if (x > 0 && x <= _bounds.width &&
-            y > 0 && y <= _bounds.height)
+        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
         {
-            notifyListeners(Listener::CLICK);
+            // Leave this control in the FOCUS state.
+            notifyListeners(Listener::CLICK);
         }
+
         return _consumeInputEvents;
     }
 
@@ -934,10 +977,8 @@ void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsCl
     if (needsClear)
     {
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
-        GL_ASSERT( glClearColor(0, 0, 0, 0) );
-        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height,
-            _clearBounds.width, _clearBounds.height) );
-        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
+        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height, _clearBounds.width, _clearBounds.height) );
+        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
     }
 
@@ -955,7 +996,7 @@ bool Control::isDirty()
     return _dirty;
 }
 
-bool Control::isContainer()
+bool Control::isContainer() const
 {
     return false;
 }
@@ -999,6 +1040,11 @@ Theme::ThemeImage* Control::getImage(const char* id, State state)
     return imageList->getImage(id);
 }
 
+const char* Control::getType() const
+{
+    return "control";
+}
+
 // Implementation of AnimationHandler
 unsigned int Control::getAnimationPropertyComponentCount(int propertyId) const
 {
@@ -1085,8 +1131,7 @@ void Control::setAnimationPropertyValue(int propertyId, AnimationValue* value, f
         _dirty = true;
         break;
     case ANIMATE_OPACITY:
-        _dirty = true;
-    default:
+        _dirty = true;
         break;
     }
 }

+ 56 - 6
gameplay/src/Control.h

@@ -25,6 +25,7 @@ class Control : public Ref, public AnimationTarget
     friend class AbsoluteLayout;
     friend class VerticalLayout;
     friend class FlowLayout;
+    friend class Gamepad;
 
 public:
 
@@ -683,6 +684,20 @@ public:
      */
     void setZIndex(int zIndex);
 
+    /**
+     * Get this control's focus index.
+     *
+     * @return This control's focus index.
+     */
+    int getFocusIndex() const;
+
+    /**
+     * Set this control's focus index.
+     *
+     * @param focusIndex The new focus index.
+     */
+    void setFocusIndex(int focusIndex);
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -695,6 +710,13 @@ public:
      */
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
+    /**
+     * Gets the type of the Control and returns it as a string.
+     *
+     * @return The string of the Control type, all in lower-case.
+     */
+    virtual const char* getType() const;
+
     /**
      * @see AnimationTarget#getAnimationPropertyComponentCount
      */
@@ -712,6 +734,11 @@ public:
 
 protected:
 
+    /**
+     *  Constant value representing an unset or invalid contact index.
+     */
+    static const int INVALID_CONTACT_INDEX = -1;
+
     /**
      * Constructor.
      */
@@ -807,16 +834,29 @@ protected:
     virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight);
 
     /**
-     * Initialize properties common to STATE_ALL Controls.
+     * Initialize properties common to all Controls from a Properties object.
+     *
+     * @param style The style to apply to this control.
+     * @param properties The properties to set on this control.
      */
     virtual void initialize(Theme::Style* style, Properties* properties);
 
+    /**
+     * Initialize properties common to all Controls.
+     *
+     * @param id This control's ID.
+     * @param style The style to apply to this control.
+     * @param position This control's position.
+     * @param size This control's size.
+     */
+    //virtual void initialize(const char* id, Theme::Style* style, const Vector2& position, const Vector2& size);
+
     /**
      * Container and classes that extend it should implement this and return true.
      *
      * @return true if this object is of class Container, false otherwise.
      */
-    virtual bool isContainer();
+    virtual bool isContainer() const;
 
     /**
      * Returns whether this control has been modified and requires an update.
@@ -930,14 +970,14 @@ protected:
     bool _autoHeight;
     
     /**
-     * The Control's Theme::Style.
+     * Listeners map of EventType's to a list of Listeners.
      */
-    Theme::Style* _style;
+    std::map<Listener::EventType, std::list<Listener*>*>* _listeners;
     
     /**
-     * Listeners map of EventType's to a list of Listeners.
+     * The Control's Theme::Style.
      */
-    std::map<Listener::EventType, std::list<Listener*>*>* _listeners;
+    Theme::Style* _style;
 
     /**
      * The current opacity of the control.
@@ -949,6 +989,16 @@ protected:
      */
     int _zIndex;
 
+    /**
+     * The contact index assigned to this control.
+     */
+    int _contactIndex;
+
+    /**
+     * The focus order of the control.
+     */
+    int _focusIndex;
+
 private:
 
     /*

+ 142 - 10
gameplay/src/Effect.cpp

@@ -2,7 +2,7 @@
 #include "Effect.h"
 #include "FileSystem.h"
 
-#define OPENGL_ES_DEFINE  "#define OPENGL_ES"
+#define OPENGL_ES_DEFINE  "#define OPENGL_ES\n"
 
 namespace gameplay
 {
@@ -102,6 +102,111 @@ Effect* Effect::createFromSource(const char* vshSource, const char* fshSource, c
     return createFromSource(NULL, vshSource, NULL, fshSource, defines);
 }
 
+
+void replaceDefines(const char* defines, std::string& out)
+{
+    if (defines && strlen(defines) != 0)
+    {
+        out = defines;
+        unsigned int pos;
+        out.insert(0, "#define ");
+        while ((pos = out.find(';')) != std::string::npos)
+        {
+            out.replace(pos, 1, "\n#define ");
+        }
+        out += "\n";
+    }
+#ifdef OPENGL_ES
+    out.insert(0, OPENGL_ES_DEFINE);
+#endif
+}
+
+void replaceIncludes(const char* filepath, const char* source, std::string& out)
+{
+    // Replace the #include "xxxx.xxx" with the sourced file contents of "filepath/xxxx.xxx"
+    std::string str = source;
+    size_t lastPos = 0;
+    size_t headPos = 0;
+    size_t tailPos = 0;
+    size_t fileLen = str.length();
+    tailPos = fileLen;
+    while (headPos < fileLen)
+    {
+        lastPos = headPos;
+        if (headPos == 0)
+        {
+            // find the first "#include"
+            headPos = str.find("#include");
+        }
+        else
+        {
+            // find the next "#include"
+            headPos = str.find("#include", headPos + 1);
+        }
+
+        // If "#include" is found
+        if (headPos != std::string::npos)
+        {
+            // append from our last position for the legth (head - last position) 
+            out.append(str.substr(lastPos,  headPos - lastPos));
+
+            // find the start quote "
+            size_t startQuote = str.find("\"", headPos) + 1;
+            if (startQuote == std::string::npos)
+            {
+                // We have started an "#include" but missing the leading quote "
+                GP_ERROR("Compile failed for shader '%s' missing leading \".", filepath);
+                return;
+            }
+            // find the end quote "
+            size_t endQuote = str.find("\"", startQuote);
+            if (endQuote == std::string::npos)
+            {
+                // We have a start quote but missing the trailing quote "
+                GP_ERROR("Compile failed for shader '%s' missing trailing \".", filepath);
+                return;
+            }
+
+            // jump the head position past the end quote
+            headPos = endQuote + 1;
+            
+            // File path to include and 'stitch' in the value in the quotes to the file path and source it.
+            std::string filepathStr = filepath;
+            std::string directoryPath = filepathStr.substr(0, filepathStr.rfind('/') + 1);
+            size_t len = endQuote - (startQuote);
+            std::string includeStr = str.substr(startQuote, len);
+            directoryPath.append(includeStr);
+            const char* includedSource = FileSystem::readAll(directoryPath.c_str());
+            if (includedSource == NULL)
+            {
+                GP_ERROR("Compile failed for shader '%s' invalid filepath.", filepathStr.c_str());
+                return;
+            }
+            else
+            {
+                // Valid file so lets attempt to see if we need to append anything to it too (recurse...)
+                replaceIncludes(directoryPath.c_str(), includedSource, out);
+                SAFE_DELETE_ARRAY(includedSource);
+            }
+        }
+        else
+        {
+            // Append the remaining
+            out.append(str.c_str(), lastPos, tailPos);
+        }
+    }
+}
+
+void writeShaderToErrorFile(const char* filePath, const char* source)
+{
+    std::string path = filePath;
+    path += ".err";
+    FILE* file = FileSystem::openFile(path.c_str(), "wb");
+    int err = ferror(file);
+    fwrite(source, 1, strlen(source), file);
+    fclose(file);
+}
+
 Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, const char* fshPath, const char* fshSource, const char* defines)
 {
     GP_ASSERT(vshSource);
@@ -116,16 +221,23 @@ Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, con
     GLint length;
     GLint success;
 
-    // Compile vertex shader.
-    std::string definesStr = (defines == NULL) ? "" : defines;
-#ifdef OPENGL_ES
-    if (defines && strlen(defines) != 0)
-        definesStr += "\n";
-    definesStr+= OPENGL_ES_DEFINE;
-#endif
+    // Replace all comma seperated definitions with #define prefix and \n suffix
+    std::string definesStr = "";
+    replaceDefines(defines, definesStr);
+    
     shaderSource[0] = definesStr.c_str();
     shaderSource[1] = "\n";
-    shaderSource[2] = vshSource;
+    std::string vshSourceStr = "";
+    if (vshPath)
+    {
+        // Replace the #include "xxxxx.xxx" with the sources that come from file paths
+        replaceIncludes(vshPath, vshSource, vshSourceStr);
+        if (vshSource && strlen(vshSource) != 0)
+            vshSourceStr += "\n";
+            
+        //writeShaderToErrorFile(vshPath, vshSourceStr.c_str());   // Debugging
+    }
+    shaderSource[2] = vshPath ? vshSourceStr.c_str() :  vshSource;
     GL_ASSERT( vertexShader = glCreateShader(GL_VERTEX_SHADER) );
     GL_ASSERT( glShaderSource(vertexShader, SHADER_SOURCE_LENGTH, shaderSource, NULL) );
     GL_ASSERT( glCompileShader(vertexShader) );
@@ -139,6 +251,11 @@ Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, con
             GL_ASSERT( glGetShaderInfoLog(vertexShader, length, NULL, infoLog) );
             infoLog[length-1] = '\0';
         }
+
+        // Write out the expanded shader file.
+        if (vshPath)
+            writeShaderToErrorFile(vshPath, shaderSource[2]);
+
         GP_ERROR("Compile failed for vertex shader '%s' with error '%s'.", vshPath == NULL ? "NULL" : vshPath, infoLog == NULL ? "" : infoLog);
         SAFE_DELETE_ARRAY(infoLog);
 
@@ -149,7 +266,17 @@ Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, con
     }
 
     // Compile the fragment shader.
-    shaderSource[2] = fshSource;
+    std::string fshSourceStr;
+    if (fshPath)
+    {
+        // Replace the #include "xxxxx.xxx" with the sources that come from file paths
+        replaceIncludes(fshPath, fshSource, fshSourceStr);
+        if (fshSource && strlen(fshSource) != 0)
+            fshSourceStr += "\n";
+
+        //writeShaderToErrorFile(fshPath, fshSourceStr.c_str()); // Debugging
+    }
+    shaderSource[2] = fshPath ? fshSourceStr.c_str() : fshSource;
     GL_ASSERT( fragmentShader = glCreateShader(GL_FRAGMENT_SHADER) );
     GL_ASSERT( glShaderSource(fragmentShader, SHADER_SOURCE_LENGTH, shaderSource, NULL) );
     GL_ASSERT( glCompileShader(fragmentShader) );
@@ -163,6 +290,11 @@ Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, con
             GL_ASSERT( glGetShaderInfoLog(fragmentShader, length, NULL, infoLog) );
             infoLog[length-1] = '\0';
         }
+        
+        // Write out the expanded shader file.
+        if (fshPath)
+            writeShaderToErrorFile(fshPath, shaderSource[2]);
+
         GP_ERROR("Compile failed for fragment shader (%s): %s", fshPath == NULL ? "NULL" : fshPath, infoLog == NULL ? "" : infoLog);
         SAFE_DELETE_ARRAY(infoLog);
 

+ 8 - 5
gameplay/src/FileSystem.cpp

@@ -200,14 +200,14 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
 #endif
 }
 
-bool FileSystem::fileExists(const char* path)
+bool FileSystem::fileExists(const char* filePath)
 {
-    GP_ASSERT(path);
+    GP_ASSERT(filePath);
 
     std::string fullPath(__resourcePath);
-    fullPath += resolvePath(path);
+    fullPath += resolvePath(filePath);
 
-    createFileFromAsset(path);
+    createFileFromAsset(filePath);
 
     gp_stat_struct s;
 // Win32 doesn't support an asset or bundle definitions.
@@ -216,7 +216,7 @@ bool FileSystem::fileExists(const char* path)
     {
         fullPath = __resourcePath;
         fullPath += "../../gameplay/";
-        fullPath += path;
+        fullPath += filePath;
         
         return stat(fullPath.c_str(), &s) == 0;
     }
@@ -229,6 +229,7 @@ bool FileSystem::fileExists(const char* path)
 FILE* FileSystem::openFile(const char* path, const char* mode)
 {
     GP_ASSERT(path);
+    GP_ASSERT(mode);
 
     std::string fullPath(__resourcePath);
     fullPath += resolvePath(path);
@@ -254,6 +255,8 @@ FILE* FileSystem::openFile(const char* path, const char* mode)
 
 char* FileSystem::readAll(const char* filePath, int* fileSize)
 {
+    GP_ASSERT(filePath);
+
     // Open file for reading.
     FILE* file = openFile(filePath, "rb");
     if (file == NULL)

+ 4 - 4
gameplay/src/FileSystem.h

@@ -95,10 +95,10 @@ public:
     /**
      * Checks if the file at the given path exists.
      * 
-     * @param path The path to the file.
+     * @param filePath The path to the file.
      * @return <code>true</code> if the file exists; <code>false</code> otherwise.
      */
-    static bool fileExists(const char* path);
+    static bool fileExists(const char* filePath);
 
     /**
      * Opens the specified file.
@@ -106,12 +106,12 @@ public:
      * The file at the specified location is opened, relative to the currently set
      * resource path.
      *
-     * @param path The path to the file to be opened, relative to the currently set resource path.
+     * @param filePath The path to the file to be opened, relative to the currently set resource path.
      * @param mode The mode used to open the file, passed directly to fopen.
      * 
      * @see setResourcePath(const char*)
      */
-    static FILE* openFile(const char* path, const char* mode);
+    static FILE* openFile(const char* filePath, const char* mode);
 
     /**
      * Reads the entire contents of the specified file and returns its contents.

+ 177 - 119
gameplay/src/Form.cpp

@@ -10,12 +10,35 @@
 #include "CheckBox.h"
 #include "Scene.h"
 
+#define FORM_VSH \
+    "uniform mat4 u_worldViewProjectionMatrix;\n" \
+    "attribute vec3 a_position;\n" \
+    "attribute vec2 a_texCoord;\n" \
+    "varying vec2 v_texCoord;\n" \
+    "void main()\n" \
+    "{\n" \
+        "gl_Position = u_worldViewProjectionMatrix * vec4(a_position, 1);\n" \
+        "v_texCoord = a_texCoord;\n" \
+    "}\n"
+
+#define FORM_FSH \
+    "#ifdef OPENGL_ES\n" \
+    "precision highp float;\n" \
+    "#endif\n" \
+    "varying vec2 v_texCoord;\n" \
+    "uniform sampler2D u_texture;\n" \
+    "void main()\n" \
+    "{\n" \
+        "gl_FragColor = texture2D(u_texture, v_texCoord);\n" \
+    "}\n"
+
 namespace gameplay
 {
 
+static Effect* __formEffect = NULL;
 static std::vector<Form*> __forms;
 
-Form::Form() : _theme(NULL), _quad(NULL), _node(NULL), _frameBuffer(NULL), _spriteBatch(NULL)
+Form::Form() : _theme(NULL), _frameBuffer(NULL), _spriteBatch(NULL), _node(NULL), _nodeQuad(NULL), _nodeMaterial(NULL) , _u2(0), _v1(0)
 {
 }
 
@@ -25,11 +48,19 @@ Form::Form(const Form& copy)
 
 Form::~Form()
 {
-    SAFE_RELEASE(_quad);
     SAFE_RELEASE(_node);
+    SAFE_DELETE(_spriteBatch);
     SAFE_RELEASE(_frameBuffer);
     SAFE_RELEASE(_theme);
-    SAFE_DELETE(_spriteBatch);
+
+    if (__formEffect)
+    {
+        if (__formEffect->getRefCount() == 1)
+        {
+            __formEffect->release();
+            __formEffect = NULL;
+        }
+    }
 
     // Remove this Form from the global list.
     std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
@@ -39,6 +70,43 @@ Form::~Form()
     }
 }
 
+Form* Form::create(const char* id, Theme::Style* style, Layout::Type layoutType)
+{
+    GP_ASSERT(style);
+
+    Layout* layout;
+    switch (layoutType)
+    {
+    case Layout::LAYOUT_ABSOLUTE:
+        layout = AbsoluteLayout::create();
+        break;
+    case Layout::LAYOUT_FLOW:
+        layout = FlowLayout::create();
+        break;
+    case Layout::LAYOUT_VERTICAL:
+        layout = VerticalLayout::create();
+        break;
+    default:
+        GP_ERROR("Unsupported layout type '%d'.", layoutType);
+        break;
+    }
+
+    Form* form = new Form();
+    if (id)
+        form->_id = id;
+    form->_style = style;
+    form->_layout = layout;
+    form->_theme = style->getTheme();
+
+    // Get default projection matrix.
+    Game* game = Game::getInstance();
+    Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &form->_defaultProjectionMatrix);
+
+    __forms.push_back(form);
+
+    return form;
+}
+
 Form* Form::create(const char* url)
 {
     // Load Form from .form file.
@@ -99,9 +167,7 @@ Form* Form::create(const char* url)
     }
     else
     {
-        Theme::Style::Overlay* overlay = Theme::Style::Overlay::create();
-        style = new Theme::Style(theme, "", 1.0f / theme->_texture->getWidth(), 1.0f / theme->_texture->getHeight(),
-            Theme::Margin::empty(), Theme::Border::empty(), overlay, overlay, overlay, overlay);
+        style = theme->getEmptyStyle();
     }
     form->initialize(style, formProperties);
 
@@ -155,10 +221,14 @@ Form* Form::getForm(const char* id)
             return f;
         }
     }
-        
     return NULL;
 }
 
+Theme* Form::getTheme() const
+{
+    return _theme;
+}
+
 void Form::setSize(float width, float height)
 {
     if (_autoWidth)
@@ -194,15 +264,13 @@ void Form::setSize(float width, float height)
         _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
         GP_ASSERT(_spriteBatch);
 
-        // Clear FBO.
-        _frameBuffer->bind();
+        // Clear the framebuffer black
         Game* game = Game::getInstance();
+        _frameBuffer->bind();
         Rectangle prevViewport = game->getViewport();
         game->setViewport(Rectangle(0, 0, width, height));
         _theme->setProjectionMatrix(_projectionMatrix);
-        GL_ASSERT( glClearColor(0, 0, 0, 0) );
-        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
-        GL_ASSERT( glClearColor(0, 0, 0, 1) );
+        game->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0, 0);
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
         FrameBuffer::bindDefault();
         game->setViewport(prevViewport);
@@ -247,52 +315,83 @@ void Form::setAutoHeight(bool autoHeight)
     }
 }
 
-void Form::setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4)
-{
-    Mesh* mesh = Mesh::createQuad(p1, p2, p3, p4);
-
-    initializeQuad(mesh);
-    SAFE_RELEASE(mesh);
-}
-
-void Form::setQuad(float x, float y, float width, float height)
+Effect* createEffect()
 {
-    float x2 = x + width;
-    float y2 = y + height;
-
-    float vertices[] =
+    Effect* effect = NULL;
+    if (__formEffect == NULL)
     {
-        x, y2, 0,   0, _v1,
-        x, y, 0,    0, 0,
-        x2, y2, 0,  _u2, _v1,
-        x2, y, 0,   _u2, 0
-    };
-
-    VertexFormat::Element elements[] =
+        __formEffect = Effect::createFromSource(FORM_VSH, FORM_FSH);
+        if (__formEffect == NULL)
+        {
+            GP_ERROR("Unable to load form effect.");
+            return NULL;
+        }
+        effect = __formEffect;
+    }
+    else
     {
-        VertexFormat::Element(VertexFormat::POSITION, 3),
-        VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
-    };
-    Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
-    assert(mesh);
-
-    mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
-    mesh->setVertexData(vertices, 0, 4);
-
-    initializeQuad(mesh);
-    SAFE_RELEASE(mesh);
+        effect = __formEffect;
+    }
+    return effect;
 }
 
 void Form::setNode(Node* node)
 {
-    _node = node;
-        
-    if (_node)
+    // If the user wants a custom node then we need to create a 3D quad
+    if (node && node != _node)
     {
         // Set this Form up to be 3D by initializing a quad.
-        setQuad(0.0f, 0.0f, _bounds.width, _bounds.height);
-        _node->setModel(_quad);
+        float x2 = _bounds.width;
+        float y2 = _bounds.height;
+        float vertices[] =
+        {
+            0, y2, 0,   0, _v1,
+            0, 0, 0,    0, 0,
+            x2, y2, 0,  _u2, _v1,
+            x2, 0, 0,   _u2, 0
+        };
+        VertexFormat::Element elements[] =
+        {
+            VertexFormat::Element(VertexFormat::POSITION, 3),
+            VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
+        };
+        Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
+        GP_ASSERT(mesh);
+        mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
+        mesh->setVertexData(vertices, 0, 4);
+
+        _nodeQuad = Model::create(mesh);
+        SAFE_RELEASE(mesh);
+        GP_ASSERT(_nodeQuad);
+
+        // Create the effect and material
+        Effect* effect = createEffect();
+        GP_ASSERT(effect);
+        _nodeMaterial = Material::create(effect);
+
+        GP_ASSERT(_nodeMaterial);
+        _nodeQuad->setMaterial(_nodeMaterial);
+        _nodeMaterial->release();
+        node->setModel(_nodeQuad);
+        _nodeQuad->release();
+
+        // Bind the WorldViewProjection matrix.
+        _nodeMaterial->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
+
+        // Bind the texture from the framebuffer and set the texture to clamp
+        Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
+        GP_ASSERT(sampler);
+        sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
+        _nodeMaterial->getParameter("u_texture")->setValue(sampler);
+        sampler->release();
+
+        RenderState::StateBlock* rsBlock = _nodeMaterial->getStateBlock();
+        rsBlock->setDepthWrite(true);
+        rsBlock->setBlend(true);
+        rsBlock->setBlendSrc(RenderState::BLEND_SRC_ALPHA);
+        rsBlock->setBlendDst(RenderState::BLEND_ONE_MINUS_SRC_ALPHA);
     }
+    _node = node;
 }
 
 void Form::update()
@@ -346,8 +445,7 @@ void Form::update()
         y = 0;
         _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
 
-        // Calculate the absolute viewport bounds.
-        // Absolute bounds minus border and padding.
+        // Calculate the absolute viewport bounds. Absolute bounds minus border and padding.
         const Theme::Border& border = getBorder(_state);
         const Theme::Padding& padding = getPadding();
 
@@ -358,9 +456,7 @@ void Form::update()
 
         _viewportBounds.set(x, y, width, height);
 
-        // Calculate the clip area.
-        // Absolute bounds, minus border and padding,
-        // clipped to the parent container's clip area.
+        // Calculate the clip area. Absolute bounds, minus border and padding, clipped to the parent container's clip area.
         clipX2 = clip.x + clip.width;
         x2 = x + width;
         if (x2 > clipX2)
@@ -428,20 +524,15 @@ void Form::update()
 
 void Form::draw()
 {
-    /*
-    The first time a form is drawn, its contents are rendered into a framebuffer.
-    The framebuffer will only be drawn into again when the contents of the form change.
-
-    If this form has a node then it's a 3D form and the framebuffer will be used
-    to texture a quad.  The quad will be given the same dimensions as the form and
-    must be transformed appropriately by the user, unless they call setQuad() themselves.
-
-    On the other hand, if this form has not been set on a node, SpriteBatch will be used
-    to render the contents of the frambuffer directly to the display.
-    */
-
-    // Check whether this form has changed since the last call to draw()
-    // and if so, render into the framebuffer.
+    // The first time a form is drawn, its contents are rendered into a framebuffer.
+    // The framebuffer will only be drawn into again when the contents of the form change.
+    // If this form has a node then it's a 3D form and the framebuffer will be used
+    // to texture a quad.  The quad will be given the same dimensions as the form and
+    // must be transformed appropriately by the user, unless they call setQuad() themselves.
+    // On the other hand, if this form has not been set on a node, SpriteBatch will be used
+    // to render the contents of the frambuffer directly to the display.
+
+    // Check whether this form has changed since the last call to draw() and if so, render into the framebuffer.
     if (isDirty())
     {
         GP_ASSERT(_frameBuffer);
@@ -463,62 +554,36 @@ void Form::draw()
         game->setViewport(prevViewport);
     }
 
+    // Draw either with a 3D quad or sprite batch
     if (_node)
     {
-        GP_ASSERT(_quad);
-        _quad->draw();
+         // If we have the node set, then draw a 3D quad model
+        _nodeQuad->draw();
     }
     else
     {
+        // Otherwise we draw the framebuffer in ortho space with a spritebatch.
         if (!_spriteBatch)
         {
             _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
             GP_ASSERT(_spriteBatch);
         }
-
         _spriteBatch->begin();
         _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
         _spriteBatch->end();
     }
 }
 
-void Form::initializeQuad(Mesh* mesh)
+const char* Form::getType() const
 {
-    // Release current model.
-    SAFE_RELEASE(_quad);
-
-    // Create the model.
-    _quad = Model::create(mesh);
-
-    // Create the material.
-    Material* material = _quad->setMaterial("res/shaders/textured.vsh", "res/shaders/textured.fsh");
-    GP_ASSERT(material);
-
-    // Set the common render state block for the material.
-    GP_ASSERT(_theme);
-    GP_ASSERT(_theme->getSpriteBatch());
-    RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
-    GP_ASSERT(stateBlock);
-    stateBlock->setDepthWrite(true);
-    material->setStateBlock(stateBlock);
-
-    // Bind the WorldViewProjection matrix.
-    material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
-
-    // Bind the texture.
-    Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
-    GP_ASSERT(sampler);
-    sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
-    material->getParameter("u_diffuseTexture")->setValue(sampler);
-    material->getParameter("u_diffuseColor")->setValue(Vector4::one());
-
-    SAFE_RELEASE(sampler);
+    return "form";
 }
 
 bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     // Check for a collision with each Form in __forms.
     // Pass the event on.
+    bool eventConsumed = false;
     std::vector<Form*>::const_iterator it;
     for (it = __forms.begin(); it < __forms.end(); it++)
     {
@@ -540,7 +605,7 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
                          point.y >= bounds.y &&
                          point.y <= bounds.y + bounds.height))
                     {
-                        return form->touchEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, contactIndex);
+                        eventConsumed |= form->touchEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, contactIndex);
                     }
                 }
             }
@@ -556,13 +621,12 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
                         y <= bounds.y + bounds.height))
                 {
                     // Pass on the event's position relative to the form.
-                    return form->touchEvent(evt, x - bounds.x, y - bounds.y, contactIndex);
+                    eventConsumed |= form->touchEvent(evt, x - bounds.x, y - bounds.y, contactIndex);
                 }
             }
         }
     }
-
-    return false;
+    return eventConsumed;
 }
 
 bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
@@ -578,12 +642,13 @@ bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
                 return true;
         }
     }
-
     return false;
 }
 
 bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 {
+    bool eventConsumed = false;
+
     std::vector<Form*>::const_iterator it;
     for (it = __forms.begin(); it < __forms.end(); it++)
     {
@@ -608,7 +673,7 @@ bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
                          point.y >= bounds.y &&
                          point.y <= bounds.y + bounds.height))
                     {
-                        return form->mouseEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, wheelDelta);
+                        eventConsumed |= form->mouseEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, wheelDelta);
                     }
                 }
             }
@@ -627,13 +692,12 @@ bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
                         y <= bounds.y + bounds.height))
                 {
                     // Pass on the event's position relative to the form.
-                    return form->mouseEvent(evt, x - bounds.x, y - bounds.y, wheelDelta);
+                    eventConsumed |= form->mouseEvent(evt, x - bounds.x, y - bounds.y, wheelDelta);
                 }
             }
         }
     }
-
-    return false;
+    return eventConsumed;
 }
 
 bool Form::projectPoint(int x, int y, Vector3* point)
@@ -653,14 +717,11 @@ bool Form::projectPoint(int x, int y, Vector3* point)
         Ray ray;
         camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
 
-        // Find the quad's plane.
-        // We know its normal is the quad's forward vector.
+        // Find the quad's plane.  We know its normal is the quad's forward vector.
         Vector3 normal = _node->getForwardVectorWorld();
 
-        // To get the plane's distance from the origin,
-        // we'll find the distance from the plane defined
-        // by the quad's forward vector and one of its points
-        // to the plane defined by the same vector and the origin.
+        // To get the plane's distance from the origin, we'll find the distance from the plane defined
+        // by the quad's forward vector and one of its points to the plane defined by the same vector and the origin.
         const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
         const float d = -(a*min.x) - (b*min.y) - (c*min.z);
         const float distance = abs(d) /  sqrt(a*a + b*b + c*c);
@@ -670,8 +731,7 @@ bool Form::projectPoint(int x, int y, Vector3* point)
         float collisionDistance = ray.intersects(plane);
         if (collisionDistance != Ray::INTERSECTS_NONE)
         {
-            // Multiply the ray's direction vector by collision distance
-            // and add that to the ray's origin.
+            // Multiply the ray's direction vector by collision distance and add that to the ray's origin.
             point->set(ray.getOrigin() + collisionDistance*ray.getDirection());
 
             // Project this point into the plane.
@@ -681,13 +741,11 @@ bool Form::projectPoint(int x, int y, Vector3* point)
             return true;
         }
     }
-
     return false;
 }
 
 unsigned int Form::nextPowerOfTwo(unsigned int v)
 {
-
     if (!((v & (v - 1)) == 0))
     {
         v--;

+ 31 - 32
gameplay/src/Form.h

@@ -55,10 +55,21 @@ public:
      * where the URL is of the format "<file-path>.<extension>#<namespace-id>/<namespace-id>/.../<namespace-id>"
      * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional). 
      * 
-     * @param url The URL pointing to the Properties object defining the animation data. 
+     * @param url The URL pointing to the Properties object defining the form. 
      */
     static Form* create(const char* url);
 
+    /**
+     * Create a new Form.
+     *
+     * @param id The Form's ID.
+     * @param style The Form's style.
+     * @param layoutType The form's layout type.
+     *
+     * @return The new Form.
+     */
+    static Form* create(const char* id, Theme::Style* style, Layout::Type layoutType = Layout::LAYOUT_ABSOLUTE);
+
     /**
      * Get a form from its ID.
      *
@@ -67,6 +78,13 @@ public:
      * @return A form with the given ID, or null if one was not found.
      */
     static Form* getForm(const char* id);
+    
+    /**
+     * Gets the theme for the form.
+     *
+     * @return The theme for the form.
+     */
+    Theme* getTheme() const;
 
     /**
      * Set the desired size of this form.
@@ -97,30 +115,6 @@ public:
      */
     virtual void setAutoHeight(bool autoHeight);
 
-    /**
-     * Create a 3D quad to texture with this Form.
-     *
-     * The specified points should describe a triangle strip with the first 3 points
-     * forming a triangle wound in counter-clockwise direction, with the second triangle
-     * formed from the last three points in clockwise direction.
-     *
-     * @param p1 The first point.
-     * @param p2 The second point.
-     * @param p3 The third point.
-     * @param p4 The fourth point.
-     */
-    void setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4);
-
-    /**
-     * Create a 2D quad to texture with this Form.
-     *
-     * @param x The x coordinate.
-     * @param y The y coordinate.
-     * @param width The width of the quad.
-     * @param height The height of the quad.
-     */
-    void setQuad(float x, float y, float width, float height);
-
     /**
      * Attach this form to a node.
      *
@@ -143,6 +137,11 @@ public:
      */
     void draw();
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
 private:
     
     /**
@@ -211,17 +210,17 @@ private:
     bool projectPoint(int x, int y, Vector3* point);
 
     Theme* _theme;                      // The Theme applied to this Form.
-    Model* _quad;                       // Quad for rendering this Form in world-space.
-    Node* _node;                        // Node for transforming this Form in world-space.
-    FrameBuffer* _frameBuffer;          // FBO the Form is rendered into for texturing the quad.
-    Matrix _projectionMatrix;           // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
-    Matrix _defaultProjectionMatrix;
+    FrameBuffer* _frameBuffer;          // FBO the Form is rendered into for texturing the quad. 
     SpriteBatch* _spriteBatch;
-
+    Node* _node;                        // Node for transforming this Form in world-space.
+    Model* _nodeQuad;                   // Quad for rendering this Form in 3d space.
+    Material* _nodeMaterial;            // Material for rendering this Form in 3d space.
     float _u2;
     float _v1;
+    Matrix _projectionMatrix;           // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
+    Matrix _defaultProjectionMatrix;   
 };
 
 }
 
-#endif
+#endif

+ 5 - 1
gameplay/src/FrameBuffer.cpp

@@ -24,7 +24,10 @@ FrameBuffer::~FrameBuffer()
     {
         for (unsigned int i = 0; i < __maxRenderTargets; ++i)
         {
-            SAFE_RELEASE(_renderTargets[i]);
+            if (_renderTargets[i])
+            {
+                SAFE_RELEASE(_renderTargets[i]);
+            }
         }
         SAFE_DELETE_ARRAY(_renderTargets);
     }
@@ -86,6 +89,7 @@ FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned in
     frameBuffer->_renderTargets = renderTargets;
 
     frameBuffer->setRenderTarget(renderTarget, 0);
+    SAFE_RELEASE(renderTarget);
 
     __frameBuffers.push_back(frameBuffer);
 

+ 76 - 2
gameplay/src/Game.cpp

@@ -20,7 +20,8 @@ Game::Game()
     : _initialized(false), _state(UNINITIALIZED), 
       _frameLastFPS(0), _frameCount(0), _frameRate(0), 
       _clearDepth(1.0f), _clearStencil(0), _properties(NULL),
-      _animationController(NULL), _audioController(NULL), _physicsController(NULL), _audioListener(NULL)
+      _animationController(NULL), _audioController(NULL), _physicsController(NULL), _audioListener(NULL), 
+      _gamepadCount(0), _gamepads(NULL)
 {
     GP_ASSERT(__gameInstance == NULL);
     __gameInstance = this;
@@ -95,7 +96,7 @@ bool Game::startup()
     setViewport(Rectangle(0.0f, 0.0f, (float)_width, (float)_height));
     RenderState::initialize();
     FrameBuffer::initialize();
-
+    
     _animationController = new AnimationController();
     _animationController->initialize();
 
@@ -105,6 +106,8 @@ bool Game::startup()
     _physicsController = new PhysicsController();
     _physicsController->initialize();
 
+    loadGamepad();
+    
     _state = RUNNING;
 
     return true;
@@ -122,6 +125,15 @@ void Game::shutdown()
         Platform::signalShutdown();
         finalize();
 
+        if (_gamepads)
+        {
+            for (unsigned int i = 0; i < _gamepadCount; i++)
+            {
+                SAFE_DELETE(_gamepads[i]);
+            }
+            SAFE_DELETE_ARRAY(_gamepads);
+        }
+
         _animationController->finalize();
         SAFE_DELETE(_animationController);
 
@@ -207,6 +219,12 @@ void Game::frame()
         // Update the physics.
         _physicsController->update(elapsedTime);
 
+        if (_gamepads)
+        {
+            for (unsigned int i = 0; i < _gamepadCount; i++)
+                _gamepads[i]->update();
+        }
+
         // Application Update.
         update(elapsedTime);
 
@@ -215,6 +233,12 @@ void Game::frame()
 
         // Graphics Rendering.
         render(elapsedTime);
+        
+        if (_gamepads)
+        {
+            for (unsigned int i = 0; i < _gamepadCount; i++)
+                _gamepads[i]->render();
+        }
 
         // Update FPS.
         ++_frameCount;
@@ -305,6 +329,10 @@ void Game::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactI
 {
 }
 
+void Game::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int index)
+{
+}
+
 void Game::schedule(float timeOffset, TimeListener* timeListener, void* cookie)
 {
     GP_ASSERT(_timeEvents);
@@ -386,4 +414,50 @@ bool Game::TimeEvent::operator<(const TimeEvent& v) const
     return time > v.time;
 }
 
+Gamepad* Game::createGamepad(const char* gamepadFormPath)
+{
+    GP_ASSERT(gamepadFormPath);
+
+    Gamepad* gamepad = new Gamepad(gamepadFormPath);
+    GP_ASSERT(gamepad);
+
+    if (!_gamepads)
+    {
+        _gamepadCount++;
+        _gamepads = new Gamepad*[_gamepadCount];
+        _gamepads[0] = gamepad;
+    }
+    else
+    {
+        int oldSize = _gamepadCount;
+        _gamepadCount++;
+        Gamepad** tempGamepads = new Gamepad*[_gamepadCount];
+        memcpy(tempGamepads, _gamepads, sizeof(Gamepad*) * oldSize);
+        tempGamepads[oldSize] = gamepad;
+        
+        SAFE_DELETE_ARRAY(_gamepads);
+        _gamepads = tempGamepads;
+    }
+
+    return gamepad;
+}
+
+void Game::loadGamepad()
+{
+    if (_properties)
+    {
+        // Check if there is a virtual keyboard included in the .config file.
+        // If there is, try to create it and assign it to "player one".
+        Properties* gamepadProperties = _properties->getNamespace("gamepad", true);
+        if (gamepadProperties && gamepadProperties->exists("form"))
+        {
+            const char* gamepadFormPath = gamepadProperties->getString("form");
+            GP_ASSERT(gamepadFormPath);
+
+            Gamepad* gamepad = createGamepad(gamepadFormPath);
+            GP_ASSERT(gamepad);
+        }
+    }
+}
+
 }

+ 34 - 1
gameplay/src/Game.h

@@ -13,6 +13,7 @@
 #include "Rectangle.h"
 #include "Vector4.h"
 #include "TimeListener.h"
+#include "Gamepad.h"
 
 namespace gameplay
 {
@@ -22,6 +23,7 @@ namespace gameplay
  */
 class Game
 {
+
 public:
 
     /**
@@ -267,6 +269,15 @@ public:
      */
     virtual bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
 
+    /**
+     * Gamepad callback on gamepad events.
+     *
+     * @param evt The gamepad event that occured.
+     * @param gamepad the gamepad the event occured on
+     * @param index The joystick or button index that triggered the event.
+     */
+    virtual void gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int index);
+
     /**
      * Sets muli-touch is to be enabled/disabled. Default is disabled.
      *
@@ -290,7 +301,7 @@ public:
     inline void getAccelerometerValues(float* pitch, float* roll);
 
     /**
-     * Schedules a time event to be sent to the given TimeListener a given of game milliseconds from now.
+     * Schedules a time event to be sent to the given TimeListener a given number of game milliseconds from now.
      * Game time stops while the game is paused. A time offset of zero will fire the time event in the next frame.
      * 
      * @param timeOffset The number of game milliseconds in the future to schedule the event to be fired.
@@ -299,6 +310,21 @@ public:
      */
     void schedule(float timeOffset, TimeListener* timeListener, void* cookie = 0);
 
+    /** 
+     * Creates a Gamepad object from a .form file.
+     *
+     * @param playerIndex
+     * @param formPath
+     */
+    Gamepad* createGamepad(const char* gamepadFormPath);
+
+    /**
+     * Gets the gamepad for the specified player index.
+     *
+     * @param playerIndex The player index to get the gamepad for (0 <= playerIndex <= 3) 
+     */
+    inline Gamepad* getGamepad(unsigned int playerIndex = 0);
+
 protected:
 
     /**
@@ -405,6 +431,11 @@ private:
      */
     void loadConfig();
 
+    /**
+     * Loads a gamepad from the configuration file.
+     */
+    void loadGamepad();
+
     bool _initialized;                          // If game has initialized yet.
     State _state;                               // The game state.
     static double _pausedTimeLast;              // The last time paused.
@@ -423,6 +454,8 @@ private:
     AudioController* _audioController;          // Controls audio sources that are playing in the game.
     PhysicsController* _physicsController;      // Controls the simulation of a physics scene and entities.
     AudioListener* _audioListener;              // The audio listener in 3D space.
+    unsigned int _gamepadCount;
+    Gamepad** _gamepads;
     std::priority_queue<TimeEvent, std::vector<TimeEvent>, std::less<TimeEvent> >* _timeEvents; // Contains the scheduled time events.
 
     // Note: Do not add STL object member variables on the stack; this will cause false memory leaks to be reported.

+ 11 - 1
gameplay/src/Game.inl

@@ -72,4 +72,14 @@ inline void Game::displayKeyboard(bool display)
     Platform::displayKeyboard(display);
 }
 
-}
+inline Gamepad* Game::getGamepad(unsigned int playerIndex)
+{
+    GP_ASSERT(playerIndex < _gamepadCount);
+
+    if (_gamepads)
+        return _gamepads[playerIndex];
+    else
+        return NULL;
+}
+
+}

+ 181 - 0
gameplay/src/Gamepad.cpp

@@ -0,0 +1,181 @@
+#include "Base.h"
+#include "Gamepad.h"
+#include "Joystick.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+Gamepad::Gamepad()
+    : _playerIndex(-1), _joystickValues(NULL), _joystickCount(0), _buttonStates(NULL), _buttonCount(0), _gamepadForm(NULL)
+{
+}
+
+Gamepad::Gamepad(const char* formPath)
+    : _playerIndex(-1), _joystickValues(NULL), _joystickCount(0), _buttonStates(NULL), _buttonCount(0), _gamepadForm(NULL)
+{
+    GP_ASSERT(formPath);
+
+    _gamepadForm = Form::create(formPath);
+    GP_ASSERT(_gamepadForm);
+
+    _gamepadForm->setConsumeInputEvents(false);
+
+    getGamepadControls(_gamepadForm);
+
+    if (_joystickCount > 0)
+    {
+        _joystickValues = new Vector2*[_joystickCount];
+        for (unsigned int i = 0; i < _joystickCount; i++)
+        {
+            _joystickValues[i] = new Vector2();
+        }
+    }
+    if (_buttonCount > 0)
+    {
+        _buttonStates = new ButtonState*[_buttonCount];
+        for (unsigned int i = 0; i < _buttonCount; i++)
+        {
+            _buttonStates[i] = new ButtonState();
+        }
+    }
+}
+
+void Gamepad::getGamepadControls(Form* form)
+{
+    std::vector<Control*> controls = form->getControls();
+    std::vector<Control*>::iterator itr = controls.begin();
+
+    for (; itr != controls.end(); itr++)
+    {
+        Control* control = *itr;
+        GP_ASSERT(control);
+
+        if (std::strcmp("container", control->getType()) == 0)
+        {
+            getGamepadControls((Form*) control);
+        }
+        else if (std::strcmp("joystick", control->getType()) == 0)
+        {
+            control->addListener(this, Control::Listener::PRESS | Control::Listener::VALUE_CHANGED | Control::Listener::RELEASE);
+            Joystick* joystick = (Joystick*) control;
+            
+            if (!joystick->_gamepadJoystickIndex)
+                joystick->_gamepadJoystickIndex = new int[1];
+            
+            *joystick->_gamepadJoystickIndex = _joystickCount;
+            _joystickCount++;
+        }
+        else if (std::strcmp("button", control->getType()) == 0)
+        {
+            control->addListener(this, Control::Listener::PRESS | Control::Listener::RELEASE);
+            Button* button = (Button*) control;
+            
+            if (!button->_gamepadButtonIndex)
+                button->_gamepadButtonIndex = new int[1];
+
+            *button->_gamepadButtonIndex = _buttonCount;
+            _buttonCount++;
+        }
+    }
+}
+
+Gamepad::~Gamepad()
+{
+    if (_joystickValues)
+    {
+        for (unsigned int i = 0; i < _joystickCount; i++)
+            SAFE_DELETE(_joystickValues[i]);
+        SAFE_DELETE_ARRAY(_joystickValues);
+    }
+
+    if (_buttonStates)
+    {
+        for (unsigned int i = 0; i < _buttonCount; i++)
+           SAFE_DELETE(_buttonStates[i]);
+        SAFE_DELETE_ARRAY(_buttonStates);
+    }
+
+    if (_gamepadForm)
+        SAFE_RELEASE(_gamepadForm);
+}
+
+void Gamepad::update()
+{
+    if (_gamepadForm && _gamepadForm->isEnabled())
+    {
+        _gamepadForm->update();
+    }
+}
+
+void Gamepad::render()
+{
+    if (_gamepadForm && _gamepadForm->isEnabled())
+    {
+        _gamepadForm->draw();
+    }
+}
+
+void Gamepad::controlEvent(Control* control, Control::Listener::EventType evt)
+{
+    if (_gamepadForm && _gamepadForm->isEnabled())
+    {
+        if (std::strcmp("joystick", control->getType()) == 0)
+        {
+            int joystickIndex = *(((Joystick*) control)->_gamepadJoystickIndex);
+            switch(evt)
+            {
+                case Control::Listener::PRESS:
+                case Control::Listener::VALUE_CHANGED:
+                    _joystickValues[joystickIndex]->set(((Joystick*)control)->getValue());
+                    break;
+                case Control::Listener::RELEASE:
+                    _joystickValues[joystickIndex]->set(0.0f, 0.0f);
+                    break;
+            }
+            Game::getInstance()->gamepadEvent(JOYSTICK_EVENT, this, joystickIndex);
+        }
+        else if (std::strcmp("button", control->getType()) == 0)
+        {
+            int buttonIndex = *(((Button*) control)->_gamepadButtonIndex);
+            switch(evt)
+            {
+                case Control::Listener::PRESS:
+                    *_buttonStates[buttonIndex] = BUTTON_PRESSED;
+                    break;
+                case Control::Listener::RELEASE:
+                    *_buttonStates[buttonIndex] = BUTTON_RELEASED;
+                    break;
+            }
+            Game::getInstance()->gamepadEvent(BUTTON_EVENT, this, buttonIndex);
+        }
+    }
+}
+
+Gamepad::ButtonState Gamepad::getButtonState(unsigned int buttonId) const
+{
+    GP_ASSERT(buttonId < _buttonCount);
+
+    return *_buttonStates[buttonId];
+}
+
+bool Gamepad::isJoystickActive(unsigned int joystickId) const
+{
+    GP_ASSERT(joystickId < _joystickCount);
+
+    return !(_joystickValues[joystickId]->isZero());
+}
+
+const Vector2& Gamepad::getJoystickValue(unsigned int joystickId) const
+{
+    GP_ASSERT(joystickId < _joystickCount);
+
+    return *_joystickValues[joystickId];
+}
+
+bool Gamepad::isVirtual() const
+{
+    return (_gamepadForm && _gamepadForm->isEnabled());
+}
+
+}

+ 113 - 0
gameplay/src/Gamepad.h

@@ -0,0 +1,113 @@
+#ifndef GAMEPAD_H_
+#define GAMEPAD_H_
+
+#include "Form.h"
+#include "Button.h"
+
+namespace gameplay
+{
+
+/**
+ * Defines an interface for handling gamepad support.
+ */
+class Gamepad : public Control::Listener
+{
+    friend class Game;
+
+public:
+
+    enum GamepadEvent
+    {
+        JOYSTICK_EVENT,
+        BUTTON_EVENT
+    };
+
+    enum ButtonState
+    {
+        BUTTON_PRESSED = gameplay::Button::Listener::PRESS, 
+        BUTTON_RELEASED = gameplay::Button::Listener::RELEASE
+    };
+    
+    /** 
+     * Gets the current state of the specified button.
+     */
+    ButtonState getButtonState(unsigned int buttonId) const;
+
+    /**
+     * Gets whether the specified joystick's state is active or not.
+     * 
+     * @param joystickId The unique integer ID of the joystick to set.
+     * @return Whether the given joystick is active or not.
+     */
+    bool isJoystickActive(unsigned int joystickId) const;
+
+    /**
+     * Returns the specified joystick's value as a Vector2.
+     *
+     * @param joystickId The unique integer ID of the joystick to set.
+     * @return A Vector2 of the joystick displacement for the specified joystick.
+     */
+    const Vector2& getJoystickValue(unsigned int joystickId) const;
+
+    /** 
+     * Listener for Control events on the gamepads Joystick or Buttons.
+     */
+    void controlEvent(Control* control, Control::Listener::EventType evt);
+
+    /**
+     * Returns whether the gamepad is represented with a UI form or not.
+     */
+    bool isVirtual() const;
+
+private:
+
+    /**
+     * Constructor.
+     */
+    Gamepad();
+    
+    /**
+     * Constructor.
+     * Create a gamepad from the specified formPath.
+     *
+     * @param formPath
+     */ 
+    Gamepad(const char* formPath);
+
+    /**
+     * Copy constructor.
+     */
+    Gamepad(const Gamepad& copy);
+
+    /** 
+     * Destructor.
+     */
+    virtual ~Gamepad();
+    
+    /** 
+     * Gets the Joystick and Button Control object's from the specified form.
+     */
+    void getGamepadControls(Form* form);
+
+    /**
+     * Updates the gamepad.
+     */
+    void update();
+
+    /**
+     * Renders the gamepad if it is based on a form and if the form is enabled.
+     */
+    void render();
+
+    int _playerIndex;
+    Vector2** _joystickValues;
+    unsigned int _joystickCount;
+    ButtonState** _buttonStates;
+    unsigned int _buttonCount;
+
+    Form* _gamepadForm;
+};
+
+}
+
+#endif

+ 77 - 47
gameplay/src/Joystick.cpp

@@ -1,12 +1,10 @@
 #include "Base.h"
 #include "Joystick.h"
 
-#define INVALID_CONTACT_INDEX ((unsigned int)-1)
-
 namespace gameplay
 {
 
-Joystick::Joystick() : _contactIndex(INVALID_CONTACT_INDEX), _absolute(true)
+Joystick::Joystick() : _absolute(true), _gamepadJoystickIndex(NULL)
 {
 }
 
@@ -16,6 +14,20 @@ Joystick::Joystick(const Joystick& copy)
 
 Joystick::~Joystick()
 {
+    if (_gamepadJoystickIndex)
+        SAFE_DELETE(_gamepadJoystickIndex);
+}
+
+Joystick* Joystick::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    Joystick* joystick = new Joystick();
+    if (id)
+        joystick->_id = id;
+    joystick->setStyle(style);
+
+    return joystick;
 }
 
 Joystick* Joystick::create(Theme::Style* style, Properties* properties)
@@ -40,6 +52,11 @@ void Joystick::initialize(Theme::Style* style, Properties* properties)
     }
     _radius = properties->getFloat("radius");
 
+    if (properties->exists("absolute"))
+    {
+        setAbsolute(properties->getBool("absolute"));
+    }
+
     Vector4 v;
     if (properties->getVector4("region", &v))
     {
@@ -84,10 +101,12 @@ bool Joystick::touchEvent(Touch::TouchEvent touchEvent, int x, int y, unsigned i
                 _region.y = y + _bounds.y - _region.height * 0.5f;
             }
 
-            if ((dx >= -_radius && dx <= _radius) && (dy >= -_radius && dy <= _radius) && 
-                _contactIndex == INVALID_CONTACT_INDEX)
+            if ((dx >= -_radius && dx <= _radius) && (dy >= -_radius && dy <= _radius))
             {
-                _contactIndex = contactIndex;
+                _contactIndex = (int) contactIndex;
+
+                notifyListeners(Listener::PRESS);
+
                 _displacement.set(0.0f, 0.0f);
                 
                 Vector2 value(0.0f, 0.0f);
@@ -99,67 +118,71 @@ bool Joystick::touchEvent(Touch::TouchEvent touchEvent, int x, int y, unsigned i
                 }
 
                 _state = ACTIVE;
+
+                return _consumeInputEvents;
+            }
+            else
+            {
+                _state = NORMAL;
             }
+            break;
         }
         case Touch::TOUCH_MOVE:
         {
-            if (_contactIndex == contactIndex)
+            float dx = x - ((!_absolute) ? _region.x - _bounds.x : 0.0f) - _region.width * 0.5f;
+            float dy = -(y - ((!_absolute) ? _region.y - _bounds.y : 0.0f) - _region.height * 0.5f);
+            if (((dx * dx) + (dy * dy)) <= (_radius * _radius))
             {
-                float dx = x - ((!_absolute) ? _region.x - _bounds.x : 0.0f) - _region.width * 0.5f;
-                float dy = -(y - ((!_absolute) ? _region.y - _bounds.y : 0.0f) - _region.height * 0.5f);
-                if (((dx * dx) + (dy * dy)) <= (_radius * _radius))
-                {
-                    GP_ASSERT(_radius);
-                    Vector2 value(dx, dy);
-                    value.scale(1.0f / _radius);
-                    if (_value != value)
-                    {
-                        _value.set(value);
-                        _dirty = true;
-                        notifyListeners(Control::Listener::VALUE_CHANGED);
-                    }
-                }
-                else
+                GP_ASSERT(_radius);
+                Vector2 value(dx, dy);
+                value.scale(1.0f / _radius);
+                if (_value != value)
                 {
-                    Vector2 value(dx, dy);
-                    value.normalize();
-                    value.scale(_radius);
-                    value.normalize();
-                    if (_value != value)
-                    {
-                        _value.set(value);
-                        _dirty = true;
-                        notifyListeners(Control::Listener::VALUE_CHANGED);
-                    }
+                    _value.set(value);
+                    _dirty = true;
+                    notifyListeners(Control::Listener::VALUE_CHANGED);
                 }
-
-                _displacement.set(dx, dy);
             }
-        }
-        break;
-        case Touch::TOUCH_RELEASE:
-        {
-            if (_contactIndex == contactIndex)
+            else
             {
-                // Reset displacement and direction vectors.
-                _contactIndex = INVALID_CONTACT_INDEX;
-                _displacement.set(0.0f, 0.0f);
-                
-                Vector2 value(0.0f, 0.0f);
+                Vector2 value(dx, dy);
+                value.normalize();
+                value.scale(_radius);
+                value.normalize();
                 if (_value != value)
                 {
                     _value.set(value);
                     _dirty = true;
                     notifyListeners(Control::Listener::VALUE_CHANGED);
                 }
+            }
 
-                _state = NORMAL;
+            _displacement.set(dx, dy);
+
+            return _consumeInputEvents;
+        }
+        case Touch::TOUCH_RELEASE:
+        {
+            _contactIndex = INVALID_CONTACT_INDEX;
+
+            // Reset displacement and direction vectors.
+            _displacement.set(0.0f, 0.0f);
+
+            Vector2 value(0.0f, 0.0f);
+            if (_value != value)
+            {
+                _value.set(value);
+                _dirty = true;
+                notifyListeners(Control::Listener::VALUE_CHANGED);
             }
+
+            _state = NORMAL;
+
+            return _consumeInputEvents;
         }
-        break;
     }
 
-    return Control::touchEvent(touchEvent, x, y, contactIndex);
+    return false;
 }
 
 void Joystick::update(const Control* container, const Vector2& offset)
@@ -226,4 +249,11 @@ void Joystick::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     spriteBatch->end();
 }
 
+const char* Joystick::getType() const
+{
+    return "joystick";
+}
+
+
+
 }

+ 17 - 1
gameplay/src/Joystick.h

@@ -12,8 +12,19 @@ namespace gameplay
 class Joystick : public Control
 {
     friend class Container;
+    friend class Gamepad;
 
 public:
+
+    /**
+     * Create a new joystick control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new joystick.
+     */
+    static Joystick* create(const char* id, Theme::Style* style);
     
     /**
      * Add a listener to be notified of specific events affecting
@@ -69,6 +80,11 @@ public:
      */
     inline bool isAbsolute() const;
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
 protected:
     
     /**
@@ -135,11 +151,11 @@ private:
     Joystick(const Joystick& copy);
 
     float _radius;
-    unsigned int _contactIndex;
     bool _absolute;
     Vector2 _displacement;
     Vector2 _value;
     Rectangle _region;
+    int* _gamepadJoystickIndex;
 };
 
 }

+ 21 - 1
gameplay/src/Label.cpp

@@ -16,11 +16,26 @@ Label::~Label()
 {
 }
 
+Label* Label::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    Label* label = new Label();
+    if (id)
+        label->_id = id;
+    label->setStyle(style);
+
+    return label;
+}
+
 Label* Label::create(Theme::Style* style, Properties* properties)
 {
     Label* label = new Label();
     label->initialize(style, properties);
     label->_consumeInputEvents = false;
+    
+    // Ensure that labels cannot receive focus.
+    label->_focusIndex = -2;
 
     return label;
 }
@@ -97,4 +112,9 @@ void Label::drawText(const Rectangle& clip)
     _dirty = false;
 }
 
-}
+const char* Label::getType() const
+{
+    return "label";
+}
+
+}

+ 16 - 1
gameplay/src/Label.h

@@ -33,6 +33,16 @@ class Label : public Control
 
 public:
 
+    /**
+     * Create a new label control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new label.
+     */
+    static Label* create(const char*id, Theme::Style* style);
+
     /**
      * Set the text for this label to display.
      *
@@ -47,6 +57,11 @@ public:
      */
     const char* getText();
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -132,4 +147,4 @@ private:
 
 }
 
-#endif
+#endif

+ 1 - 13
gameplay/src/Material.cpp

@@ -242,21 +242,9 @@ bool Material::loadPass(Technique* technique, Properties* passProperties)
     const char* fragmentShaderPath = passProperties->getString("fragmentShader");
     GP_ASSERT(fragmentShaderPath);
     const char* defines = passProperties->getString("defines");
-    std::string define;
-    if (defines != NULL)
-    {
-        define = defines;
-        define.insert(0, "#define ");
-        unsigned int pos;
-        while ((pos = define.find(';')) != std::string::npos)
-        {
-            define.replace(pos, 1, "\n#define ");
-        }
-        define += "\n";
-    }
 
     // Create the pass.
-    Pass* pass = Pass::create(passProperties->getId(), technique, vertexShaderPath, fragmentShaderPath, define.c_str());
+    Pass* pass = Pass::create(passProperties->getId(), technique, vertexShaderPath, fragmentShaderPath, defines);
     if (!pass)
     {
         GP_ERROR("Failed to create pass for technique.");

+ 0 - 1
gameplay/src/MaterialParameter.cpp

@@ -227,7 +227,6 @@ Texture::Sampler* MaterialParameter::setValue(const char* texturePath, bool gene
         }
         return sampler;
     }
-
     return NULL;
 }
 

+ 1 - 1
gameplay/src/PlatformWin32.cpp

@@ -312,7 +312,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         UpdateCapture(wParam);
         lx = GET_X_LPARAM(lParam);
         ly = GET_Y_LPARAM(lParam);
-        gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON, lx, ly, 0);
+        gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON, lx, ly, 0);
         break;
 
     case WM_RBUTTONUP:

+ 18 - 1
gameplay/src/RadioButton.cpp

@@ -24,6 +24,18 @@ RadioButton::~RadioButton()
     }
 }
 
+RadioButton* RadioButton::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    RadioButton* radioButton = new RadioButton();
+    if (id)
+        radioButton->_id = id;
+    radioButton->setStyle(style);
+
+    return radioButton;
+}
+
 RadioButton* RadioButton::create(Theme::Style* style, Properties* properties)
 {
     GP_ASSERT(properties);
@@ -186,4 +198,9 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
 }
 
-}
+const char* RadioButton::getType() const
+{
+    return "radioButton";
+}
+
+}

+ 17 - 1
gameplay/src/RadioButton.h

@@ -38,6 +38,17 @@ class RadioButton : public Button
     friend class Container;
 
 public:
+
+    /**
+     * Create a new radio button control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new radio button.
+     */
+    static RadioButton* create(const char* id, Theme::Style* style);
+
     /**
      * Get whether this radio button is currently selected.
      *
@@ -60,6 +71,11 @@ public:
      */
     const Vector2& getImageSize() const;
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -159,4 +175,4 @@ private:
 
 }
 
-#endif
+#endif

+ 16 - 15
gameplay/src/RenderState.cpp

@@ -293,7 +293,7 @@ void RenderState::bind(Pass* pass)
     // Apply parameter bindings and renderer state for the entire hierarchy, top-down.
     rs = NULL;
     Effect* effect = pass->getEffect();
-    while (rs = getTopmost(rs))
+    while ((rs = getTopmost(rs)))
     {
         for (unsigned int i = 0, count = rs->_parameters.size(); i < count; ++i)
         {
@@ -360,8 +360,9 @@ void RenderState::cloneInto(RenderState* renderState, NodeCloneContext& context)
 }
 
 RenderState::StateBlock::StateBlock()
-    : _blendEnabled(false), _cullFaceEnabled(false), _depthTestEnabled(false), _depthWriteEnabled(false),
-      _srcBlend(RenderState::BLEND_ONE), _dstBlend(RenderState::BLEND_ONE), _bits(0L)
+    : _cullFaceEnabled(false), _depthTestEnabled(false), _depthWriteEnabled(false),
+      _blendEnabled(false), _blendSrc(RenderState::BLEND_ONE), _blendDst(RenderState::BLEND_ONE),
+      _bits(0L)
 {
 }
 
@@ -404,11 +405,11 @@ void RenderState::StateBlock::bindNoRestore()
             GL_ASSERT( glDisable(GL_BLEND) );
         _defaultState->_blendEnabled = _blendEnabled;
     }
-    if ((_bits & RS_BLEND_FUNC) && (_srcBlend != _defaultState->_srcBlend || _dstBlend != _defaultState->_dstBlend))
+    if ((_bits & RS_BLEND_FUNC) && (_blendSrc != _defaultState->_blendSrc || _blendDst != _defaultState->_blendDst))
     {
-        GL_ASSERT( glBlendFunc((GLenum)_srcBlend, (GLenum)_dstBlend) );
-        _defaultState->_srcBlend = _srcBlend;
-        _defaultState->_dstBlend = _dstBlend;
+        GL_ASSERT( glBlendFunc((GLenum)_blendSrc, (GLenum)_blendDst) );
+        _defaultState->_blendSrc = _blendSrc;
+        _defaultState->_blendDst = _blendDst;
     }
     if ((_bits & RS_CULL_FACE) && (_cullFaceEnabled != _defaultState->_cullFaceEnabled))
     {
@@ -456,8 +457,8 @@ void RenderState::StateBlock::restore(long stateOverrideBits)
     {
         GL_ASSERT( glBlendFunc(GL_ONE, GL_ONE) );
         _defaultState->_bits &= ~RS_BLEND_FUNC;
-        _defaultState->_srcBlend = RenderState::BLEND_ONE;
-        _defaultState->_dstBlend = RenderState::BLEND_ONE;
+        _defaultState->_blendSrc = RenderState::BLEND_ONE;
+        _defaultState->_blendDst = RenderState::BLEND_ONE;
     }
     if (!(stateOverrideBits & RS_CULL_FACE) && (_defaultState->_bits & RS_CULL_FACE))
     {
@@ -550,11 +551,11 @@ void RenderState::StateBlock::setState(const char* name, const char* value)
     {
         setBlend(parseBoolean(value));
     }
-    else if (strcmp(name, "srcBlend") == 0)
+    else if (strcmp(name, "blendSrc") == 0 || strcmp(name, "srcBlend") == 0 )   // Leaving srcBlend for backward compat.
     {
         setBlendSrc(parseBlend(value));
     }
-    else if (strcmp(name, "dstBlend") == 0)
+    else if (strcmp(name, "blendDst") == 0 || strcmp(name, "dstBlend") == 0)    // // Leaving dstBlend for backward compat.
     {
         setBlendDst(parseBlend(value));
     }
@@ -591,8 +592,8 @@ void RenderState::StateBlock::setBlend(bool enabled)
 
 void RenderState::StateBlock::setBlendSrc(Blend blend)
 {
-    _srcBlend = blend;
-    if (_srcBlend == BLEND_ONE && _dstBlend == BLEND_ONE)
+    _blendSrc = blend;
+    if (_blendSrc == BLEND_ONE && _blendDst == BLEND_ONE)
     {
         _bits &= ~RS_BLEND_FUNC;
     }
@@ -604,8 +605,8 @@ void RenderState::StateBlock::setBlendSrc(Blend blend)
 
 void RenderState::StateBlock::setBlendDst(Blend blend)
 {
-    _dstBlend = blend;
-    if (_srcBlend == BLEND_ONE && _dstBlend == BLEND_ONE)
+    _blendDst = blend;
+    if (_blendSrc == BLEND_ONE && _blendDst == BLEND_ONE)
     {
         _bits &= ~RS_BLEND_FUNC;
     }

+ 3 - 4
gameplay/src/RenderState.h

@@ -213,13 +213,12 @@ public:
         static void enableDepthWrite();
 
         // States
-        bool _blendEnabled;
         bool _cullFaceEnabled;
         bool _depthTestEnabled;
         bool _depthWriteEnabled;
-        Blend _srcBlend;
-        Blend _dstBlend;
-        // State bits
+        bool _blendEnabled;
+        Blend _blendSrc;
+        Blend _blendDst;
         long _bits;
 
         static StateBlock* _defaultState;

+ 74 - 2
gameplay/src/Slider.cpp

@@ -3,6 +3,9 @@
 namespace gameplay
 {
 
+// Fraction of slider to scroll when mouse scrollwheel is used.
+static const float SCROLL_FRACTION = 0.1f;
+
 Slider::Slider() : _minImage(NULL), _maxImage(NULL), _trackImage(NULL), _markerImage(NULL)
 {
 }
@@ -11,6 +14,18 @@ Slider::~Slider()
 {
 }
 
+Slider* Slider::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    Slider* slider = new Slider();
+    if (id)
+        slider->_id = id;
+    slider->setStyle(style);
+
+    return slider;
+}
+
 Slider* Slider::create(Theme::Style* style, Properties* properties)
 {
     GP_ASSERT(properties);
@@ -133,13 +148,65 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
 
         if (evt == Touch::TOUCH_RELEASE)
         {
-            _state = NORMAL;
+            _state = FOCUS;
             _dirty = true;
         }
         break;
     }
+    
+    if (evt == Touch::TOUCH_MOVE)
+        return _consumeInputEvents;
+    else
+        return Control::touchEvent(evt, x, y, contactIndex);
+}
+
+bool Slider::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+{
+    if (!isEnabled())
+    {
+        return false;
+    }
 
-    return Control::touchEvent(evt, x, y, contactIndex);
+    switch (evt)
+    {
+        case Mouse::MOUSE_PRESS_LEFT_BUTTON:
+            return touchEvent(Touch::TOUCH_PRESS, x, y, 0);
+
+        case Mouse::MOUSE_MOVE:
+            return touchEvent(Touch::TOUCH_MOVE, x, y, 0);
+
+        case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
+            return touchEvent(Touch::TOUCH_RELEASE, x, y, 0);
+
+        case Mouse::MOUSE_WHEEL:
+        {
+            if (_state == FOCUS)
+            {
+                float total = _max - _min;
+                float oldValue = _value;
+                _value += (total * SCROLL_FRACTION) * wheelDelta;
+            
+                if (_value > _max)
+                    _value = _max;
+                else if (_value < _min)
+                    _value = _min;
+
+                if (_value != oldValue)
+                {
+                    notifyListeners(Listener::VALUE_CHANGED);
+                }
+
+                _dirty = true;
+                return _consumeInputEvents;
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    return false;
 }
 
 void Slider::update(const Control* container, const Vector2& offset)
@@ -208,4 +275,9 @@ void Slider::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _viewportClipBounds);
 }
 
+const char* Slider::getType() const
+{
+    return "slider";
+}
+
 }

+ 29 - 0
gameplay/src/Slider.h

@@ -35,6 +35,16 @@ class Slider : public Label
 
 public:
 
+    /**
+     * Create a new slider control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new slider.
+     */
+    static Slider* create(const char* id, Theme::Style* style);
+
     /**
      * Set the minimum value that can be set on this slider.
      *
@@ -93,6 +103,11 @@ public:
      */
     float getValue();
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -141,6 +156,20 @@ protected:
      */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Mouse callback on mouse events.
+     *
+     * @param evt The mouse event that occurred.
+     * @param x The x position of the mouse in pixels. Left edge is zero.
+     * @param y The y position of the mouse in pixels. Top edge is zero.
+     * @param wheelDelta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
+     *
+     * @return True if the mouse event is consumed or false if it is not consumed.
+     *
+     * @see Mouse::MouseEvent
+     */
+    bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
+
     /**
      * Draw the images associated with this control.
      *

+ 24 - 49
gameplay/src/SpriteBatch.cpp

@@ -9,7 +9,7 @@
 #define SPRITE_BATCH_GROW_FACTOR 2.0f
 
 // Macro for adding a sprite to the batch
-#define ADD_SPRITE_VERTEX(vtx, vx, vy, vz, vu, vv, vr, vg, vb, va) \
+#define SPRITE_ADD_VERTEX(vtx, vx, vy, vz, vu, vv, vr, vg, vb, va) \
     vtx.x = vx; vtx.y = vy; vtx.z = vz; \
     vtx.u = vu; vtx.v = vv; \
     vtx.r = vr; vtx.g = vg; vtx.b = vb; vtx.a = va
@@ -45,7 +45,6 @@
 namespace gameplay
 {
 
-// Shared sprite effects
 static Effect* __spriteEffect = NULL;
 
 SpriteBatch::SpriteBatch()
@@ -63,13 +62,15 @@ SpriteBatch::~SpriteBatch()
     SAFE_DELETE(_batch);
     if (!_customEffect)
     {
-        if (__spriteEffect->getRefCount() == 1)
+        if (__spriteEffect && __spriteEffect->getRefCount() == 1)
         {
             __spriteEffect->release();
             __spriteEffect = NULL;
         }
         else
+        {
             __spriteEffect->release();
+        }
     }
 }
 
@@ -97,7 +98,6 @@ SpriteBatch* SpriteBatch::create(Texture* texture, Effect* effect, unsigned int
                 GP_ERROR("Unable to load sprite effect.");
                 return NULL;
             }
-
             effect = __spriteEffect;
         }
         else
@@ -242,10 +242,10 @@ void SpriteBatch::draw(float x, float y, float z, float width, float height, flo
 
     // Write sprite vertex data.
     static SpriteVertex v[4];
-    ADD_SPRITE_VERTEX(v[0], downLeft.x, downLeft.y, z, u1, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[1], upLeft.x, upLeft.y, z, u1, v2, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[2], downRight.x, downRight.y, z, u2, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[3], upRight.x, upRight.y, z, u2, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[0], downLeft.x, downLeft.y, z, u1, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[1], upLeft.x, upLeft.y, z, u1, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[2], downRight.x, downRight.y, z, u2, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[3], upRight.x, upRight.y, z, u2, v2, color.x, color.y, color.z, color.w);
     
     static unsigned short indices[4] = { 0, 1, 2, 3 };
 
@@ -256,17 +256,6 @@ void SpriteBatch::draw(const Vector3& position, const Vector3& right, const Vect
     float u1, float v1, float u2, float v2, const Vector4& color, const Vector2& rotationPoint, float rotationAngle)
 {
     // Calculate the vertex positions.
-    //static Vector3 p[4];
-
-    // Pre-optimized:
-    /*
-    p[0] = position - 0.5f * width * right - 0.5f * height * forward;
-    p[1] = position + 0.5f * width * right - 0.5f * height * forward;
-    p[2] = p[0] + height * forward;
-    p[3] = p[1] + height * forward;
-    */
-    
-    // Optimized:
     Vector3 tRight(right);
     tRight *= width * 0.5f;
     Vector3 tForward(forward);
@@ -288,11 +277,6 @@ void SpriteBatch::draw(const Vector3& position, const Vector3& right, const Vect
     p3 += tForward;
 
     // Calculate the rotation point.
-    
-    // Pre-optimized:
-    //Vector3 rp = p[0] + (rotationPoint.x * width * right) + (rotationPoint.y * height * forward);
-
-    // Optimized:
     Vector3 rp = p0;
     tRight = right;
     tRight *= width * rotationPoint.x;
@@ -306,15 +290,6 @@ void SpriteBatch::draw(const Vector3& position, const Vector3& right, const Vect
     static Matrix rotation;
     Matrix::createRotation(u, rotationAngle, &rotation);
 
-    // Pre-optimized:
-    /*
-    p[0] = (rotation * (p[0] - rp)) + rp;
-    p[1] = (rotation * (p[1] - rp)) + rp;
-    p[2] = (rotation * (p[2] - rp)) + rp;
-    p[3] = (rotation * (p[3] - rp)) + rp;
-    */
-
-    // Optimized:
     p0 -= rp;
     p0 *= rotation;
     p0 += rp;
@@ -333,10 +308,10 @@ void SpriteBatch::draw(const Vector3& position, const Vector3& right, const Vect
 
     // Add the sprite vertex data to the batch.
     static SpriteVertex v[4];
-    ADD_SPRITE_VERTEX(v[0], p0.x, p0.y, p0.z, u1, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[1], p1.x, p1.y, p1.z, u2, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[2], p2.x, p2.y, p2.z, u1, v2, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[3], p3.x, p3.y, p3.z, u2, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[0], p0.x, p0.y, p0.z, u1, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[1], p1.x, p1.y, p1.z, u2, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[2], p2.x, p2.y, p2.z, u1, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[3], p3.x, p3.y, p3.z, u2, v2, color.x, color.y, color.z, color.w);
     
     static const unsigned short indices[4] = { 0, 1, 2, 3 };
     _batch->add(v, 4, const_cast<unsigned short*>(indices), 4);
@@ -360,10 +335,10 @@ void SpriteBatch::addSprite(float x, float y, float width, float height, float u
 
     const float x2 = x + width;
     const float y2 = y + height;
-    ADD_SPRITE_VERTEX(vertices[0], x, y, 0, u1, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(vertices[1], x, y2, 0, u1, v2, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(vertices[2], x2, y, 0, u2, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(vertices[3], x2, y2, 0, u2, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(vertices[0], x, y, 0, u1, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(vertices[1], x, y2, 0, u1, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(vertices[2], x2, y, 0, u2, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(vertices[3], x2, y2, 0, u2, v2, color.x, color.y, color.z, color.w);
 }
 
 void SpriteBatch::addSprite(float x, float y, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color, const Rectangle& clip, SpriteBatch::SpriteVertex* vertices)
@@ -375,10 +350,10 @@ void SpriteBatch::addSprite(float x, float y, float width, float height, float u
     {
         const float x2 = x + width;
         const float y2 = y + height;
-        ADD_SPRITE_VERTEX(vertices[0], x, y, 0, u1, v1, color.x, color.y, color.z, color.w);
-        ADD_SPRITE_VERTEX(vertices[1], x, y2, 0, u1, v2, color.x, color.y, color.z, color.w);
-        ADD_SPRITE_VERTEX(vertices[2], x2, y, 0, u2, v1, color.x, color.y, color.z, color.w);
-        ADD_SPRITE_VERTEX(vertices[3], x2, y2, 0, u2, v2, color.x, color.y, color.z, color.w);
+        SPRITE_ADD_VERTEX(vertices[0], x, y, 0, u1, v1, color.x, color.y, color.z, color.w);
+        SPRITE_ADD_VERTEX(vertices[1], x, y2, 0, u1, v2, color.x, color.y, color.z, color.w);
+        SPRITE_ADD_VERTEX(vertices[2], x2, y, 0, u2, v1, color.x, color.y, color.z, color.w);
+        SPRITE_ADD_VERTEX(vertices[3], x2, y2, 0, u2, v2, color.x, color.y, color.z, color.w);
     }
 }
 
@@ -403,10 +378,10 @@ void SpriteBatch::draw(float x, float y, float z, float width, float height, flo
     const float x2 = x + width;
     const float y2 = y + height;
     static SpriteVertex v[4];
-    ADD_SPRITE_VERTEX(v[0], x, y, z, u1, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[1], x, y2, z, u1, v2, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[2], x2, y, z, u2, v1, color.x, color.y, color.z, color.w);
-    ADD_SPRITE_VERTEX(v[3], x2, y2, z, u2, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[0], x, y, z, u1, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[1], x, y2, z, u1, v2, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[2], x2, y, z, u2, v1, color.x, color.y, color.z, color.w);
+    SPRITE_ADD_VERTEX(v[3], x2, y2, z, u2, v2, color.x, color.y, color.z, color.w);
 
     static unsigned short indices[4] = { 0, 1, 2, 3 };
 

+ 60 - 25
gameplay/src/TextBox.cpp

@@ -16,6 +16,18 @@ TextBox::~TextBox()
 {
 }
 
+TextBox* TextBox::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    TextBox* textBox = new TextBox();
+    if (id)
+        textBox->_id = id;
+    textBox->setStyle(style);
+
+    return textBox;
+}
+
 TextBox* TextBox::create(Theme::Style* style, Properties* properties)
 {
     TextBox* textBox = new TextBox();
@@ -49,36 +61,35 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
     switch (evt)
     {
     case Touch::TOUCH_PRESS: 
-        if (_state == NORMAL)
-        {
-            _state = ACTIVE;
-            Game::getInstance()->displayKeyboard(true);
-            _dirty = true;
-            return _consumeInputEvents;
-        }
-        else if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
                  y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
         {
-            setCaretLocation(x, y);
+            _contactIndex = (int) contactIndex;
+
+            if (_state == NORMAL)
+                Game::getInstance()->displayKeyboard(true);
+            else
+                setCaretLocation(x, y);
+
+            _state = ACTIVE;
             _dirty = true;
-            return _consumeInputEvents;
         }
         else
         {
+            _contactIndex = INVALID_CONTACT_INDEX;
             _state = NORMAL;
             Game::getInstance()->displayKeyboard(false);
             _dirty = true;
-            return _consumeInputEvents;
+            return false;
         }
         break;
     case Touch::TOUCH_MOVE:
-        if (_state == FOCUS &&
+        if (_state == ACTIVE &&
             x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
             y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
         {
             setCaretLocation(x, y);
             _dirty = true;
-            return _consumeInputEvents;
         }
         break;
     case Touch::TOUCH_RELEASE:
@@ -87,16 +98,14 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
         {
             setCaretLocation(x, y);
             _state = FOCUS;
-            _dirty = true;
-            return _consumeInputEvents;
         }
         else
         {
             _state = NORMAL;
             Game::getInstance()->displayKeyboard(false);
-            _dirty = true;
-            return _consumeInputEvents;
         }
+        _contactIndex = INVALID_CONTACT_INDEX;
+        _dirty = true;
         break;
     }
 
@@ -156,7 +165,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
 
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                        int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
                         font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex - 1,
                             textAlignment, true, rightToLeft);
@@ -187,10 +196,15 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         unsigned int fontSize = getFontSize(_state);
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
-
+                        _prevCaretLocation.set(_caretLocation);
                         _caretLocation.y -= fontSize;
-                        font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                        int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
+                        if (textIndex == -1)
+                        {
+                            _caretLocation.set(_prevCaretLocation);
+                        }
+
                         _dirty = true;
                         consume = true;
                         break;
@@ -202,10 +216,15 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         unsigned int fontSize = getFontSize(_state);
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
-
+                        _prevCaretLocation.set(_caretLocation);
                         _caretLocation.y += fontSize;
-                        font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                        int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
+                        if (textIndex == -1)
+                        {
+                            _caretLocation.set(_prevCaretLocation);
+                        }
+
                         _dirty = true;
                         consume = true;
                         break;
@@ -224,6 +243,12 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
 
                 int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                     textAlignment, true, rightToLeft);
+                if (textIndex == -1)
+                {
+                    textIndex = 0;
+                    font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, 0,
+                        textAlignment, true, rightToLeft);
+                }
 
                 switch (key)
                 {
@@ -237,13 +262,17 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                                 textAlignment, true, rightToLeft);
 
                             _dirty = true;
-                            consume = true;
                         }
+                        consume = true;
                         break;
                     }
                     case Keyboard::KEY_RETURN:
                         // TODO: Handle line-break insertion correctly.
                         break;
+                    case Keyboard::KEY_ESCAPE:
+                        break;
+                    case Keyboard::KEY_TAB:
+                        break;
                     default:
                     {
                         // Insert character into string.
@@ -293,6 +322,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                 }
 
                 notifyListeners(Listener::TEXT_CHANGED);
+                break;
             }
         }
     }
@@ -312,7 +342,7 @@ void TextBox::update(const Control* container, const Vector2& offset)
 
 void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
 {
-    if (_state == FOCUS)
+    if (_state == ACTIVE || _state == FOCUS)
     {
         // Draw the cursor at its current location.
         GP_ASSERT(_caretImage);
@@ -352,4 +382,9 @@ void TextBox::setCaretLocation(int x, int y)
     }
 }
 
-}
+const char* TextBox::getType() const
+{
+    return "textBox";
+}
+
+}

+ 16 - 1
gameplay/src/TextBox.h

@@ -39,6 +39,16 @@ class TextBox : public Label
 
 public:
 
+    /**
+     * Create a new text box control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new text box.
+     */
+    static TextBox* create(const char* id, Theme::Style* style);
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -58,6 +68,11 @@ public:
      */
     int getLastKeypress();
 
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
 protected:
 
     /**
@@ -165,4 +180,4 @@ private:
 
 }
 
-#endif
+#endif

+ 3 - 1
gameplay/src/Texture.h

@@ -99,7 +99,9 @@ public:
         void setFilterMode(Filter minificationFilter, Filter magnificationFilter);
 
         /**
-         * Returns the texture for this sampler.
+         * Gets the texture for this sampler.
+         *
+         * @return The texture for this sampler.
          */
         Texture* getTexture() const;
 

+ 29 - 17
gameplay/src/Theme.h

@@ -135,7 +135,6 @@ namespace gameplay
 class Theme: public Ref
 {
     friend class Control;
-    friend class Container;
     friend class Form;
     friend class Skin;
 
@@ -294,6 +293,35 @@ public:
         Vector4 _color;
     };
 
+    /**
+     * Creates a theme using the data from the Properties object defined at the specified URL, 
+     * where the URL is of the format "<file-path>.<extension>#<namespace-id>/<namespace-id>/.../<namespace-id>"
+     * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional). 
+     * 
+     * @param url The URL pointing to the Properties object defining the theme. 
+     */
+    static Theme* create(const char* url);
+
+    /**
+     * Get a style by its ID.
+     *
+     * @param id The style ID.
+     *
+     * @return The style with the specified ID, or NULL if it does not exist.
+     */
+    Theme::Style* getStyle(const char* id) const;
+
+    /**
+     * Get the empty style.  Used when a control does not specify a style.
+     * This is especially useful for containers that are being used only for
+     * layout and positioning, and have no background or border themselves.
+     * The empty style has no border, background, margin, padding, images, etc..
+     * Any needed properties can be set on the control directly.
+     *
+     * @return The empty style.
+     */
+    Theme::Style* getEmptyStyle();
+
 private:
 
     /**
@@ -406,22 +434,6 @@ private:
      */
     ~Theme();
 
-    /**
-     * Creates an instance of a Theme using the data from the Properties object defined at the specified URL, 
-     * where the URL is of the format "<file-path>.<extension>#<namespace-id>/<namespace-id>/.../<namespace-id>"
-     * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional). 
-     * 
-     * @param url The URL pointing to the Properties object defining the theme.
-     *
-     * @return A new Theme.
-     */
-    static Theme* create(const char* url);
-
-    Theme::Style* getStyle(const char* id) const;
-
-    // Used when a control does not specify a style.
-    Theme::Style* getEmptyStyle();
-
     void setProjectionMatrix(const Matrix& matrix);
 
     SpriteBatch* getSpriteBatch() const;

+ 5 - 0
gameplay/src/ThemeStyle.cpp

@@ -39,6 +39,11 @@ Theme::Style::~Style()
         SAFE_RELEASE(_overlays[i]);
     }
 }
+
+Theme* Theme::Style::getTheme() const
+{
+    return _theme;
+}
     
 const char* Theme::Style::getId() const
 {

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