Explorar el Código

GamePlay v1.0.1
Added new material functionality now supporting techniques, passes, render state's and texture sampler definitions.
Added support for loading from .material, .animation and .particle files.
Added support for point and spot lights.
Added tutorials for sample01-longboard and sample02-spaceship.
Various other minor enhancements and bug fixes.

Sean Paul Taylor hace 14 años
padre
commit
65ee2544e0
Se han modificado 100 ficheros con 3767 adiciones y 1499 borrados
  1. 19 18
      README.md
  2. 14 15
      gameplay-encoder/gameplay-binary.txt
  3. 8 0
      gameplay-encoder/gameplay-encoder.vcxproj
  4. 12 0
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  5. 2 1
      gameplay-encoder/gameplay-encoder.vcxproj.user
  6. 9 8
      gameplay-encoder/src/Animation.cpp
  7. 1 1
      gameplay-encoder/src/Animation.h
  8. 28 23
      gameplay-encoder/src/AnimationChannel.cpp
  9. 13 12
      gameplay-encoder/src/AnimationChannel.h
  10. 54 0
      gameplay-encoder/src/Animations.cpp
  11. 39 0
      gameplay-encoder/src/Animations.h
  12. 2 0
      gameplay-encoder/src/Base.cpp
  13. 32 32
      gameplay-encoder/src/Camera.cpp
  14. 11 12
      gameplay-encoder/src/Camera.h
  15. 13 7
      gameplay-encoder/src/CameraInstance.cpp
  16. 1 1
      gameplay-encoder/src/CameraInstance.h
  17. 15 16
      gameplay-encoder/src/DAEChannelTarget.cpp
  18. 9 9
      gameplay-encoder/src/DAEChannelTarget.h
  19. 125 0
      gameplay-encoder/src/DAEOptimizer.cpp
  20. 63 0
      gameplay-encoder/src/DAEOptimizer.h
  21. 0 17
      gameplay-encoder/src/DAEPolygonInput.cpp
  22. 0 23
      gameplay-encoder/src/DAEPolygonInput.h
  23. 237 256
      gameplay-encoder/src/DAESceneEncoder.cpp
  24. 32 27
      gameplay-encoder/src/DAESceneEncoder.h
  25. 303 0
      gameplay-encoder/src/DAEUtil.cpp
  26. 126 0
      gameplay-encoder/src/DAEUtil.h
  27. 4 4
      gameplay-encoder/src/Effect.cpp
  28. 3 2
      gameplay-encoder/src/Effect.h
  29. 275 0
      gameplay-encoder/src/EncoderArguments.cpp
  30. 120 0
      gameplay-encoder/src/EncoderArguments.h
  31. 12 0
      gameplay-encoder/src/FileIO.cpp
  32. 1 0
      gameplay-encoder/src/FileIO.h
  33. 20 20
      gameplay-encoder/src/GPBDecoder.cpp
  34. 2 2
      gameplay-encoder/src/GPBDecoder.h
  35. 48 67
      gameplay-encoder/src/GPBFile.cpp
  36. 17 16
      gameplay-encoder/src/GPBFile.h
  37. 142 49
      gameplay-encoder/src/Light.cpp
  38. 16 9
      gameplay-encoder/src/Light.h
  39. 12 9
      gameplay-encoder/src/LightInstance.cpp
  40. 1 1
      gameplay-encoder/src/LightInstance.h
  41. 5 5
      gameplay-encoder/src/Material.cpp
  42. 3 2
      gameplay-encoder/src/Material.h
  43. 5 5
      gameplay-encoder/src/MaterialParameter.cpp
  44. 3 2
      gameplay-encoder/src/MaterialParameter.h
  45. 7 3
      gameplay-encoder/src/Matrix.cpp
  46. 5 5
      gameplay-encoder/src/Matrix.h
  47. 6 4
      gameplay-encoder/src/Mesh.cpp
  48. 2 1
      gameplay-encoder/src/Mesh.h
  49. 20 16
      gameplay-encoder/src/MeshPart.cpp
  50. 3 3
      gameplay-encoder/src/MeshPart.h
  51. 18 58
      gameplay-encoder/src/MeshSkin.cpp
  52. 6 24
      gameplay-encoder/src/MeshSkin.h
  53. 19 15
      gameplay-encoder/src/Model.cpp
  54. 4 3
      gameplay-encoder/src/Model.h
  55. 38 34
      gameplay-encoder/src/Node.cpp
  56. 6 5
      gameplay-encoder/src/Node.h
  57. 0 49
      gameplay-encoder/src/NodeInstance.cpp
  58. 0 28
      gameplay-encoder/src/NodeInstance.h
  59. 16 8
      gameplay-encoder/src/Object.cpp
  60. 17 8
      gameplay-encoder/src/Object.h
  61. 2 0
      gameplay-encoder/src/Quaternion.h
  62. 17 17
      gameplay-encoder/src/Reference.cpp
  63. 6 4
      gameplay-encoder/src/Reference.h
  64. 9 9
      gameplay-encoder/src/ReferenceTable.cpp
  65. 14 1
      gameplay-encoder/src/ReferenceTable.h
  66. 19 19
      gameplay-encoder/src/Scene.cpp
  67. 4 3
      gameplay-encoder/src/Scene.h
  68. 32 1
      gameplay-encoder/src/StringUtil.cpp
  69. 1 0
      gameplay-encoder/src/StringUtil.h
  70. 14 2
      gameplay-encoder/src/TTFFontEncoder.cpp
  71. 1 1
      gameplay-encoder/src/TTFFontEncoder.h
  72. 7 0
      gameplay-encoder/src/Vector2.h
  73. 5 0
      gameplay-encoder/src/Vector3.h
  74. 5 0
      gameplay-encoder/src/Vector4.h
  75. 1 1
      gameplay-encoder/src/Vertex.h
  76. 21 169
      gameplay-encoder/src/main.cpp
  77. 99 26
      gameplay-resources/res/shaders/bumped-specular.fsh
  78. 79 17
      gameplay-resources/res/shaders/bumped-specular.vsh
  79. 90 20
      gameplay-resources/res/shaders/bumped.fsh
  80. 82 19
      gameplay-resources/res/shaders/bumped.vsh
  81. 95 21
      gameplay-resources/res/shaders/colored-specular.fsh
  82. 166 9
      gameplay-resources/res/shaders/colored-specular.vsh
  83. 86 12
      gameplay-resources/res/shaders/colored.fsh
  84. 165 7
      gameplay-resources/res/shaders/colored.vsh
  85. 96 25
      gameplay-resources/res/shaders/diffuse-specular.fsh
  86. 164 9
      gameplay-resources/res/shaders/diffuse-specular.vsh
  87. 85 11
      gameplay-resources/res/shaders/diffuse.fsh
  88. 169 10
      gameplay-resources/res/shaders/diffuse.vsh
  89. 8 8
      gameplay-resources/res/shaders/parallax-specular.fsh
  90. 11 11
      gameplay-resources/res/shaders/parallax-specular.vsh
  91. 7 7
      gameplay-resources/res/shaders/parallax.fsh
  92. 11 11
      gameplay-resources/res/shaders/parallax.vsh
  93. 3 3
      gameplay-resources/res/shaders/textured.fsh
  94. 65 5
      gameplay-resources/res/shaders/textured.vsh
  95. BIN
      gameplay-tutorials/sample01-longboard.pdf
  96. BIN
      gameplay-tutorials/sample02-spaceship.pdf
  97. 0 7
      gameplay/.cproject
  98. 6 3
      gameplay/gameplay.vcxproj
  99. 24 12
      gameplay/gameplay.vcxproj.filters
  100. 74 84
      gameplay/src/Animation.cpp

+ 19 - 18
README.md

@@ -1,18 +1,19 @@
-# GamePlay
-
-The _**GamePlay**_ repository holds the sources for GamePlay, an open-source, cross-platform 3D native gaming framework that makes it easy to learn and write mobile and desktop games.  The repository includes samples.
-
-
-**Repository Committers** 
-
-* [Sean Paul Taylor](https://github.com/seanpaultaylor)
-
-
-## Bug Reporting and Feature Requests
-
-If you find a bug in a Sample, or have an enhancement request, simply file an [Issue](https://github.com/blackberry/GamePlay/issues) and send a message (via github messages) to the Committers to the project to let them know that you have filed an [Issue](https://github.com/blackberry/GamePlay/issues).
-
-## Disclaimer
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+GamePlay v1.0.1
+---------------
+GamePlay is a open-source, cross-platform 3D native gaming framework making it easy to learn and write mobile and desktop games. 
+
+Supported platforms
+-------------------
+Microsoft Windows 7 (using Microsoft Visual Studio 2010)
+BlackBerry PlayBook 1.0/2.0 (using BlackBerry Native SDK 1.0)
+
+Roadmap
+-------
+- Apple Mac OS X support (using XCode 4.0)
+- Physics support with Bullet Physics
+- Encoded audio support with Ogg Vorbis
+- FrameBuffer's (RenderTarget + DepthStencilTarget)
+- UI Forms
+- Shadow and Light map generation.
+- Spatial Partitioning with Octree (Visibility Testing and Light Determination)
+

+ 14 - 15
gameplay-encoder/gameplay-binary.txt

@@ -142,13 +142,17 @@ Reference
                 light                   Light
                 model                   Model
 ------------------------------------------------------------------------------------------------------
-3->Animation
+3->Animations
+                animations              Animation[]
+------------------------------------------------------------------------------------------------------
+4->Animation
+                id                      string
                 channels                AnimationChannel[]
 -----------------------------------------------------------------------------------------------------
-4->AnimationChannel
+5->AnimationChannel
                 targetId                string
                 targetAttribute         uint
-                keyTimes                float[]  (milliseconds)
+                keyTimes                unsigned long[]  (milliseconds)
                 values                  float[]
                 tangents_in             float[]
                 tangents_out            float[]
@@ -180,19 +184,15 @@ Reference
                 ]
 ------------------------------------------------------------------------------------------------------
 33->Light
-                lightType               byte {ambient|directional|spot|point}
+                lightType               byte {directional|point|spot}
                 color                   float[3]
-                [ lightType : spot
-                  constantAttenuation   float
-                  linearAttenuation     float
-                  quadraticAttenuation  float
-                  falloffAngle          float
-                  falloffExponent       float
-                ]
                 [ lightType : point
-                  constantAttenuation   float
-                  linearAttenuation     float
-                  quadraticAttenuation  float
+                  range                 float
+                ]
+                [ lightType : spot
+                  range                 float 
+                  innerAngle            float (in radians)
+                  outerAngle            float (in radians)
                 ]
 ------------------------------------------------------------------------------------------------------
 34->Mesh
@@ -209,7 +209,6 @@ Reference
 ------------------------------------------------------------------------------------------------------
 36->MeshSkin
                 bindShape               float[16]
-                rootJoint               string
                 joints                  xref:Node[]
                 jointsBindPoses         float[] // 16 * joints.length
 ------------------------------------------------------------------------------------------------------

+ 8 - 0
gameplay-encoder/gameplay-encoder.vcxproj

@@ -16,14 +16,18 @@
     <ClCompile Include="src\Base.cpp" />
     <ClCompile Include="src\Camera.cpp" />
     <ClCompile Include="src\CameraInstance.cpp" />
+    <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\DAEChannelTarget.cpp" />
+    <ClCompile Include="src\DAEOptimizer.cpp" />
     <ClCompile Include="src\DAESceneEncoder.cpp" />
+    <ClCompile Include="src\DAEUtil.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\FileIO.cpp" />
     <ClCompile Include="src\Font.cpp" />
     <ClCompile Include="src\GPBFile.cpp" />
     <ClCompile Include="src\Glyph.cpp" />
     <ClCompile Include="src\GPBDecoder.cpp" />
+    <ClCompile Include="src\Animations.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\LightInstance.cpp" />
     <ClCompile Include="src\main.cpp" />
@@ -55,14 +59,18 @@
     <ClInclude Include="src\Base.h" />
     <ClInclude Include="src\Camera.h" />
     <ClInclude Include="src\CameraInstance.h" />
+    <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\DAEChannelTarget.h" />
+    <ClInclude Include="src\DAEOptimizer.h" />
     <ClInclude Include="src\DAESceneEncoder.h" />
+    <ClInclude Include="src\DAEUtil.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\FileIO.h" />
     <ClInclude Include="src\Font.h" />
     <ClInclude Include="src\GPBFile.h" />
     <ClInclude Include="src\Glyph.h" />
     <ClInclude Include="src\GPBDecoder.h" />
+    <ClInclude Include="src\Animations.h" />
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\LightInstance.h" />
     <ClInclude Include="src\Material.h" />

+ 12 - 0
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -90,6 +90,12 @@
     <ClCompile Include="src\Matrix.cpp">
       <Filter>Math</Filter>
     </ClCompile>
+    <ClCompile Include="src\DAEOptimizer.cpp" />
+    <ClCompile Include="src\DAEUtil.cpp" />
+    <ClCompile Include="src\EncoderArguments.cpp" />
+    <ClCompile Include="src\Animations.cpp">
+      <Filter>Objects\Animation</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\DAESceneEncoder.h" />
@@ -180,6 +186,12 @@
     <ClInclude Include="src\Matrix.h">
       <Filter>Math</Filter>
     </ClInclude>
+    <ClInclude Include="src\DAEOptimizer.h" />
+    <ClInclude Include="src\DAEUtil.h" />
+    <ClInclude Include="src\EncoderArguments.h" />
+    <ClInclude Include="src\Animations.h">
+      <Filter>Objects\Animation</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="Objects">

+ 2 - 1
gameplay-encoder/gameplay-encoder.vcxproj.user

@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <LocalDebuggerCommandArguments>C:\svn\gaming\gameplay\gameplay-samples\sample03-character\res\meshes\test_Collada_DAE.dae</LocalDebuggerCommandArguments>
+    <LocalDebuggerCommandArguments>
+    </LocalDebuggerCommandArguments>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
   </PropertyGroup>
 </Project>

+ 9 - 8
gameplay-encoder/src/Animation.cpp

@@ -23,20 +23,21 @@ const char* Animation::getElementName(void) const
 void Animation::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    // Write AnimationChannels
-    write(channels.size(), file);
-    for (std::vector<AnimationChannel*>::iterator i = channels.begin(); i != channels.end(); i++)
+    // Animation writes its ID because it is not listed in the ref table.
+    write(getId(), file);
+    write(_channels.size(), file);
+    for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); i++)
     {
         (*i)->writeBinary(file);
     }
 }
 
 void Animation::writeText(FILE* file)
-{   
+{
     fprintElementStart(file);
-    if (channels.size() > 0 )
+    if (_channels.size() > 0 )
     {
-        for (std::vector<AnimationChannel*>::iterator i = channels.begin(); i != channels.end(); i++)
+        for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); i++)
         {
             (*i)->writeText(file);
         }
@@ -46,12 +47,12 @@ void Animation::writeText(FILE* file)
 
 void Animation::add(AnimationChannel* animationChannel)
 {
-    channels.push_back(animationChannel);
+    _channels.push_back(animationChannel);
 }
 
 unsigned int Animation::getAnimationChannelCount() const
 {
-    return channels.size();
+    return _channels.size();
 }
 
 }

+ 1 - 1
gameplay-encoder/src/Animation.h

@@ -35,7 +35,7 @@ public:
     unsigned int getAnimationChannelCount() const;
 
 private:
-    std::vector<AnimationChannel*> channels;
+    std::vector<AnimationChannel*> _channels;
 };
 
 }

+ 28 - 23
gameplay-encoder/src/AnimationChannel.cpp

@@ -4,7 +4,7 @@ namespace gameplay
 {
 
 AnimationChannel::AnimationChannel(void) :
-    targetAttrib(0)
+    _targetAttrib(0)
 {
 }
 
@@ -24,66 +24,71 @@ const char* AnimationChannel::getElementName(void) const
 void AnimationChannel::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    write(targetId, file);
-    write(targetAttrib, file);
-    write(keytimes, file);
-    write(keyValues, file);
-    write(tangentsIn, file);
-    write(tangentsOut, file);
-    write(interpolations, file);
+    write(_targetId, file);
+    write(_targetAttrib, file);
+    write(_keytimes.size(), file);
+    for (std::vector<float>::const_iterator i = _keytimes.begin(); i != _keytimes.end(); i++)
+    {
+        write((unsigned long)*i, file);
+    }
+    write(_keyValues, file);
+    write(_tangentsIn, file);
+    write(_tangentsOut, file);
+    write(_interpolations, file);
+
 }
 
 void AnimationChannel::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "targetId", targetId);
-    fprintfElement(file, "targetAttrib", targetAttrib);
-    fprintfElement(file, "%f ", "keytimes", keytimes);
-    fprintfElement(file, "%f ", "values", keyValues);
-    fprintfElement(file, "%f ", "tangentsIn", tangentsIn);
-    fprintfElement(file, "%f ", "tangentsOut", tangentsOut);
-    fprintfElement(file, "%u ", "interpolations", interpolations);
+    fprintfElement(file, "targetId", _targetId);
+    fprintfElement(file, "targetAttrib", _targetAttrib);
+    fprintfElement(file, "%f ", "keytimes", _keytimes);
+    fprintfElement(file, "%f ", "values", _keyValues);
+    fprintfElement(file, "%f ", "tangentsIn", _tangentsIn);
+    fprintfElement(file, "%f ", "tangentsOut", _tangentsOut);
+    fprintfElement(file, "%u ", "interpolations", _interpolations);
     fprintElementEnd(file);
 }
 
 void AnimationChannel::setTargetId(const std::string str)
 {
-    targetId = str;
+    _targetId = str;
 }
 
 void AnimationChannel::setTargetAttribute(unsigned int attrib)
 {
-    targetAttrib = attrib;
+    _targetAttrib = attrib;
 }
 
 void AnimationChannel::setKeyTimes(const std::vector<float>& values)
 {
-    keytimes = values;
+    _keytimes = values;
 }
 
 void AnimationChannel::setKeyValues(const std::vector<float>& values)
 {
-    keyValues = values;
+    _keyValues = values;
 }
 
 void AnimationChannel::setTangentsIn(const std::vector<float>& values)
 {
-    tangentsIn = values;
+    _tangentsIn = values;
 }
 
 void AnimationChannel::setTangentsOut(const std::vector<float>& values)
 {
-    tangentsOut = values;
+    _tangentsOut = values;
 }
 
 void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values)
 {
-    interpolations = values;
+    _interpolations = values;
 }
 
 const std::vector<float>& AnimationChannel::getKeyValues() const
 {
-    return keyValues;
+    return _keyValues;
 }
 
 unsigned int AnimationChannel::getInterpolationType(const char* str)

+ 13 - 12
gameplay-encoder/src/AnimationChannel.h

@@ -12,11 +12,11 @@ public:
 
     enum InterpolationTypes
     {
-        LINEAR = 1, 
-        BEZIER = 2, 
-        CARDINAL = 3, 
-        HERMITE = 4, 
-        BSPLINE = 5, 
+        LINEAR = 1,
+        BEZIER = 2,
+        CARDINAL = 3,
+        HERMITE = 4,
+        BSPLINE = 5,
         STEP = 6
     };
 
@@ -51,6 +51,7 @@ public:
      * Example: "LINEAR" returns AnimationChannel::LINEAR
      * 
      * @param str Interpolation such as "LINEAR" or "BSPLINE".
+     * 
      * @return A value from InterpolationTypes enum or zero if not valid.
      */
     static unsigned int getInterpolationType(const char* str);
@@ -58,13 +59,13 @@ public:
 
 private:
 
-    std::string targetId;
-    unsigned int targetAttrib;
-    std::vector<float> keytimes;
-    std::vector<float> keyValues;
-    std::vector<float> tangentsIn;
-    std::vector<float> tangentsOut;
-    std::vector<unsigned int> interpolations;
+    std::string _targetId;
+    unsigned int _targetAttrib;
+    std::vector<float> _keytimes;
+    std::vector<float> _keyValues;
+    std::vector<float> _tangentsIn;
+    std::vector<float> _tangentsOut;
+    std::vector<unsigned int> _interpolations;
 };
 
 

+ 54 - 0
gameplay-encoder/src/Animations.cpp

@@ -0,0 +1,54 @@
+#include "Animations.h"
+
+namespace gameplay
+{
+
+Animations::Animations(void)
+{
+    // There will only be one Animations.
+    // It requires an ID because it will be stores in the ref table.
+    setId("__Animations__");
+}
+
+Animations::~Animations(void)
+{
+}
+
+unsigned int Animations::getTypeId(void) const
+{
+    return ANIMATIONS_ID;
+}
+const char* Animations::getElementName(void) const
+{
+    return "Animations";
+}
+
+void Animations::writeBinary(FILE* file)
+{
+    Object::writeBinary(file);
+    write(_animations.size(), file);
+    for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); i++)
+    {
+        (*i)->writeBinary(file);
+    }
+}
+
+void Animations::writeText(FILE* file)
+{
+    fprintElementStart(file);
+    if (_animations.size() > 0 )
+    {
+        for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); i++)
+        {
+            (*i)->writeText(file);
+        }
+    }
+    fprintElementEnd(file);
+}
+
+void Animations::add(Animation* animation)
+{
+    _animations.push_back(animation);
+}
+
+}

+ 39 - 0
gameplay-encoder/src/Animations.h

@@ -0,0 +1,39 @@
+#ifndef LIBRARYANIMATIONS_H_
+#define LIBRARYANIMATIONS_H_
+
+#include "Object.h"
+#include "Animation.h"
+
+namespace gameplay
+{
+
+/**
+ * Animations contains all of the animations in the GamePlay Binary file.
+ */
+class Animations : public Object
+{
+public:
+
+    /**
+     * Constructor.
+     */
+    Animations(void);
+
+    /**
+     * Destructor.
+     */
+    virtual ~Animations(void);
+
+    virtual unsigned int getTypeId(void) const;
+    virtual const char* getElementName(void) const;
+    virtual void writeBinary(FILE* file);
+    virtual void writeText(FILE* file);
+
+    void add(Animation* animation);
+
+private:
+    std::vector<Animation*> _animations;
+};
+
+}
+#endif

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

@@ -6,7 +6,9 @@ namespace gameplay
 void fillArray(float values[], float value, size_t length)
 {
     for (size_t i = 0; i < length; i++)
+    {
         values[i] = value;
+    }
 }
 
 void setIdentityMatrix(float values[])

+ 32 - 32
gameplay-encoder/src/Camera.cpp

@@ -5,12 +5,12 @@ namespace gameplay
 {
 
 Camera::Camera(void) :
-    fieldOfView(0.0f),
-    aspectRatio(0.0f),
-    nearPlane(0.0f),
-    farPlane(0.0f),
-    viewportWidth(0.0f),
-    viewportHeight(0.0f)
+    _fieldOfView(0.0f),
+    _aspectRatio(0.0f),
+    _nearPlane(0.0f),
+    _farPlane(0.0f),
+    _viewportWidth(0.0f),
+    _viewportHeight(0.0f)
 {
 }
 
@@ -20,25 +20,25 @@ Camera::~Camera(void)
 
 void Camera::setFieldOfView(float value)
 {
-    fieldOfView = value;
+    _fieldOfView = value;
 }
 
 
 void Camera::setAspectRatio(float value)
 {
-    aspectRatio = value;
+    _aspectRatio = value;
 }
 
 
 void Camera::setNearPlane(float value)
 {
-    nearPlane = value;
+    _nearPlane = value;
 }
 
 
 void Camera::setFarPlane(float value)
 {
-    farPlane = value;
+    _farPlane = value;
 }
 
 unsigned int Camera::getTypeId(void) const
@@ -53,16 +53,16 @@ const char* Camera::getElementName(void) const
 void Camera::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    write(cameraType, file);
-    write(aspectRatio, file);
-    write(nearPlane, file);
-    write(farPlane, file);
+    write(_cameraType, file);
+    write(_aspectRatio, file);
+    write(_nearPlane, file);
+    write(_farPlane, file);
 
-    if (cameraType == CameraPerspective)
+    if (_cameraType == CameraPerspective)
     {
-        write(fieldOfView, file);
+        write(_fieldOfView, file);
     }
-    else if (cameraType == CameraOrthographic)
+    else if (_cameraType == CameraOrthographic)
     {
         write(getViewPortWidth(), file);
         write(getViewPortHeight(), file);
@@ -75,19 +75,19 @@ void Camera::writeBinary(FILE* file)
 void Camera::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "cameraType", cameraType == CameraPerspective ? "CameraPerspective" : "CameraOrthographic");
-    fprintfElement(file, "aspectRatio", aspectRatio);
-    fprintfElement(file, "nearPlane", nearPlane);
-    fprintfElement(file, "farPlane", farPlane);
+    fprintfElement(file, "cameraType", _cameraType == CameraPerspective ? "CameraPerspective" : "CameraOrthographic");
+    fprintfElement(file, "aspectRatio", _aspectRatio);
+    fprintfElement(file, "nearPlane", _nearPlane);
+    fprintfElement(file, "farPlane", _farPlane);
 
-    if (cameraType == CameraPerspective)
+    if (_cameraType == CameraPerspective)
     {
-        fprintfElement(file, "fieldOfView", fieldOfView);
+        fprintfElement(file, "fieldOfView", _fieldOfView);
     }
-    else if (cameraType == CameraOrthographic)
+    else if (_cameraType == CameraOrthographic)
     {
-        fprintfElement(file, "viewportWidth", viewportWidth);
-        fprintfElement(file, "viewportHeight", viewportHeight);
+        fprintfElement(file, "viewportWidth", _viewportWidth);
+        fprintfElement(file, "viewportHeight", _viewportHeight);
     }
     else
     {
@@ -98,28 +98,28 @@ void Camera::writeText(FILE* file)
 
 void Camera::setPerspective()
 {
-    cameraType = CameraPerspective;
+    _cameraType = CameraPerspective;
 }
 void Camera::setOrthographic()
 {
-    cameraType = CameraOrthographic;
+    _cameraType = CameraOrthographic;
 }
 void Camera::setViewportWidth(float width)
 {
-    viewportWidth = width;
+    _viewportWidth = width;
 }
 void Camera::setViewportHeight(float height)
 {
-    viewportHeight = height;
+    _viewportHeight = height;
 }
 
 float Camera::getViewPortWidth()
 {
-    return viewportWidth;
+    return _viewportWidth;
 }
 float Camera::getViewPortHeight()
 {
-    return viewportHeight;
+    return _viewportHeight;
 }
 
 }

+ 11 - 12
gameplay-encoder/src/Camera.h

@@ -19,10 +19,6 @@ public:
      * Destructor.
      */
     virtual ~Camera(void);
-    void setFieldOfView(float value);
-    void setAspectRatio(float value);
-    void setNearPlane(float value);
-    void setFarPlane(float value);
 
     virtual unsigned int getTypeId(void) const;
     virtual const char* getElementName(void) const;
@@ -31,8 +27,12 @@ public:
 
     void setPerspective();
     void setOrthographic();
+    void setAspectRatio(float value);
+    void setNearPlane(float value);
+    void setFarPlane(float value);
     void setViewportWidth(float width);
     void setViewportHeight(float height);
+    void setFieldOfView(float value);
 
     float getViewPortWidth();
     float getViewPortHeight();
@@ -44,14 +44,13 @@ public:
     };
 
 private:
-    unsigned char cameraType;
-    float viewport[4];
-    float fieldOfView;
-    float aspectRatio;
-    float nearPlane;
-    float farPlane;
-    float viewportWidth;
-    float viewportHeight;
+    unsigned char _cameraType;
+    float _fieldOfView;
+    float _aspectRatio;
+    float _nearPlane;
+    float _farPlane;
+    float _viewportWidth;
+    float _viewportHeight;
 };
 
 }

+ 13 - 7
gameplay-encoder/src/CameraInstance.cpp

@@ -3,7 +3,7 @@
 namespace gameplay
 {
 
-CameraInstance::CameraInstance(void) : ref(NULL)
+CameraInstance::CameraInstance(void) : _ref(NULL)
 {
 
 }
@@ -23,25 +23,31 @@ const char* CameraInstance::getElementName(void) const
 
 void CameraInstance::writeBinary(FILE* file)
 {
-    if (ref != NULL)
-        ref->writeBinary(file);
+    if (_ref != NULL)
+    {
+        _ref->writeBinary(file);
+    }
     else
+    {
         write((unsigned int)0, file);
+    }
 }
 void CameraInstance::writeText(FILE* file)
 {
-    if (ref != NULL)
-        ref->writeText(file);
+    if (_ref != NULL)
+    {
+        _ref->writeText(file);
+    }
 }
 
 Camera* CameraInstance::getCamera()
 {
-    return ref;
+    return _ref;
 }
 
 void CameraInstance::setCamera(Camera* camera)
 {
-    ref = camera;
+    _ref = camera;
 }
 
 }

+ 1 - 1
gameplay-encoder/src/CameraInstance.h

@@ -29,7 +29,7 @@ public:
     Camera* getCamera();
     void setCamera(Camera* camera);
 private:
-    Camera* ref;
+    Camera* _ref;
 };
 
 }

+ 15 - 16
gameplay-encoder/src/DAEChannelTarget.cpp

@@ -5,21 +5,20 @@
 namespace gameplay
 {
 
-DAEChannelTarget::DAEChannelTarget(const domChannel* channelRef) : channel(NULL), targetElement(NULL)
+DAEChannelTarget::DAEChannelTarget(const domChannelRef channelRef) : _channel(channelRef), _targetElement(NULL)
 {
-    channel = channelRef;
     const std::string target = channelRef->getTarget();
     size_t index = target.find('/');
     if (index == std::string::npos)
     {
         // If the string doesn't contain a '/' then the whole string is the id
         // and there are no sid's being targeted.
-        targetId = target;
+        _targetId = target;
     }
     else
     {
         // The targetId is the part before the first '/'
-        targetId = target.substr(0, index);
+        _targetId = target.substr(0, index);
 
         // each '/' denotes another sid
         size_t start;
@@ -40,7 +39,7 @@ DAEChannelTarget::DAEChannelTarget(const domChannel* channelRef) : channel(NULL)
                 sub = target.substr(start, end - start);
                 index = end + 1;
             }
-            attributeIds.push_back(sub);
+            _attributeIds.push_back(sub);
         } while(end != std::string::npos);
     }
 
@@ -52,31 +51,31 @@ DAEChannelTarget::~DAEChannelTarget(void)
 
 daeElement* DAEChannelTarget::getTargetElement()
 {
-    if (!targetElement && targetId.length() > 0)
+    if (!_targetElement && _targetId.length() > 0)
     {
-        daeSIDResolver resolver(channel->getDocument()->getDomRoot(), targetId.c_str());
-        targetElement = resolver.getElement();
+        daeSIDResolver resolver(_channel->getDocument()->getDomRoot(), _targetId.c_str());
+        _targetElement = resolver.getElement();
     }
-    return targetElement;
+    return _targetElement;
 }
 
 const std::string& DAEChannelTarget::getTargetId() const
 {
-    return targetId;
+    return _targetId;
 }
 
 size_t DAEChannelTarget::getTargetAttributeCount() const
 {
-    return attributeIds.size();
+    return _attributeIds.size();
 }
 
 daeElement* DAEChannelTarget::getTargetAttribute(size_t index)
 {
-    if (index >= attributeIds.size())
+    if (index >= _attributeIds.size())
     {
         return NULL;
     }
-    const std::string& att = attributeIds[index];
+    const std::string& att = _attributeIds[index];
     std::string sid = att.substr(0, att.find('.'));
     daeSIDResolver resolver(getTargetElement(), sid.c_str());
     return resolver.getElement();
@@ -84,14 +83,14 @@ daeElement* DAEChannelTarget::getTargetAttribute(size_t index)
 
 void DAEChannelTarget::getPropertyName(size_t index, std::string* str)
 {
-    if (index < attributeIds.size())
+    if (index < _attributeIds.size())
     {
         // The property name is the string segment after the '.'
         // The propery is optional so it might not be found.
-        const std::string& att = attributeIds[index];
+        const std::string& att = _attributeIds[index];
         size_t i = att.find('.');
         if (i != std::string::npos && i < att.size())
-        {   
+        {
             str->assign(att.substr(i+1));
             return;
         }

+ 9 - 9
gameplay-encoder/src/DAEChannelTarget.h

@@ -1,5 +1,5 @@
-#ifndef CHANNELTARGET_H_
-#define CHANNELTARGET_H_
+#ifndef DAECHANNELTARGET_H_
+#define DAECHANNELTARGET_H_
 
 #include <dae.h>
 #include <dae/daeSIDResolver.h>
@@ -27,7 +27,7 @@ public:
     /**
      * Constructs the DAEChannelTarget from the given channel element.
      */
-    DAEChannelTarget(const domChannel* channelRef);
+    DAEChannelTarget(const domChannelRef channelRef);
 
     /**
      * Destructor.
@@ -68,17 +68,17 @@ public:
 
 private:
     /**
-     * Pointer to the <channel> element. 
+     * The channel element.
      */
-    const domChannel* channel;
+    const domChannelRef _channel;
 
-    domElement* targetElement;
+    domElement* _targetElement;
 
     /**
-     * The first part is the id attribute of an element in the instance document 
+     * The first part is the id attribute of an element in the instance document
      * or a dot segment (".") indicating that this is a relative address.
      */
-    std::string targetId;
+    std::string _targetId;
 
     /**
      * A channel target can have zero or more target attributes.
@@ -87,7 +87,7 @@ private:
      * Result: attributeIds will contain 2 elements. "Translate.X" and "Translate.Y"
      * Refer to the COLLADA spec "COLLADA Target Addressing".
      */
-    std::vector<std::string> attributeIds;
+    std::vector<std::string> _attributeIds;
 };
 
 }

+ 125 - 0
gameplay-encoder/src/DAEOptimizer.cpp

@@ -0,0 +1,125 @@
+#include "DAEOptimizer.h"
+
+#include <algorithm>
+
+#include "StringUtil.h"
+
+DAEOptimizer::DAEOptimizer(domCOLLADA* dom)
+{
+    _dom = dom;
+}
+
+DAEOptimizer::~DAEOptimizer()
+{   
+}
+
+void DAEOptimizer::combineAnimations(const std::string& nodeId, const std::string& animationId)
+{
+    std::list<domChannelRef> channels;
+
+    daeSIDResolver resolver(_dom, nodeId.c_str());
+    daeElement* element = resolver.getElement();
+    if (element && element->getElementType() == COLLADA_TYPE::NODE)
+    {
+        domNodeRef node = daeSafeCast<domNode>(resolver.getElement());
+        getAnimationChannels(node, channels);
+    }
+
+    // Get the <library_animations>
+    domLibrary_animations_Array& animationsLibraryArray = _dom->getLibrary_animations_array();
+    assert(animationsLibraryArray.getCount() > 0);
+    domLibrary_animationsRef& animationsLibrary = animationsLibraryArray.get(0);
+
+    // Add a new animation
+    domAnimationRef animation = daeSafeCast<domAnimation>(animationsLibrary->createAndPlace("animation"));
+    assert(animation);
+    animation->setId(animationId.c_str());
+    // TODO: Make sure that there doesn't already exist an animation with this ID.
+
+    // Move each of the channels to this animation
+    for (std::list<domChannelRef>::iterator i = channels.begin(); i != channels.end(); i++)
+    {
+        moveChannelAndSouresToAnimation(*i, animation);
+    }
+
+    // Clean up the empty animations
+    deleteEmptyAnimations();
+}
+
+void DAEOptimizer::getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels)
+{
+    assert(node->getId());
+    std::string nodeIdSlash (node->getId());
+    nodeIdSlash.append("/");
+
+    domCOLLADA* root = (domCOLLADA*)node->getDocument()->getDomRoot();
+
+    domLibrary_animations_Array& animationLibrary = root->getLibrary_animations_array();
+    size_t animationLibraryCount = animationLibrary.getCount();
+    for (size_t i = 0; i < animationLibraryCount; i++)
+    {
+        domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
+        domAnimation_Array& animationArray = animationsRef->getAnimation_array();
+        size_t animationCount = animationArray.getCount();
+        for (size_t j = 0; j < animationCount; j++)
+        {
+            domAnimationRef& animationRef = animationArray.get(j);
+            domChannel_Array& channelArray = animationRef->getChannel_array();
+            size_t channelArrayCount = channelArray.getCount();
+            for (size_t k = 0; k < channelArrayCount; k++)
+            {
+                domChannelRef& channel = channelArray.get(k);
+                const char* target = channel->getTarget();
+
+                // TODO: Assumes only one target per channel?
+                if (startsWith(target, nodeIdSlash.c_str()))
+                {
+                    channels.push_back(channel);
+                }
+            }
+        }
+    }
+
+    // Recursively do the same for all nodes
+    daeTArray<daeSmartRef<daeElement>> children;
+    node->getChildren(children);
+    size_t childCount = children.getCount();
+    for (size_t i = 0; i < childCount; i++)
+    {
+        daeElementRef childElement = children[i];
+        if (childElement->getElementType() == COLLADA_TYPE::NODE)
+        {
+            domNodeRef childNode = daeSafeCast<domNode>(childElement);
+            getAnimationChannels(childNode, channels);
+        }
+    }
+}
+
+void DAEOptimizer::deleteEmptyAnimations()
+{
+    std::list<domAnimationRef> animations;
+    
+    // Get the list of empty animations
+    domLibrary_animations_Array& animationLibrary = _dom->getLibrary_animations_array();
+    size_t animationLibraryCount = animationLibrary.getCount();
+    for (size_t i = 0; i < animationLibraryCount; i++)
+    {
+        domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
+        domAnimation_Array& animationArray = animationsRef->getAnimation_array();
+        size_t animationCount = animationArray.getCount();
+        for (size_t j = 0; j < animationCount; j++)
+        {
+            domAnimationRef& animation = animationArray.get(j);
+            if (isEmptyAnimation(animation))
+            {
+                animations.push_back(animation);
+            }
+        }
+    }
+
+    // Delete all of the empty animations
+    for (std::list<domAnimationRef>::iterator i = animations.begin(); i != animations.end(); i++)
+    {
+        daeElement::removeFromParent(*i);
+    }
+}

+ 63 - 0
gameplay-encoder/src/DAEOptimizer.h

@@ -0,0 +1,63 @@
+#ifndef DAEOPTIMIZER_H_
+#define DAEOPTIMIZER_H_
+
+#include <dae.h>
+#include <dae/daeSIDResolver.h>
+#include <dae/domAny.h>
+#include <dom/domCOLLADA.h>
+#include <dom/domConstants.h>
+#include <dom/domElements.h>
+#include <dom/domProfile_COMMON.h>
+
+#include <vector>
+
+#include "Base.h"
+#include "DAEUtil.h"
+
+/**
+ * The DAEOptimizer optimizes a COLLADA dom.
+ */
+class DAEOptimizer
+{
+public:
+
+    /**
+     * Constructor.
+     */
+    DAEOptimizer(domCOLLADA* dom);
+
+    /**
+     * Destructor.
+     */
+    ~DAEOptimizer(void);
+
+    /**
+     * Combines all of the animations that target the node and all of its child nodes into a new animation with the given ID.
+     * 
+     * @param nodeId The ID of the node.
+     * @param animationId The ID of the new animation to create.
+     */
+    void combineAnimations(const std::string& nodeId, const std::string& animationId);
+
+private:
+
+    /**
+     * Gets all of the animation channels that target the given node and appends them to the list.
+     * 
+     * @param node The node that the animation channels target.
+     * @param channels The list of channels to append to.
+     */
+    void getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels);
+
+    /**
+     * Deletes all of the empty animations in the dom.
+     */
+    void deleteEmptyAnimations();
+
+private:
+    
+    domCOLLADA* _dom;
+    std::string _inputPath;
+};
+
+#endif

+ 0 - 17
gameplay-encoder/src/DAEPolygonInput.cpp

@@ -1,17 +0,0 @@
-#include "DAEPolygonInput.h"
-
-namespace gameplay
-{
-
-DAEPolygonInput::DAEPolygonInput(void) :
-    offset(0),
-    type(0),
-    accessor(NULL)
-{
-}
-
-DAEPolygonInput::~DAEPolygonInput(void)
-{
-}
-
-}

+ 0 - 23
gameplay-encoder/src/DAEPolygonInput.h

@@ -1,23 +0,0 @@
-#ifndef DAEPOLYGONINPUT_H_
-#define DAEPOLYGONINPUT_H_
-
-#include <dom/domTypes.h>
-#include <dom/domAccessor.h>
-
-namespace gameplay
-{
-
-class DAEPolygonInput
-{
-public:
-    DAEPolygonInput(void);
-    virtual ~DAEPolygonInput(void);
-
-    unsigned int offset;
-    int type;
-    domListOfFloats sourceValues;
-    domAccessor* accessor;
-};
-
-}
-#endif

+ 237 - 256
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -5,11 +5,14 @@
 #include <algorithm>
 
 #include "DAESceneEncoder.h"
+#include "DAEOptimizer.h"
+
+//#define ENCODER_PRINT_TIME 1
 
 using namespace gameplay;
 
 DAESceneEncoder::DAESceneEncoder()
-    : _collada(NULL), file(NULL), vertexBlendWeights(NULL), vertexBlendIndices(NULL)
+    : _collada(NULL), _dom(NULL), file(NULL), _vertexBlendWeights(NULL), _vertexBlendIndices(NULL)
 {
 }
 
@@ -49,6 +52,31 @@ unsigned int getMaxOffset(domInputLocalOffset_Array& inputArray)
     return maxOffset;
 }
 
+void DAESceneEncoder::optimizeCOLLADA(const EncoderArguments& arguments, domCOLLADA* dom)
+{
+    DAEOptimizer optimizer(dom);
+    const std::vector<std::string>& groupAnimatioNodeIds = arguments.getGroupAnimationNodeId();
+    const std::vector<std::string>& groupAnimatioIds = arguments.getGroupAnimationAnimationId();
+    assert(groupAnimatioNodeIds.size() == groupAnimatioIds.size());
+    size_t size = groupAnimatioNodeIds.size();
+    if (size > 0)
+    {
+        begin();
+        for (size_t i = 0; i < size; i++)
+        {
+            optimizer.combineAnimations(groupAnimatioNodeIds[i], groupAnimatioIds[i]);
+        }
+        end("groupAnimation");
+    }
+    if (arguments.DAEOutputEnabled())
+    {
+        if (!_collada->writeTo(arguments.getFilePath(), arguments.getDAEOutputPath()))
+        {
+            fprintf(stderr,"Error: COLLADA failed to write the dom for file:%s\n", arguments.getDAEOutputPath().c_str());
+        }
+    }
+}
+
 void DAESceneEncoder::triangulate(DAE* dae)
 {
     daeDatabase* dataBase = dae->getDatabase();
@@ -213,14 +241,21 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     triangles->setCount(trianglesProcessed);
 }
 
-void DAESceneEncoder::write(const std::string& filepath, const char* nodeId, bool text)
+void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
 {
+    _begin = std::clock();
+    const char* nodeId = arguments.getNodeId();
+    bool text = arguments.textOutputEnabled();
+
     std::string filenameOnly = getFilenameFromFilePath(filepath);
     std::string dstPath = filepath.substr(0, filepath.find_last_of('/'));
     
     // Load the collada document
     _collada = new DAE();
-    if (_collada->load(filepath.c_str()) != DAE_OK)
+    begin();
+    _dom = _collada->open(filepath);
+    end("Open file");
+    if (!_dom)
     {
         fprintf(stderr,"Error: COLLADA failed to open file:%s\n", filepath.c_str());
         if (_collada)
@@ -230,35 +265,35 @@ void DAESceneEncoder::write(const std::string& filepath, const char* nodeId, boo
         }
         return;
     }
-
-    // Get the dom tree
-    domCOLLADA* dom = _collada->getDom(filepath.c_str());
-    if (!dom)
-    {
-        fprintf(stderr,"Error: COLLADA failed to the dom for file:%s\n", filepath.c_str());
-        if (_collada)
-        {
-            delete _collada;
-            _collada = NULL;
-        }
-        return;
-    }
     
     // Run collada conditioners
+    begin();
     triangulate(_collada);
+    end("triangulate");
+
+    // Optimize the dom before encoding
+    optimizeCOLLADA(arguments, _dom);
 
     // Find the <visual_scene> element within the <scene>
-    const domCOLLADA::domSceneRef& domScene = dom->getScene();
+    const domCOLLADA::domSceneRef& domScene = _dom->getScene();
     daeElement* scene = NULL;
     if (domScene && domScene->getInstance_visual_scene())
     {
         scene = domScene->getInstance_visual_scene()->getUrl().getElement();
+        if (scene->getElementType() != COLLADA_TYPE::VISUAL_SCENE)
+        {
+            // This occured once where Maya exported a Node and Scene element with the same ID.
+            fprintf(stderr,"Error: instance_visual_scene does not reference visual_scene for file:%s\n", filepath.c_str());
+            return;
+        }
         if (scene)
         {
             if (nodeId == NULL)
             {
                 // If the -n <node_id> parameter was not passed then write out the entire scene.
+                begin();
                 loadScene((domVisual_scene*)scene);
+                end("load scene");
             }
             else
             {
@@ -286,7 +321,9 @@ void DAESceneEncoder::write(const std::string& filepath, const char* nodeId, boo
     }
     
     // The animations should be loaded last
-    loadAnimations(dom);
+    begin();
+    loadAnimations(_dom);
+    end("loadAnimations");
 
     std::string dstFilename = dstPath;
     dstFilename.append(1, '/');
@@ -296,11 +333,17 @@ void DAESceneEncoder::write(const std::string& filepath, const char* nodeId, boo
 
     if (text)
     {
-        _gamePlayFile.saveText(dstFilename + ".xml");
+        std::string outFile = dstFilename + ".xml";
+        fprintf(stderr, "Saving debug file: %s\n", outFile.c_str());
+        _gamePlayFile.saveText(outFile);
     }
     else
     {
-        _gamePlayFile.saveBinary(dstFilename + ".gpb");
+        std::string outFile = dstFilename + ".gpb";
+        fprintf(stderr, "Saving binary file: %s\n", outFile.c_str());
+        begin();
+        _gamePlayFile.saveBinary(outFile);
+        end("save binary");
     }
     
     // Cleanup
@@ -318,28 +361,32 @@ void DAESceneEncoder::write(const std::string& filepath, const char* nodeId, boo
 void DAESceneEncoder::loadAnimations(const domCOLLADA* dom)
 {
     // Call loadAnimation on all <animation> elements in all <library_animations>
-    const domLibrary_animations_Array& animationLibrary = dom->getLibrary_animations_array();
-    size_t animationLibraryCount = animationLibrary.getCount();
-    for (size_t i = 0; i < animationLibraryCount; i++)
+    const domLibrary_animations_Array& animationLibrarys = dom->getLibrary_animations_array();
+    size_t animationLibrarysCount = animationLibrarys.getCount();
+    for (size_t i = 0; i < animationLibrarysCount; i++)
     {
-        const domLibrary_animationsRef& animationsRef = animationLibrary.get(i);
-        const domAnimation_Array& animationArray = animationsRef->getAnimation_array();
+        const domLibrary_animationsRef& libraryAnimation = animationLibrarys.get(i);
+        const domAnimation_Array& animationArray = libraryAnimation->getAnimation_array();
         size_t animationCount = animationArray.getCount();
-        for (size_t i = 0; i < animationCount; i++)
+        for (size_t j = 0; j < animationCount; j++)
         {
-            const domAnimationRef& animationRef = animationArray.get(i);
+            const domAnimationRef& animationRef = animationArray.get(j);
             loadAnimation(animationRef);
         }
     }
 }
 
-void DAESceneEncoder::loadAnimation(const domAnimation* animationRef)
+void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
 {
     // <channel> points to one <sampler>
     // <sampler> points to multiple <input> elements
 
     Animation* animation = new Animation();
-    animation->setId(findAnimationId(animationRef));
+    const char* str = animationRef->getId();
+    if (str)
+    {
+        animation->setId(str);
+    }
 
     // <channel>
     const domChannel_Array& channelArray = animationRef->getChannel_array();
@@ -351,20 +398,18 @@ void DAESceneEncoder::loadAnimation(const domAnimation* animationRef)
         const domChannelRef& channelRef = channelArray.get(i);
 
         // <sampler>
-        daeElement* samplerElement = channelRef->getSource().getElement();
-        assert(samplerElement);
-        const domSampler* sampler = static_cast<domSampler*>(samplerElement);
+        const domSamplerRef sampler = getSampler(channelRef);
+        assert(sampler);
 
         // <input>
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         size_t inputArrayCount = inputArray.getCount();
-        for (size_t i = 0; i < inputArrayCount; i++)
+        for (size_t j = 0; j < inputArrayCount; j++)
         {
-            const domInputLocalRef& inputLocal = inputArray.get(i);
+            const domInputLocalRef& inputLocal = inputArray.get(j);
 
             // <source>
-            daeElement* sourceElement = inputLocal->getSource().getElement();
-            const domSource* source = static_cast<domSource*>(sourceElement);
+            const domSourceRef source = getSource(inputLocal, animationRef);
 
             std::string semantic = inputLocal->getSemantic();
             if (equals(semantic, "INTERPOLATION"))
@@ -380,10 +425,10 @@ void DAESceneEncoder::loadAnimation(const domAnimation* animationRef)
                 if (equals(semantic, "INPUT"))
                 {
                     // TODO: Ensure param name is TIME?
-                    for (std::vector<float>::iterator i = floats.begin(); i != floats.end(); i++)
+                    for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); k++)
                     {
                         // Convert seconds to milliseconds
-                        *i = *i * 1000.0f;
+                        *k = *k * 1000.0f;
                     }
                     animationChannel->setKeyTimes(floats);
                 }
@@ -402,45 +447,10 @@ void DAESceneEncoder::loadAnimation(const domAnimation* animationRef)
             }
         }
         // get target attribute enum value
-        loadTarget(channelRef, animationChannel);
-        
-        // Set the ID of the AnimationChannel
-        std::string channelId = channelRef->getTarget();
-        replace(channelId.begin(), channelId.end(), '/', '_');
-        // ensure no duplicate IDs
-        while (_gamePlayFile.idExists(channelId))
-        {
-            channelId.append("_");
-        }
-        animationChannel->setId(channelId);
-
-        // Animations that target a joint should be grouped with the other animations for that skin.
-        // If this animation channel targets a joint then add the animation channel to the skin's animation instead.
-        DAEChannelTarget channelTarget(channelRef);
-        daeElement* element = channelTarget.getTargetElement();
-        daeInt type = element->typeID();
-        if (type == domNode::ID())
+        if (loadTarget(channelRef, animationChannel))
         {
-            const domNode* node = daeSafeCast<domNode>(element);
-            if (node->getType() == NODETYPE_JOINT)
-            {
-                const char* id = node->getId();
-                if (id)
-                {
-                    Animation* skinAnimation = _gamePlayFile.findAnimationForJoint(id);
-                    if (skinAnimation)
-                    {
-                        // TODO: Assert will fail if <controller> doesn't have an ID.
-                        assert(skinAnimation->getId().length() > 0);
-                        skinAnimation->add(animationChannel);
-                        _gamePlayFile.addAnimation(skinAnimation);
-                        continue;
-                    }
-                }
-            }
+            animation->add(animationChannel);
         }
-
-        animation->add(animationChannel);
     }
     if (animation->getAnimationChannelCount() > 0)
     {
@@ -452,11 +462,13 @@ void DAESceneEncoder::loadAnimation(const domAnimation* animationRef)
     }
 }
 
-void DAESceneEncoder::loadInterpolation(const domSource* source, AnimationChannel* animationChannel)
+void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChannel* animationChannel)
 {
     // COLLADA stores the interpolations as a list of strings while GBP uses unsigned int
     std::vector<unsigned int> values;
-    const domListOfNames& names = source->getName_array()->getValue();
+    const domName_arrayRef nameArray = getSourceNameArray(source);
+    assert(nameArray);
+    const domListOfNames& names = nameArray->getValue();
     size_t count = (size_t)names.getCount();
     values.resize(count);
     if (count > 0)
@@ -486,11 +498,19 @@ void DAESceneEncoder::loadInterpolation(const domSource* source, AnimationChanne
     animationChannel->setInterpolations(values);
 }
 
-void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel* animationChannel)
+bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChannel* animationChannel)
 {
+    // GamePlay requires that animations are baked. Use "Bake Transforms" in your 3D modeling tool.
+    // If the target of an animation is not a matrix then an error will be printed.
+
+    const static char* TRANSFORM_WARNING_FORMAT = "Warning: Node \"%s\":\n %s %s\n";
+    const static char* TRANSFORM_MESSAGE = "transform found but not supported.\n Use \"Bake Transforms\" option when exporting.";
+
     unsigned int targetProperty = 0;
     DAEChannelTarget channelTarget(channelRef);
 
+    const char* targetId = channelTarget.getTargetId().c_str();
+
     // TODO: Do we want to support more than one? If yes then this needs to be fixed.
     for (size_t i = 0; i < channelTarget.getTargetAttributeCount(); i++)
     {
@@ -502,6 +522,9 @@ void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel*
             daeInt type = attributeElement->typeID();
             if (type == domRotate::ID())
             {
+                printf(TRANSFORM_WARNING_FORMAT, targetId, "Rotate", TRANSFORM_MESSAGE);
+                return false;
+                /*
                 // <rotate>
                 const domRotate* rotate = daeSafeCast<domRotate>(attributeElement);
 
@@ -536,9 +559,13 @@ void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel*
                         animationChannel->setKeyValues(floats);
                     }
                 }
+                */
             }
             else if (type == domScale::ID())
             {
+                printf(TRANSFORM_WARNING_FORMAT, targetId, "Scale", TRANSFORM_MESSAGE);
+                return false;
+                /*
                 // <scale>
                 //const domScale* scale = daeSafeCast<domScale>(attributeElement);
                 if (equalsIgnoreCase(prop, "X"))
@@ -557,9 +584,13 @@ void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel*
                 {
                     targetProperty = Transform::ANIMATE_SCALE;
                 }
+                */
             }
             else if (type == domTranslate::ID())
             {
+                printf(TRANSFORM_WARNING_FORMAT, targetId, "Translate", TRANSFORM_MESSAGE);
+                return false;
+                /*
                 // <translate>
                 //const domTranslate* translate = daeSafeCast<domTranslate>(attributeElement);
                 if (equalsIgnoreCase(prop, "X"))
@@ -578,6 +609,7 @@ void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel*
                 {
                     targetProperty = Transform::ANIMATE_TRANSLATE;
                 }
+                */
             }
             else if (type == domMatrix::ID())
             {
@@ -597,9 +629,9 @@ void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel*
                     size_t j = i * 16;
                     // COLLADA used row-major but the Matrix class uses column-major
                     Matrix matrix(
-                        keyValues[j+0], keyValues[j+4], keyValues[j+8], keyValues[j+12], 
-                        keyValues[j+1], keyValues[j+5], keyValues[j+9], keyValues[j+13], 
-                        keyValues[j+2], keyValues[j+6], keyValues[j+10], keyValues[j+14], 
+                        keyValues[j+0], keyValues[j+4], keyValues[j+8], keyValues[j+12],
+                        keyValues[j+1], keyValues[j+5], keyValues[j+9], keyValues[j+13],
+                        keyValues[j+2], keyValues[j+6], keyValues[j+10], keyValues[j+14],
                         keyValues[j+3], keyValues[j+7], keyValues[j+11], keyValues[j+15]);
                     Vector3 scale;
                     Quaternion rotation;
@@ -624,32 +656,22 @@ void DAESceneEncoder::loadTarget(const domChannel* channelRef, AnimationChannel*
     }
     animationChannel->setTargetAttribute(targetProperty);
     animationChannel->setTargetId(channelTarget.getTargetId());
+    return true;
 }
 
-std::string DAESceneEncoder::findAnimationId(const domAnimation* animationRef)
+void DAESceneEncoder::begin()
 {
-    std::string animationId;
-    const char* str = animationRef->getId();
-    if (str)
-    {
-        animationId = str;
-        // check if this ID already exists
-        if (_gamePlayFile.idExists(animationId))
-        {
-            // choose a different id
-            animationId.append("_animation");
-        }
-    }
-    if (animationId.length() == 0)
-    {
-        animationId.assign("animation"); // TODO: Remove this later
-    }
-    // ensure no duplicate IDs
-    while (_gamePlayFile.idExists(animationId))
-    {
-        animationId.append("_");
-    }
-    return animationId;
+    #ifdef ENCODER_PRINT_TIME
+    _begin = std::clock();
+    #endif
+}
+
+void DAESceneEncoder::end(const char* str)
+{
+    #ifdef ENCODER_PRINT_TIME
+    clock_t time = std::clock() - _begin;
+    fprintf(stderr,"%5d %s\n", time, str);
+    #endif
 }
 
 void DAESceneEncoder::copyFloats(const domFloat_array* source, std::vector<float>* target)
@@ -660,7 +682,7 @@ void DAESceneEncoder::copyFloats(const domFloat_array* source, std::vector<float
     t.resize(count);
     const domListOfFloats& listOfFloats = source->getValue();
     for (size_t i = 0; i < count; i++)
-    {   
+    {
         t[i] = (float)listOfFloats.get(i);
     }
 }
@@ -727,7 +749,9 @@ Node* DAESceneEncoder::loadNode(domNode* n, Node* parent)
     {
         node = _gamePlayFile.getNode(n->getID());
         if (node)
+        {
             return node;
+        }
     }
     
     // Load the node
@@ -774,7 +798,9 @@ void DAESceneEncoder::transformNode(domNode* domNode, Node* node)
     {
         const domMatrixRef& matrix = matrixArray.get(0);
         if (!matrix)
+        {
             return;
+        }
         const domFloat4x4& tx = matrix->getValue();
         float transform[] = {(float)tx.get(0), (float)tx.get(4), (float)tx.get(8), (float)tx.get(12),
                               (float)tx.get(1), (float)tx.get(5), (float)tx.get(9), (float)tx.get(13),
@@ -814,7 +840,7 @@ void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
         {
             case COLLADA_TYPE::TRANSLATE:
             {
-                domTranslate* translateNode = dynamic_cast<domTranslate*>(static_cast<daeElement*>(childElement));
+                domTranslateRef translateNode = daeSafeCast<domTranslate>(childElement);
                 float x = (float)translateNode->getValue().get(0);
                 float y = (float)translateNode->getValue().get(1);
                 float z = (float)translateNode->getValue().get(2);
@@ -823,20 +849,20 @@ void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
             }
             case COLLADA_TYPE::ROTATE:
             {
-                domRotate* rotateNode = dynamic_cast<domRotate*>(static_cast<daeElement*>(childElement));
+                domRotateRef rotateNode = daeSafeCast<domRotate>(childElement);
                 float x = (float)rotateNode->getValue().get(0);
                 float y = (float)rotateNode->getValue().get(1);
                 float z = (float)rotateNode->getValue().get(2);
-                float angle = MATH_DEG_TO_RAD((float)rotateNode->getValue().get(3));
-                if (x == 1 && y == 0 && z == 0)
+                float angle = MATH_DEG_TO_RAD((float)rotateNode->getValue().get(3)); // COLLADA uses degrees, gameplay uses radians
+                if (x == 1.0f && y == 0.0f && z == 0.0f)
                 {
                     dstTransform.rotateX(angle);
                 }
-                else if (x == 0 && y == 1 && z == 0)
+                else if (x == 0.0f && y == 1.0f && z == 0.0f)
                 {
                     dstTransform.rotateY(angle);
                 }
-                else if (x == 0 && y == 0 && z == 1)
+                else if (x == 0.0f && y == 0.0f && z == 1.0f)
                 {
                     dstTransform.rotateZ(angle);
                 }
@@ -848,7 +874,7 @@ void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
             }
             case COLLADA_TYPE::SCALE:
             {
-                domScale* scaleNode = dynamic_cast<domScale*>(static_cast<daeElement*>(childElement));
+                domScaleRef scaleNode = daeSafeCast<domScale>(childElement);
                 float x = (float)scaleNode->getValue().get(0);
                 float y = (float)scaleNode->getValue().get(1);
                 float z = (float)scaleNode->getValue().get(2);
@@ -856,12 +882,13 @@ void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
                 break;
             }
             case COLLADA_TYPE::SKEW:
+                warning("Skew transform found but not supported.");
+                break;
             case COLLADA_TYPE::LOOKAT:
+                warning("Lookat transform found but not supported.");
+                break;
             default:
-            {
-                warning("Skew or lookat transform found but not supported.");
                 break;
-            }
         }
     }
 }
@@ -955,8 +982,8 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
     size_t instanceControllerCount = instanceControllers.getCount();
     for (size_t i = 0; i < instanceControllerCount; i++)
     {
-        const domInstance_controllerRef controllerInstanceRef = instanceControllers.get(i);
-        xsAnyURI controllerURI = controllerInstanceRef->getUrl();
+        const domInstance_controllerRef instanceControllerRef = instanceControllers.get(i);
+        xsAnyURI controllerURI = instanceControllerRef->getUrl();
         domController* controllerRef = daeSafeCast<domController>(controllerURI.getElement());
 
         if (controllerRef)
@@ -967,25 +994,19 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
                 Model* model = loadSkin(skinElement);
                 if (model)
                 {
-                    // use only the first skeleton
-                    domInstance_controller::domSkeleton_Array& skeletons = controllerInstanceRef->getSkeleton_array();
+                    domInstance_controller::domSkeleton_Array& skeletons = instanceControllerRef->getSkeleton_array();
                     if (skeletons.getCount() == 0)
                     {
                         warning("No skeletons found for instance controller: ");
                         delete model;
                         continue;
                     }
-                    else if (skeletons.getCount() > 1)
-                    {
-                        // Only log a warning, don't exit
-                        warning("More than one skeleton found for instance controller. Using first skeleton only.");
-                    }
                     // Load the skeleton for this skin
-                    loadSkeleton((domInstance_controller::domSkeleton*)skeletons.get((size_t)0), model->getSkin());
+                    domInstance_controller::domSkeletonRef skeleton = getSkeleton(instanceControllerRef);
+                    assert(skeleton);
+                    loadSkeleton(skeleton, model->getSkin());
 
                     node->setModel(model);
-
-                    // TODO: Load animations
                 }
             }
         }
@@ -993,8 +1014,8 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
         {
             // warning
         }
-        jointLookupTable.clear();
-        jointInverseBindPoseMatrices.clear();
+        _jointLookupTable.clear();
+        _jointInverseBindPoseMatrices.clear();
     }
 }
 
@@ -1118,7 +1139,7 @@ LightInstance* DAESceneEncoder::loadLight(const domLight* lightRef)
         {
             const domLight::domTechnique_common::domSpotRef spotRef = techRef->getSpot();
             if (spotRef.cast())
-            {   
+            {
                 light->setSpotLight();
                 // color
                 const domTargetableFloat3Ref float3Ref = spotRef->getColor();
@@ -1198,20 +1219,19 @@ LightInstance* DAESceneEncoder::loadLight(const domLight* lightRef)
 
 void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin)
 {
-    xsAnyURI skeletonUri = skeletonElement->getValue(); 
+    xsAnyURI skeletonUri = skeletonElement->getValue();
     daeString skeletonId = skeletonUri.getID();
     daeSIDResolver resolver(skeletonUri.getElement(), skeletonId);
     domNode* rootNode = daeSafeCast<domNode>(resolver.getElement());
     
-    // Get the lookup scene id (sid) and joint index.     
-    std::string sid = std::string(rootNode->getSid());
-    std::string id = std::string(skeletonId);   
+    // Get the lookup scene id (sid) and joint index.
+    std::string id = std::string(skeletonId);
 
-    // Has the root joint been loaded yet?
-    Node* rootJoint = (Node*)_gamePlayFile.getFromRefTable(id);
+    // Has the skeleton (root joint) been loaded yet?
+    Node* skeleton = (Node*)_gamePlayFile.getFromRefTable(id);
 
-    // The root node is not loaded yet, so let's load it now
-    if (rootJoint == NULL)
+    // The skeleton node is not loaded yet, so let's load it now
+    if (skeleton == NULL)
     {
         // Find the top most parent of rootNode that has not yet been loaded
         domNode* topLevelParent = rootNode;
@@ -1225,29 +1245,27 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
 
         // Is the parent of this node loaded yet?
         Node* parentNode = NULL;
-        if (topLevelParent->getParent() && 
+        if (topLevelParent->getParent() &&
             topLevelParent->getParent()->getElementType() == COLLADA_TYPE::NODE &&
             _gamePlayFile.getFromRefTable(topLevelParent->getParent()->getID()) != NULL)
         {
             parentNode = (Node*)_gamePlayFile.getFromRefTable(topLevelParent->getParent()->getID());
         }
 
-        // Finally, load the node hierarchy that includes the root node
-        rootJoint = loadNode(topLevelParent, parentNode);
+        // Finally, load the node hierarchy that includes the skeleton
+        skeleton = loadNode(topLevelParent, parentNode);
     }
-    
-    if (rootJoint == NULL)
+
+    if (skeleton == NULL)
     {
         // This shouldn't really happen..
-        rootJoint = new Node();
-        rootJoint->setId(id);
-        _gamePlayFile.addNode(rootJoint);
+        skeleton = new Node();
+        skeleton->setId(id);
+        _gamePlayFile.addNode(skeleton);
     }
 
-    skin->setNode(rootJoint);
-    
     // Resolve and set joints array for skin
-    std::list<Node*> joints;
+    std::list<Node*> _joints;
     const std::list<std::string>& jointNames = skin->getJointNames();
     for (std::list<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
     {
@@ -1255,10 +1273,10 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
         if (obj)
         {
             Node* node = (Node*)obj;
-            joints.push_back(node);
+            _joints.push_back(node);
         }
     }
-    skin->setJoints(joints);
+    skin->setJoints(_joints);
 }
 
 Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
@@ -1267,20 +1285,6 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     Model* model = new Model();
     MeshSkin* skin = new MeshSkin();
 
-    // MeshSkins have an animation container but we need to find an appropriate ID for it.
-    // If the <controller> has an ID, use that ID as the animation's ID.
-    // Need to break const qualified in order to get the parent.
-    daeElement* e = ((domSkin*)skinElement)->getParent();
-    if (e->getElementType() == COLLADA_TYPE::CONTROLLER)
-    {
-        const domController* controller = (domController*)e;
-        const char* controllerId = controller->getId();
-        if (controllerId)
-        {
-            skin->setAnimationId(controllerId);
-        }
-    }
-
     // Bind Shape Matrix
     const domSkin::domBind_shape_matrix* bindShapeMatrix = skinElement->getBind_shape_matrix();
     if (bindShapeMatrix)
@@ -1294,19 +1298,19 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     }
 
     // Read and set our joints
-    domSkin::domJointsRef joints = skinElement->getJoints();
-    domInputLocal_Array& jointInputs = joints->getInput_array();
+    domSkin::domJointsRef _joints = skinElement->getJoints();
+    domInputLocal_Array& jointInputs = _joints->getInput_array();
 
 
     // Process "JOINT" input semantic first (we need to do this to set the joint count)
     unsigned int jointCount = 0;
     for (unsigned int i = 0; i < jointInputs.getCount(); i++)
     {
-        domInputLocalRef input = jointInputs.get(i);    
-        std::string inputSemantic = std::string(input->getSemantic());                
+        domInputLocalRef input = jointInputs.get(i);
+        std::string inputSemantic = std::string(input->getSemantic());
         domURIFragmentType* sourceURI = &input->getSource();
-        sourceURI->resolveElement();                
-        domSource* source = (domSource*)(daeElement*)sourceURI->getElement();
+        sourceURI->resolveElement();
+        const domSourceRef source = (domSource*)(daeElement*)sourceURI->getElement();
 
         if (equals(inputSemantic, "JOINT"))
         {
@@ -1317,12 +1321,12 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
             // Go through the joint list and conver them from sid to id because the sid information is
             // lost when converting to the gameplay binary format.
             for (std::list<std::string>::iterator i = list.begin(); i != list.end(); i++)
-            {   
+            {
                 daeSIDResolver resolver(source->getDocument()->getDomRoot(), i->c_str());
                 daeElement* element = resolver.getElement();
                 if (element && element->getElementType() == COLLADA_TYPE::NODE)
                 {
-                    domNode* node = dynamic_cast<domNode*>(static_cast<daeElement*>(element));
+                    domNodeRef node = daeSafeCast<domNode>(element);
                     const char* nodeId = node->getId();
                     if (nodeId && !equals(*i, nodeId))
                     {
@@ -1333,11 +1337,11 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
 
             // Get the joint count and set the capacities for both the
             jointCount = list.size();
-            jointInverseBindPoseMatrices.reserve(jointCount);
+            _jointInverseBindPoseMatrices.reserve(jointCount);
             unsigned int j = 0;
             for (std::list<std::string>::const_iterator i = list.begin(); i != list.end(); i++)
             {
-                jointLookupTable[*i] = j++;
+                _jointLookupTable[*i] = j++;
             }
             skin->setJointNames(list);
         }
@@ -1353,10 +1357,10 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     // Process "INV_BIND_MATRIX" next
     for (unsigned int i = 0; i < jointInputs.getCount(); i++)
     {
-        domInputLocalRef input = jointInputs.get(i);    
-        std::string inputSemantic = std::string(input->getSemantic());                
+        domInputLocalRef input = jointInputs.get(i);
+        std::string inputSemantic = std::string(input->getSemantic());
         domURIFragmentType* sourceURI = &input->getSource();
-        sourceURI->resolveElement();                
+        sourceURI->resolveElement();
         domSource* source = (domSource*)(daeElement*)sourceURI->getElement();
 
         if (equals(inputSemantic, "INV_BIND_MATRIX"))
@@ -1367,50 +1371,52 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
 
             for (unsigned int j = 0; j < jointCount; j++)
             {
-                Matrix matrix((float)matrixFloats.get(jointIndex + 0), (float)matrixFloats.get(jointIndex + 4), (float)matrixFloats.get(jointIndex + 8), (float)matrixFloats.get(jointIndex + 12), 
-                              (float)matrixFloats.get(jointIndex + 1), (float)matrixFloats.get(jointIndex + 5), (float)matrixFloats.get(jointIndex + 9), (float)matrixFloats.get(jointIndex + 13), 
-                              (float)matrixFloats.get(jointIndex + 2), (float)matrixFloats.get(jointIndex + 6), (float)matrixFloats.get(jointIndex + 10), (float)matrixFloats.get(jointIndex + 14), 
-                              (float)matrixFloats.get(jointIndex + 3), (float)matrixFloats.get(jointIndex + 7), (float)matrixFloats.get(jointIndex + 11), (float)matrixFloats.get(jointIndex + 15));    
+                Matrix matrix((float)matrixFloats.get(jointIndex + 0), (float)matrixFloats.get(jointIndex + 4), (float)matrixFloats.get(jointIndex + 8), (float)matrixFloats.get(jointIndex + 12),
+                              (float)matrixFloats.get(jointIndex + 1), (float)matrixFloats.get(jointIndex + 5), (float)matrixFloats.get(jointIndex + 9), (float)matrixFloats.get(jointIndex + 13),
+                              (float)matrixFloats.get(jointIndex + 2), (float)matrixFloats.get(jointIndex + 6), (float)matrixFloats.get(jointIndex + 10), (float)matrixFloats.get(jointIndex + 14),
+                              (float)matrixFloats.get(jointIndex + 3), (float)matrixFloats.get(jointIndex + 7), (float)matrixFloats.get(jointIndex + 11), (float)matrixFloats.get(jointIndex + 15));
 
-                jointInverseBindPoseMatrices.push_back(matrix);
+                _jointInverseBindPoseMatrices.push_back(matrix);
                 jointIndex += 16;
             }
         }
     }
 
-    skin->setBindPoses(jointInverseBindPoseMatrices);
+    skin->setBindPoses(_jointInverseBindPoseMatrices);
 
     // Get the vertex weights inputs
-    domSkin::domVertex_weights* vertexWeights =  skinElement->getVertex_weights();        
+    domSkin::domVertex_weights* vertexWeights =  skinElement->getVertex_weights();
     domInputLocalOffset_Array& vertexWeightsInputs = vertexWeights->getInput_array();
-    unsigned int vertexWeightsCount = (unsigned int)vertexWeights->getCount();    
-    domListOfFloats jointWeights;    
+    unsigned int vertexWeightsCount = (unsigned int)vertexWeights->getCount();
+    domListOfFloats jointWeights;
 
     for (unsigned int i = 0; i < jointInputs.getCount(); i++)
     {
         domInputLocalOffsetRef input = vertexWeightsInputs.get(i);
-        std::string inputSemantic = std::string(input->getSemantic());                
+        std::string inputSemantic = std::string(input->getSemantic());
         domURIFragmentType* sourceURI = &input->getSource();
-        sourceURI->resolveElement();                
-        domSource* source = (domSource*)(daeElement*)sourceURI->getElement();                
+        sourceURI->resolveElement();
+        domSource* source = (domSource*)(daeElement*)sourceURI->getElement();
 
         if (equals(inputSemantic, "WEIGHT"))
         {
             domFloat_array* weights = source->getFloat_array();
             if (weights)
+            {
                 jointWeights = weights->getValue();
+            }
         }
-    }    
+    }
     
     // Get the number of joint influences per vertex
-    domSkin::domVertex_weights::domVcount* vCountElement = vertexWeights->getVcount();    
-    domListOfUInts skinVertexInfluenceCounts = vCountElement->getValue();                
+    domSkin::domVertex_weights::domVcount* vCountElement = vertexWeights->getVcount();
+    domListOfUInts skinVertexInfluenceCounts = vCountElement->getValue();
     // Get the joint/weight pair data.
     domSkin::domVertex_weights::domV* vElement = vertexWeights->getV();
     domListOfInts skinVertexJointWeightPairIndices = vElement->getValue();
         
     // Get the vertex influence count for any given vertex (up to max of 4)
-    unsigned int maxVertexInfluencesCount = SCENE_SKIN_VERTEXINFLUENCES_MAX;    
+    unsigned int maxVertexInfluencesCount = SCENE_SKIN_VERTEXINFLUENCES_MAX;
     skin->setVertexInfluenceCount(maxVertexInfluencesCount);
 
     // Get the vertex blend weights and joint indices and
@@ -1418,31 +1424,31 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     // These will be used and cleaned up later in LoadMesh
     int skinVertexInfluenceCountTotal = skinVertexInfluenceCounts.getCount();
     int totalVertexInfluencesCount = vertexWeightsCount * maxVertexInfluencesCount;
-    vertexBlendWeights = new float[totalVertexInfluencesCount];
-    vertexBlendIndices = new unsigned int[totalVertexInfluencesCount];
+    _vertexBlendWeights = new float[totalVertexInfluencesCount];
+    _vertexBlendIndices = new unsigned int[totalVertexInfluencesCount];
 
     // Preset the default blend weights to 0.0f (no effect) and blend indices to 0 (uses the first which when multiplied
     // will have no effect anyhow.
-    memset(vertexBlendWeights, 0, totalVertexInfluencesCount * sizeof(float));        
-    memset(vertexBlendIndices , 0, totalVertexInfluencesCount * sizeof(unsigned int));    
+    memset(_vertexBlendWeights, 0, totalVertexInfluencesCount * sizeof(float));
+    memset(_vertexBlendIndices , 0, totalVertexInfluencesCount * sizeof(unsigned int));
     
-    int vOffset = 0;        
-    int weightOffset = 0;    
+    int vOffset = 0;
+    int weightOffset = 0;
 
-    // Go through all the skin vertex influence weights from the indexed data.    
+    // Go through all the skin vertex influence weights from the indexed data.
     for (int i = 0; i < skinVertexInfluenceCountTotal; i++)
-    {            
-        // Get the influence count and directly get the vertext blend weights and indices.        
-        unsigned int vertexInfluenceCount = (unsigned int)skinVertexInfluenceCounts.get(i);        
+    {
+        // Get the influence count and directly get the vertext blend weights and indices.
+        unsigned int vertexInfluenceCount = (unsigned int)skinVertexInfluenceCounts.get(i);
         float vertexInfluencesTotalWeights = 0.0f;
         std::vector<SkinnedVertexWeightPair> vertexInfluences;
         //vertexInfluences.SetCapacity(vertexInfluenceCount);
 
         // Get the index/weight pairs and some the weight totals while at it.
         for (unsigned int j = 0; j < vertexInfluenceCount; j++)
-        {        
+        {
             float weight = (float)jointWeights.get((unsigned int)skinVertexJointWeightPairIndices[vOffset + 1]);
-            int index = (int)skinVertexJointWeightPairIndices[vOffset];            
+            int index = (int)skinVertexJointWeightPairIndices[vOffset];
             
             // Set invalid index corresponding weights to zero
             if (index < 0 || index > (int)vertexWeightsCount)
@@ -1460,25 +1466,25 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
 
         // Get up the the maximum vertex weight influence count.
          for (unsigned int j = 0; j < maxVertexInfluencesCount; j++)
-        {            
-            if (j < vertexInfluenceCount)                
-            {        
+        {
+            if (j < vertexInfluenceCount)
+            {
                 SkinnedVertexWeightPair pair = vertexInfluences[j];
-                vertexBlendIndices[weightOffset] = pair.BlendIndex;
+                _vertexBlendIndices[weightOffset] = pair.BlendIndex;
                     
-                if (vertexInfluencesTotalWeights > 0.0f)        
-                {                
-                    vertexBlendWeights[weightOffset] = pair.BlendWeight;
+                if (vertexInfluencesTotalWeights > 0.0f)
+                {
+                    _vertexBlendWeights[weightOffset] = pair.BlendWeight;
                 }
                 else
                 {
                     if (j == 0)
                     {
-                        vertexBlendWeights[weightOffset] = 1.0f;
+                        _vertexBlendWeights[weightOffset] = 1.0f;
                     }
                     else
                     {
-                        vertexBlendWeights[weightOffset] = 0.0f;
+                        _vertexBlendWeights[weightOffset] = 0.0f;
                     }
                 }
             }
@@ -1641,8 +1647,10 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             // If there is a triangle array with a different number of inputs, this is not supported.
             if (inputCount != (unsigned int)inputArray.getCount())
             {
-                for (size_t i = 0; i < polygonInputs.size(); i++)
-                    delete polygonInputs[i];
+                for (size_t j = 0; j < polygonInputs.size(); j++)
+                {
+                    delete polygonInputs[j];
+                }
                 warning(std::string("Triangles do not all have the same number of input sources for geometry mesh: ") + geometryId);
                 return false;
             }
@@ -1684,7 +1692,9 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             const domListOfFloats& source = polygonInputs[k]->sourceValues;
             unsigned int offset = polygonInputs[k]->offset;
             if (offset > maxOffset)
+            {
                 maxOffset = offset;
+            }
             int type = polygonInputs[k]->type;
 
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
@@ -1692,19 +1702,19 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             {
             case POSITION:
                 vertex.reset();
-                if (vertexBlendWeights && vertexBlendIndices)
+                if (_vertexBlendWeights && _vertexBlendIndices)
                 {
                     vertex.hasWeights = true;
 
-                    vertex.blendWeights.x =  vertexBlendWeights[polyIndex * 4];
-                    vertex.blendWeights.y =  vertexBlendWeights[polyIndex * 4 + 1];
-                    vertex.blendWeights.z =  vertexBlendWeights[polyIndex * 4 + 2];
-                    vertex.blendWeights.w =  vertexBlendWeights[polyIndex * 4 + 3];
+                    vertex.blendWeights.x =  _vertexBlendWeights[polyIndex * 4];
+                    vertex.blendWeights.y =  _vertexBlendWeights[polyIndex * 4 + 1];
+                    vertex.blendWeights.z =  _vertexBlendWeights[polyIndex * 4 + 2];
+                    vertex.blendWeights.w =  _vertexBlendWeights[polyIndex * 4 + 3];
 
-                    vertex.blendIndices.x =  (float)vertexBlendIndices[polyIndex * 4];
-                    vertex.blendIndices.y =  (float)vertexBlendIndices[polyIndex * 4 + 1];
-                    vertex.blendIndices.z =  (float)vertexBlendIndices[polyIndex * 4 + 2];
-                    vertex.blendIndices.w =  (float)vertexBlendIndices[polyIndex * 4 + 3];
+                    vertex.blendIndices.x =  (float)_vertexBlendIndices[polyIndex * 4];
+                    vertex.blendIndices.y =  (float)_vertexBlendIndices[polyIndex * 4 + 1];
+                    vertex.blendIndices.z =  (float)_vertexBlendIndices[polyIndex * 4 + 2];
+                    vertex.blendIndices.w =  (float)_vertexBlendIndices[polyIndex * 4 + 3];
                 }
 
                 vertex.position.x = (float)source.get(polyIndex * 3);
@@ -1829,7 +1839,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
         mesh->addVetexAttribute(COLOR, 3);
     }
     // Skinning BlendWeights BlendIndices
-    if (hasWeights /*vertexBlendWeights && vertexBlendIndices*/)
+    if (hasWeights /*_vertexBlendWeights && _vertexBlendIndices*/)
     {
         mesh->addVetexAttribute(BLENDWEIGHTS, 4);
         mesh->addVetexAttribute(BLENDINDICES, 4);
@@ -1849,35 +1859,6 @@ void DAESceneEncoder::warning(const char* message)
     printf("Warning: %s\n", message);
 }
 
-void DAESceneEncoder::getJointNames(domSource* source, std::list<std::string>& list)
-{
-    // BLENDER used name_array
-    const domName_arrayRef& nameArray = source->getName_array();
-    if (nameArray.cast())
-    {
-        domListOfNames& ids = nameArray->getValue();
-        size_t jointCount = (size_t)nameArray->getCount();
-        for (size_t j = 0; j < jointCount; j++)
-        {
-            list.push_back(std::string(ids.get(j)));
-        }
-    }
-    else
-    {
-        // Seymour used IDREF_array
-        const domIDREF_arrayRef& idArray = source->getIDREF_array();
-        if (idArray.cast())
-        {
-            xsIDREFS& ids = idArray->getValue();
-            size_t jointCount = (size_t)idArray->getCount();
-            for (size_t j = 0; j < jointCount; j++)
-            {
-                list.push_back(std::string(ids.get(j).getID()));
-            }
-        }
-    }
-}
-
 int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
 {
     int type = -1;

+ 32 - 27
gameplay-encoder/src/DAESceneEncoder.h

@@ -8,6 +8,7 @@
 #include <iostream>
 #include <list>
 #include <vector>
+#include <ctime>
 
 #include <dae.h>
 #include <dae/daeSIDResolver.h>
@@ -38,6 +39,8 @@
 #include "Transform.h"
 #include "DAEChannelTarget.h"
 #include "GPBFile.h"
+#include "DAEUtil.h"
+#include "EncoderArguments.h"
 
 using namespace gameplay;
 
@@ -63,7 +66,7 @@ public:
     /**
      * Writes out encoded Collada 1.4 file.
      */
-    void write(const std::string& filepath, const char* nodeId, bool text);
+    void write(const std::string& filepath, const EncoderArguments& arguments);
 
 private:
 
@@ -89,14 +92,22 @@ private:
         unsigned int BlendIndex;
 
         SkinnedVertexWeightPair(float blendWeight, unsigned int blendIndex) : BlendWeight(blendWeight), BlendIndex(blendIndex)
-        {                
-        }            
+        {
+        }
 
         bool operator < (const SkinnedVertexWeightPair& value) const
         {
             return value.BlendWeight < BlendWeight;
         }
     };
+
+    /**
+     * Optimizes the COLLADA dom based on the arguments passed to the encoder.
+     * 
+     * @param arguments The command line arguments passed to the encoder.
+     * @param dom The COLLADA dom.
+     */
+    void optimizeCOLLADA(const EncoderArguments& arguments, domCOLLADA* dom);
     
     void triangulate(DAE* dae);
     
@@ -119,9 +130,9 @@ private:
     /**
      * Loads a COLLADA animation element.
      * 
-     * @param animationRef Pointer to the animation dom element to load from.
+     * @param animationRef The animation dom element to load from.
      */
-    void loadAnimation(const domAnimation* animationRef);
+    void loadAnimation(const domAnimationRef animationRef);
 
     CameraInstance* loadCamera(const domCamera* cameraRef);
     LightInstance* loadLight(const domLight* lightRef);
@@ -136,13 +147,14 @@ private:
      * @param source The source dom element to load interpolation curves from.
      * @param animation The destination animation to copy to.
      */
-    void loadInterpolation(const domSource* source, AnimationChannel* animation);
+    void loadInterpolation(const domSourceRef source, AnimationChannel* animation);
 
     /**
      * Returns the active camera node for the given scene.
      * 
      * @param visualScene The collada visual scene node.
      * @param scene The gameplay scene node.
+     * 
      * @return The active camera node or NULL if one was not found.
      */
     Node* findSceneActiveCameraNode(const domVisual_scene* visualScene, Scene* scene);
@@ -162,11 +174,6 @@ private:
      */
     void calcTransform(domNode* domNode, Matrix& dstTransform);
 
-    /**
-     * Gets the joint names for the given source and appends them to the given list.
-     */
-    void getJointNames(domSource* source, std::list<std::string>& list);
-
     void warning(const std::string& message);
     void warning(const char* message);
 
@@ -176,20 +183,15 @@ private:
      * Target ID is "Cube"
      * The target attribute is "location.X"
      * 
-     * @param channelRef Pointer to the channel dom element.
-     * @param animation The animation to copy to.
-     */
-    void loadTarget(const domChannel* channelRef, AnimationChannel* animation);
-
-    /**
-     * Finds the ID for an animation.
-     * If the COLLADA animation element doesn't have an ID then this method will trying 
-     * to find an appropriate ID for the animation.
+     * @param channelRef The channel dom element.
+     * @param animationChannel The animation to copy to.
      * 
-     * @param animationRef The COLLADA animation element to find an ID for.
-     * @return The ID string for the animation.
+     * @return True if the animation channel data was loaded without error; false if there was an error.
      */
-    std::string findAnimationId(const domAnimation* animationRef);
+    bool loadTarget(const domChannelRef& channelRef, AnimationChannel* animationChannel);
+
+    void begin();
+    void end(const char* str);
 
     /**
      * Copies float values from a domFloat_array to a std::vector<float>.
@@ -207,15 +209,18 @@ private:
      */
     static int getVertexUsageType(const std::string& semantic);
     
+private:
     DAE* _collada;        // Collada datastore in memory to read from.
+    domCOLLADA* _dom;
     FILE* file;        // Output file to write to.
     GPBFile _gamePlayFile;
 
-    std::map<std::string, int> jointLookupTable;
-    std::vector<Matrix>jointInverseBindPoseMatrices;
-    float* vertexBlendWeights;
-    unsigned int* vertexBlendIndices;
+    std::map<std::string, int> _jointLookupTable;
+    std::vector<Matrix>_jointInverseBindPoseMatrices;
+    float* _vertexBlendWeights;
+    unsigned int* _vertexBlendIndices;
 
+    clock_t _begin;
 };
 
 #endif

+ 303 - 0
gameplay-encoder/src/DAEUtil.cpp

@@ -0,0 +1,303 @@
+
+#include "DAEUtil.h"
+
+/**
+ * Returns the index of the skeleton in skeletonArray that points to the given node.
+ * 
+ * @param skeletonArray The array of skeletons to search.
+ * @param node The target node.
+ * 
+ * @return The index in skeletonArray or -1 if not found.
+ */
+int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node);
+
+void getJointNames(const domSourceRef source, std::list<std::string>& list)
+{
+    // BLENDER used name_array
+    const domName_arrayRef& nameArray = source->getName_array();
+    if (nameArray.cast())
+    {
+        domListOfNames& ids = nameArray->getValue();
+        size_t jointCount = (size_t)nameArray->getCount();
+        for (size_t j = 0; j < jointCount; j++)
+        {
+            list.push_back(std::string(ids.get(j)));
+        }
+    }
+    else
+    {
+        // Seymour used IDREF_array
+        const domIDREF_arrayRef& idArray = source->getIDREF_array();
+        if (idArray.cast())
+        {
+            xsIDREFS& ids = idArray->getValue();
+            size_t jointCount = (size_t)idArray->getCount();
+            for (size_t j = 0; j < jointCount; j++)
+            {
+                list.push_back(std::string(ids.get(j).getID()));
+            }
+        }
+    }
+}
+
+void getJointNames(const domSkin* skin, std::list<std::string>& list)
+{
+    const domSkin::domJointsRef& joints = skin->getJoints();
+    const domInputLocal_Array& inputArray = joints->getInput_array();
+    size_t inputCount = inputArray.getCount();
+    for (size_t i = 0; i < inputCount; i++)
+    {
+        const domInputLocalRef input = inputArray.get(i);
+        const char* semantic = input->getSemantic();
+        if (strcmp(semantic, "JOINT") == 0)
+        {
+            daeElement* sourceElement = input->getSource().getElement();
+            if (sourceElement)
+            {
+                const domSourceRef source = daeSafeCast<domSource>(sourceElement);
+                getJointNames(source, list);
+            }
+        }
+    }
+}
+
+domSource* getInputSource(const domChannelRef& channel)
+{
+    daeElement* element = channel->getSource().getElement();
+    if (element && element->getElementType() == COLLADA_TYPE::SAMPLER)
+    {
+        domSampler* sampler = daeSafeCast<domSampler>(element);
+        const domInputLocal_Array& inputArray = sampler->getInput_array();
+        size_t inputArrayCount = inputArray.getCount();
+        for (size_t i = 0; i < inputArrayCount; i++)
+        {
+            const domInputLocalRef& input = inputArray.get(i);
+            if (strcmp(input->getSemantic(), "INPUT") == 0)
+            {
+                daeElement* e = input->getSource().getElement();
+                if (e && e->getElementType() == COLLADA_TYPE::SOURCE)
+                {
+                    domSource* source = daeSafeCast<domSource>(e);
+                    assert(source);
+                    return source;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+const domSamplerRef getSampler(const domChannelRef& channel)
+{
+    const domURIFragmentType& uri = channel->getSource();
+    daeElementRef element = uri.getElement();
+    if (element && element->getElementType() == COLLADA_TYPE::SAMPLER)
+    {
+        const domSamplerRef sampler = daeSafeCast<domSampler>(element);
+        return sampler;
+    }
+    // resolve the source manually by searching for the sampler in the animation that the channel is a child of.
+    const std::string& id = uri.id();
+    const daeElementRef& parent = channel->getParent();
+    if (parent && parent->getElementType() == COLLADA_TYPE::ANIMATION)
+    {
+        const domAnimationRef animation = daeSafeCast<domAnimation>(parent);
+        
+        const domSampler_Array& samplerArray = animation->getSampler_array();
+        size_t count = samplerArray.getCount();
+        for (size_t i = 0; i < count; i++)
+        {
+            const domSamplerRef& sampler = samplerArray.get(i);
+            if (id.compare(sampler->getId()) == 0)
+            {
+                return sampler;
+            }
+        }
+    }
+    return NULL;
+}
+
+const domSourceRef getSource(const domInputLocalRef& inputLocal, const domAnimationRef& animation)
+{
+    const domURIFragmentType& uri = inputLocal->getSource();
+    daeElementRef element = uri.getElement();
+    if (element && element->getElementType() == COLLADA_TYPE::SAMPLER)
+    {
+        const domSourceRef source = daeSafeCast<domSource>(element);
+        return source;
+    }
+    // Resolve the URI by searching through the animation's list of sources
+    const std::string& id = uri.id();
+    const domSource_Array& sourceArray = animation->getSource_array();
+    size_t count = sourceArray.getCount();
+    for (size_t i = 0; i < count; i++)
+    {
+        const domSourceRef source = sourceArray.get(i);
+        if (id.compare(source->getId()) == 0)
+        {
+            return source;
+        }
+    }
+    return NULL;
+}
+
+const domName_arrayRef getSourceNameArray(const domSourceRef& source)
+{
+    const domName_arrayRef& nameArray = source->getName_array();
+    if (nameArray)
+    {
+        return nameArray;
+    }
+    daeTArray<daeSmartRef<daeElement>> children;
+    source->getChildren(children);
+    size_t childCount = children.getCount();
+    for (size_t i = 0; i < childCount; i++)
+    {
+        const daeElementRef element = children.get(i);
+        if (element->getElementType() == COLLADA_TYPE::NAME_ARRAY)
+        {
+            return daeSafeCast<domName_array>(element);
+        }
+    }
+    return NULL;
+}
+
+const domInstance_controller::domSkeletonRef getSkeleton(const domInstance_controllerRef& instanceController)
+{
+    domInstance_controller::domSkeleton_Array& skeletonArray = instanceController->getSkeleton_array();
+    size_t count = skeletonArray.getCount();
+    if (count == 0)
+    {
+        return NULL;
+    }
+    if (count == 1)
+    {
+        return skeletonArray.get(0);
+    }
+    // Maya sometimes outputs multiple skeleton elements.
+    // Find the skeleton element that points to the root most node.
+    const domInstance_controller::domSkeletonRef& currentSkeleton = skeletonArray.get(0);
+    const daeElementRef element = currentSkeleton->getValue().getElement();
+    if (element && element->getElementType() == COLLADA_TYPE::NODE)
+    {
+        domNode* node = daeSafeCast<domNode>(element);
+        int index = 0;
+        bool loop = true;
+        do
+        {
+            daeElementRef parent = node->getParent();
+            if (parent && parent->getElementType() == COLLADA_TYPE::NODE)
+            {
+                domNodeRef parentNode = daeSafeCast<domNode>(parent);
+                int result = getIndex(skeletonArray, parentNode);
+                if (result >= 0)
+                {
+                    index = result;
+                }
+                node = parentNode;
+            }
+            else
+            {
+                loop = false;
+            }
+        } while (loop);
+        if (index >= 0)
+        {
+            return skeletonArray.get(index);
+        }
+    }
+    return NULL;
+}
+
+bool equalKeyTimes(const domSource* s1, const domSource* s2)
+{
+    // TODO: shouldn't assume that the source has a float array.
+    const domFloat_arrayRef& f1 = s1->getFloat_array();
+    const domFloat_arrayRef& f2 = s2->getFloat_array();
+    if (f1->getCount() == f2->getCount())
+    {
+        const domListOfFloats& list1 = f1->getValue();
+        const domListOfFloats& list2 = f2->getValue();
+
+        size_t count = (size_t)f1->getCount();
+        for (size_t i = 0; i < count; i++)
+        {
+            if (list1.get(i) != list2.get(i))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+    return false;
+}
+
+bool equalKeyTimes(const domChannelRef& c1, const domChannelRef& c2)
+{
+    domSource* s1 = getInputSource(c1);
+    domSource* s2 = getInputSource(c2);
+    assert(s1);
+    assert(s2);
+    return equalKeyTimes(s1, s2);
+}
+
+void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& animation)
+{
+    assert(channel);
+    assert(animation);
+
+    daeElement::removeFromParent(channel);
+    animation->add(channel); // move channel
+
+    daeElementRef element = channel->getSource().getElement();
+    if (element)
+    {
+        domSamplerRef sampler = daeSafeCast<domSampler>(element);
+
+        domInputLocal_Array& inputArray = sampler->getInput_array();
+        size_t inputArrayCount = inputArray.getCount();
+        for (size_t i = 0; i < inputArrayCount; i++)
+        {
+            inputArray = sampler->getInput_array();
+            const domInputLocalRef& input = inputArray.get(i);
+            daeElementRef element = input->getSource().getElement();
+            if (element && element->getElementType() == COLLADA_TYPE::SOURCE)
+            {
+                domSourceRef source = daeSafeCast<domSource>(element);
+                assert(source);
+                daeElement::removeFromParent(source);
+                animation->add(source); // move source
+            }
+        }
+        daeElement::removeFromParent(sampler);
+        animation->add(sampler); // move sampler
+    }
+}
+
+bool isEmptyAnimation(domAnimationRef& animation)
+{
+    return animation->getAnimation_array().getCount() == 0 &&
+           animation->getChannel_array().getCount() == 0 &&
+           animation->getSampler_array().getCount() == 0 &&
+           animation->getSource_array().getCount() == 0;
+}
+
+int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node)
+{
+    const std::string nodeId = node->getId();
+    size_t count = skeletonArray.getCount();
+    for (size_t i = 0; i < count; i++)
+    {
+        const domInstance_controller::domSkeletonRef& skeleton = skeletonArray.get(i);
+        daeElementRef element = skeleton->getValue().getElement();
+        if (element->getElementType() == COLLADA_TYPE::NODE)
+        {
+            domNodeRef targetNode = daeSafeCast<domNode>(element);
+            if (nodeId.compare(targetNode->getId()) == 0)
+            {
+                return i;
+            }
+        }
+    }
+    return -1;
+}

+ 126 - 0
gameplay-encoder/src/DAEUtil.h

@@ -0,0 +1,126 @@
+/*
+ * DAEUtil.h
+ */
+
+#ifndef DAEUTIL_H_
+#define DAEUTIL_H_
+
+#include <iostream>
+#include <list>
+#include <vector>
+
+#include <dae.h>
+#include <dae/daeSIDResolver.h>
+#include <dae/domAny.h>
+#include <dom/domCOLLADA.h>
+#include <dom/domConstants.h>
+#include <dom/domElements.h>
+#include <dom/domProfile_COMMON.h>
+
+#include "Base.h"
+
+using namespace gameplay;
+
+/**
+ * Gets the joint names for the given source and appends them to the given list.
+ * 
+ * @param source The source element to search in.
+ * @param list The list to append the joint names to.
+ */
+void getJointNames(const domSourceRef source, std::list<std::string>& list);
+
+/**
+ * Gets the joint names for the given skin and appends them to the given list.
+ * 
+ * @param skin The skin element to search in.
+ * @param list The list to append the joint names to.
+ */
+void getJointNames(const domSkin* skin, std::list<std::string>& list);
+
+/**
+ * Gets the input source from the given channel.
+ * 
+ * @param channel The channel to search in.
+ * 
+ * @return The source element or NULL if not found.
+ */
+domSource* getInputSource(const domChannelRef& channel);
+
+/**
+ * Returns the sampler from the given channel.
+ * 
+ * @param channel The channel dom element.
+ * 
+ * @return The sampler or NULL if not found.
+ */
+const domSamplerRef getSampler(const domChannelRef& channel);
+
+/**
+ * Returns the source from the given sampler input. 
+ * Searchs within the given animation.
+ * 
+ * @param inputLocal The input element within a sampler.
+ * @param animation The animation to search within.
+ * 
+ * @return The source or NULL if not found.
+ */
+const domSourceRef getSource(const domInputLocalRef& inputLocal, const domAnimationRef& animation);
+
+/**
+ * Returns the name array from the given source.
+ * 
+ * @param source The source element.
+ * 
+ * @return The name array or NULL if not found.
+ */
+const domName_arrayRef getSourceNameArray(const domSourceRef& source);
+
+/**
+ * Returns one skeleton from the given instance controller.
+ * The COLLADA spec says that instance_controller can have multiple skeletons but we only need one.
+ * Maya sometimes exports multiple skeleton nodes so this function will try to find the correct one.
+ * 
+ * @param instanceController The instance_controller element.
+ * 
+ * @return The skeleton or NULL if not found.
+ */
+const domInstance_controller::domSkeletonRef getSkeleton(const domInstance_controllerRef& instanceController);
+
+/**
+ * Returns true if the two given animation channels have equal key time input source.
+ * 
+ * @param c1 Channel one to compare.
+ * @param c2 Channel two to compare.
+ * 
+ * @return True if the channels have the same key times, false otherwise.
+ */
+bool equalKeyTimes(const domChannelRef& c1, const domChannelRef& c2);
+
+/**
+ * Returns true if the two sources have the same key times.
+ * 
+ * @param s1 Source one.
+ * @param s2 Source two.
+ * 
+ * @return True true if the key times are equal, false otherwise.
+ */
+bool equalKeyTimes(const domSource* s1, const domSource* s2);
+
+/**
+ * Moves a channel and the sources it uses to the destination animation.
+ * 
+ * @param channel The channel to move.
+ * @param animation The destination animation to copy to.
+ */
+void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& animation);
+
+/**
+ * Returns true if the given animation is empty and contains no children.
+ * 
+ * @param animation The animation element to check.
+ * 
+ * @return True if the animation has no children, false otherwise.
+ */
+bool isEmptyAnimation(domAnimationRef& animation);
+
+#endif

+ 4 - 4
gameplay-encoder/src/Effect.cpp

@@ -23,14 +23,14 @@ const char* Effect::getElementName(void) const
 void Effect::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    write(vertexShader, file);
-    write(fragmentShader, file);
+    write(_vertexShader, file);
+    write(_fragmentShader, file);
 }
 void Effect::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "vertexShader", vertexShader);
-    fprintfElement(file, "fragmentShader", fragmentShader);
+    fprintfElement(file, "vertexShader", _vertexShader);
+    fprintfElement(file, "fragmentShader", _fragmentShader);
     fprintElementEnd(file);
 }
 

+ 3 - 2
gameplay-encoder/src/Effect.h

@@ -28,8 +28,9 @@ public:
 
     virtual void writeText(FILE* file);
 
-    std::string vertexShader;
-    std::string fragmentShader;
+private:
+    std::string _vertexShader;
+    std::string _fragmentShader;
 };
 
 

+ 275 - 0
gameplay-encoder/src/EncoderArguments.cpp

@@ -0,0 +1,275 @@
+#include "EncoderArguments.h"
+
+#include "StringUtil.h"
+
+#ifdef WIN32
+    #define PATH_MAX    _MAX_PATH
+    #define realpath(A,B)    _fullpath(B,A,PATH_MAX)
+#endif
+
+EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
+    _fontSize(0),
+    _parseError(false),
+    _fontPreview(false),
+    _textOutput(false),
+    _daeOutput(false)
+{
+    if (argc > 1)
+    {
+        size_t filePathIndex = argc - 1;
+        if (argv[filePathIndex])
+        {
+            _filePath.assign(getRealPath(argv[filePathIndex]));
+        }
+        
+        // read the options
+        std::vector<std::string> options;
+        for (size_t i = 1; i < filePathIndex; i++)
+        {
+            options.push_back(argv[i]);
+        }
+        
+        for (size_t i = 0; i < options.size(); i++)
+        {
+            if (options[i][0] == '-')
+            {
+                readOption(options, &i);
+            }
+        }
+    }
+    else
+    {
+        _parseError = true;
+    }
+}
+
+EncoderArguments::~EncoderArguments(void)
+{
+}
+
+const std::string& EncoderArguments::getFilePath() const
+{
+    return _filePath;
+}
+
+const char* EncoderArguments::getFilePathPointer() const
+{
+    return _filePath.c_str();
+}
+
+const std::string& EncoderArguments::getDAEOutputPath() const
+{
+    return _daeOutputPath;
+}
+
+const std::vector<std::string>& EncoderArguments::getGroupAnimationNodeId() const
+{
+    return _groupAnimationNodeId;
+}
+
+const std::vector<std::string>& EncoderArguments::getGroupAnimationAnimationId() const
+{
+    return _groupAnimationAnimationId;
+}
+
+bool EncoderArguments::parseErrorOccured() const
+{
+    return _parseError;
+}
+
+bool EncoderArguments::fileExists() const
+{
+    if (_filePath.length() > 0)
+    {
+        struct stat buf;
+        if (stat(_filePath.c_str(), &buf) != -1)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+void EncoderArguments::printUsage() const
+{
+    fprintf(stderr,"Usage: gameplay-encoder [options] <filepath>\n");
+    fprintf(stderr,".dae file options:\n");
+    fprintf(stderr," -i <id>\tFilter by node ID\n");
+    fprintf(stderr," -t\tWrite text/xml\n");
+    fprintf(stderr," -groupAnimations <nodeID> <animationID>\tGroup all animation channels targetting the nodes into a new animation\n");
+    fprintf(stderr," -dae <filepath>\tOutput optimized DAE\n");
+    fprintf(stderr,".ttf file options:\n");
+    fprintf(stderr," -s <size of font> -p \n");
+    exit(8);
+}
+
+bool EncoderArguments::fontPreviewEnabled() const
+{
+    return _fontPreview;
+}
+
+bool EncoderArguments::textOutputEnabled() const
+{
+    return _textOutput;
+}
+
+bool EncoderArguments::DAEOutputEnabled() const
+{
+    return _daeOutput;
+}
+
+const char* EncoderArguments::getNodeId() const
+{
+    if (_nodeId.length() == 0)
+    {
+        return NULL;
+    }
+    return _nodeId.c_str();
+}
+
+unsigned int EncoderArguments::getFontSize() const
+{
+    return _fontSize;
+}
+
+EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
+{
+    if (_filePath.length() < 5)
+    {
+        return FILEFORMAT_UNKNOWN;
+    }
+    // Extract the extension
+    std::string ext = "";
+    size_t pos = _filePath.find_last_of(".");
+    if (pos != std::string::npos)
+    {
+        ext = _filePath.substr(pos + 1);
+    }
+    
+    // Match every supported extension with its format constant
+    if (ext.compare("dae") == 0 || ext.compare("DAE") == 0)
+    {
+        return FILEFORMAT_DAE;
+    }
+    if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
+    {
+        return FILEFORMAT_TTF;
+    }
+    if (ext.compare("gpb") == 0 || ext.compare("GPB") == 0)
+    {
+        return FILEFORMAT_GPB;
+    }
+
+    return FILEFORMAT_UNKNOWN;
+}
+
+void EncoderArguments::readOption(const std::vector<std::string>& options, size_t *index)
+{
+    const std::string& str = options[*index];
+    if (str.length() == 0 && str[0] != '-')
+    {
+        return;
+    }
+    switch (str[1])
+    {
+    case 'd':
+        if (str.compare("-dae") == 0)
+        {
+            // read one string, make sure not to go out of bounds
+            if ((*index + 1) >= options.size())
+            {
+                fprintf(stderr, "Error: -dae requires 1 argument.\n");
+                _parseError = true;
+                return;
+            }
+            (*index)++;
+            _daeOutputPath = options[*index];
+            _daeOutput = true;
+        }
+        break;
+    case 'g':
+        if (str.compare("-groupAnimations") == 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");
+                _parseError = true;
+                return;
+            }
+            (*index)++;
+            _groupAnimationNodeId.push_back(options[*index]);
+            (*index)++;
+            _groupAnimationAnimationId.push_back(options[*index]);
+        }
+        break;
+    case 'i':
+    case 'o':
+        // Node ID
+        (*index)++;
+        if (*index < options.size())
+        {
+            _nodeId.assign(options[*index]);
+        }
+        else
+        {
+            fprintf(stderr, "Error: missing arguemnt for -%c.\n", str[1]);
+            _parseError = true;
+            return;
+        }
+    case 'p':
+        _fontPreview = true;
+        break;
+    case 's':
+        // Font Size
+
+        // old format was -s##
+        if (str.length() > 2)
+        {
+            char n = str[2];
+            if (n > '0' && n <= '9')
+            {
+                const char* number = str.c_str() + 2;
+                _fontSize = atoi(number);
+                break;
+            }
+        }
+
+        (*index)++;
+        if (*index < options.size())
+        {
+            _fontSize = atoi(options[*index].c_str());
+        }
+        else
+        {
+            fprintf(stderr, "Error: missing arguemnt for -%c.\n", str[1]);
+            _parseError = true;
+            return;
+        }
+        break;
+    case 't':
+        _textOutput = true;
+        break;
+    default:
+        break;
+    }
+}
+
+std::string EncoderArguments::getRealPath(const std::string& filepath)
+{
+    char path[PATH_MAX + 1]; /* not sure about the "+ 1" */
+    realpath(filepath.c_str(), path);
+    replace_char(path, '\\', '/');
+    return std::string(path);
+}
+
+void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
+{
+    for (; *str != '\0'; str++)
+    {
+        if (*str == oldChar)
+        {
+            *str = newChar;
+        }
+    }
+}

+ 120 - 0
gameplay-encoder/src/EncoderArguments.h

@@ -0,0 +1,120 @@
+#ifndef ENCODERARGUMENTS_H_
+#define ENCODERARGUMENTS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <sys/stat.h>
+#include <vector>
+
+#include "Base.h"
+
+/**
+ * EncoderArguments handles parsing the command line arguments for the GamePlay Encoder.
+ */
+class EncoderArguments
+{
+public:
+
+    enum FileFormat
+    {
+        FILEFORMAT_UNKNOWN,
+        FILEFORMAT_DAE,
+        FILEFORMAT_TTF,
+        FILEFORMAT_GPB
+    };
+
+    /**
+     * Constructor.
+     */
+    EncoderArguments(size_t argc, const char** argv);
+
+    /**
+     * Destructor.
+     */
+    ~EncoderArguments(void);
+
+    /**
+     * Gets the file format from the file path based on the extension.
+     */
+    FileFormat getFileFormat() const;
+
+    /**
+     * Returns the file path.
+     */
+    const std::string& getFilePath() const;
+
+    /**
+     * Returns the char pointer to the file path string.
+     */
+    const char* EncoderArguments::getFilePathPointer() const;
+
+    /**
+     * Returns the path to where the DAE output should be written to.
+     */
+    const std::string& EncoderArguments::getDAEOutputPath() const;
+
+    const std::vector<std::string>& getGroupAnimationNodeId() const;
+    const std::vector<std::string>& getGroupAnimationAnimationId() const;
+
+    /**
+     * Returns true if an error occured while parsing the command line arguments.
+     */
+    bool parseErrorOccured() const;
+
+    /**
+     * Tests if a file exists on the file system.
+     * 
+     * @return True if the file exists; false otherwise.
+     */
+    bool fileExists() const;
+
+    /**
+     * Prints the usage information.
+     */
+    void printUsage() const;
+
+    bool fontPreviewEnabled() const;
+    bool textOutputEnabled() const;
+    bool DAEOutputEnabled() const;
+
+    const char* getNodeId() const;
+    unsigned int getFontSize() const;
+
+private:
+
+    /**
+     * Reads the command line option from the list of options starting at the given index.
+     * 
+     * @param options The list of command line options.
+     * @param index Pointer to the index within the options list. The index will be changed
+     *              if an option takes multiple arguments.
+     */
+    void readOption(const std::vector<std::string>& options, size_t *index);
+
+    static std::string getRealPath(const std::string& filepath);
+
+    /**
+     * Replaces all instance of oldChar with newChar in str.
+     */
+    static void replace_char(char* str, char oldChar, char newChar);
+
+private:
+    
+    std::string _filePath;
+    std::string _nodeId;
+    std::string _daeOutputPath;
+
+    unsigned int _fontSize;
+
+    bool _parseError;
+    bool _fontPreview;
+    bool _textOutput;
+    bool _daeOutput;
+
+    std::vector<std::string> _groupAnimationNodeId;
+    std::vector<std::string> _groupAnimationAnimationId;
+};
+
+#endif

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

@@ -31,6 +31,12 @@ void write(unsigned int value, FILE* file)
     assert(r == 1);
 }
 
+void write(unsigned long value, FILE* file)
+{
+    size_t r = fwrite(&value, sizeof(unsigned long), 1, file);
+    assert(r == 1);
+}
+
 void write(unsigned short value, FILE* file)
 {
     size_t r = fwrite(&value, sizeof(unsigned short), 1, file);
@@ -105,11 +111,17 @@ void fprintfMatrix4f(FILE* file, const float* m)
     {
         float v = m[i];
         if (v == 1.0f)
+        {
             fprintf(file, "1.0 ");
+        }
         else if (v == 0.0)
+        {
             fprintf(file, "0.0 ");
+        }
         else
+        {
             fprintf(file, "%f ",v);
+        }
     }
 }
 void skipString(FILE* file)

+ 1 - 0
gameplay-encoder/src/FileIO.h

@@ -58,6 +58,7 @@ void write(unsigned char value, FILE* file);
 void write(char value, FILE* file);
 void write(const char* str, FILE* file);
 void write(unsigned int value, FILE* file);
+void write(unsigned long value, FILE* file);
 void write(unsigned short value, FILE* file);
 void write(bool value, FILE* file);
 void write(float value, FILE* file);

+ 20 - 20
gameplay-encoder/src/GPBDecoder.cpp

@@ -3,7 +3,7 @@
 namespace gameplay
 {
 
-GPBDecoder::GPBDecoder(void) : file(NULL), outFile(NULL)
+GPBDecoder::GPBDecoder(void) : _file(NULL), _outFile(NULL)
 {
 }
 
@@ -15,25 +15,25 @@ GPBDecoder::~GPBDecoder(void)
 void GPBDecoder::readBinary(const std::string& filepath)
 {
     // open files
-    file = fopen(filepath.c_str(), "rb");
+    _file = fopen(filepath.c_str(), "rb");
     std::string outfilePath = filepath;
     outfilePath += ".xml";
-    outFile = fopen(outfilePath.c_str(), "w");
+    _outFile = fopen(outfilePath.c_str(), "w");
 
     // read and write files
     assert(validateHeading());
 
-    fprintf(outFile, "<root>\n");
+    fprintf(_outFile, "<root>\n");
     readRefs();
-    fprintf(outFile, "</root>\n");
+    fprintf(_outFile, "</root>\n");
 
 
     // close files
-    fclose(outFile);
-    outFile = NULL;
+    fclose(_outFile);
+    _outFile = NULL;
 
-    fclose(file);
-    file = NULL;
+    fclose(_file);
+    _file = NULL;
 }
 
 bool GPBDecoder::validateHeading()
@@ -51,7 +51,7 @@ bool GPBDecoder::validateHeading()
     }
     // read version
     unsigned char version[2];
-    fread(version, sizeof(unsigned char), 2, file);
+    fread(version, sizeof(unsigned char), 2, _file);
     // don't care about version
 
     return true;
@@ -59,7 +59,7 @@ bool GPBDecoder::validateHeading()
 
 void GPBDecoder::readRefs()
 {
-    fprintf(outFile, "<RefTable>\n");
+    fprintf(_outFile, "<RefTable>\n");
     // read number of refs
     unsigned int refCount;
     assert(read(&refCount));
@@ -67,26 +67,26 @@ void GPBDecoder::readRefs()
     {
         readRef();
     }
-    fprintf(outFile, "</RefTable>\n");
+    fprintf(_outFile, "</RefTable>\n");
 }
 
 void GPBDecoder::readRef()
-{   
-    std::string xref = readString(file);
+{
+    std::string xref = readString(_file);
     unsigned int type, offset;
     assert(read(&type));
     assert(read(&offset));
     
-    fprintf(outFile, "<Reference>\n");
-    fprintfElement(outFile, "xref", xref);
-    fprintfElement(outFile, "type", type);
-    fprintfElement(outFile, "offset", offset);
-    fprintf(outFile, "</Reference>\n");
+    fprintf(_outFile, "<Reference>\n");
+    fprintfElement(_outFile, "xref", xref);
+    fprintfElement(_outFile, "type", type);
+    fprintfElement(_outFile, "offset", offset);
+    fprintf(_outFile, "</Reference>\n");
 }
 
 bool GPBDecoder::read(unsigned int* ptr)
 {
-    return fread(ptr, sizeof(unsigned int), 1, file) == 1;
+    return fread(ptr, sizeof(unsigned int), 1, _file) == 1;
 }
 
 std::string GPBDecoder::readString(FILE* fp)

+ 2 - 2
gameplay-encoder/src/GPBDecoder.h

@@ -40,8 +40,8 @@ public:
     std::string readString(FILE* fp);
 
 private:
-    FILE* file;
-    FILE* outFile;
+    FILE* _file;
+    FILE* _outFile;
 };
 
 }

+ 48 - 67
gameplay-encoder/src/GPBFile.cpp

@@ -4,7 +4,7 @@ namespace gameplay
 {
 
 GPBFile::GPBFile(void)
-    : file(NULL)
+    : _file(NULL), _animationsAdded(false)
 {
 }
 
@@ -14,104 +14,108 @@ GPBFile::~GPBFile(void)
 
 void GPBFile::saveBinary(const std::string& filepath)
 {
-    file = fopen(filepath.c_str(), "w+b");
+    _file = fopen(filepath.c_str(), "w+b");
 
     // identifier
     char identifier[] = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' };
-    fwrite(identifier, 1, sizeof(identifier), file);
+    fwrite(identifier, 1, sizeof(identifier), _file);
 
     // version
-    fwrite(VERSION, 1, sizeof(VERSION), file);
+    fwrite(VERSION, 1, sizeof(VERSION), _file);
 
     // write refs
-    refTable.writeBinary(file);
+    _refTable.writeBinary(_file);
 
     // meshes
-    write(geometry.size(), file);
-    for (std::list<Mesh*>::const_iterator i = geometry.begin(); i != geometry.end(); i++)
+    write(_geometry.size(), _file);
+    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); i++)
     {
-        (*i)->writeBinary(file);
+        (*i)->writeBinary(_file);
     }
 
     // Objects
-    write(objects.size(), file);
-    for (std::list<Object*>::const_iterator i = objects.begin(); i != objects.end(); i++)
+    write(_objects.size(), _file);
+    for (std::list<Object*>::const_iterator i = _objects.begin(); i != _objects.end(); i++)
     {
-        (*i)->writeBinary(file);
+        (*i)->writeBinary(_file);
     }
 
-    refTable.updateOffsets(file);
+    _refTable.updateOffsets(_file);
     
-    fclose(file);
+    fclose(_file);
 }
 
 void GPBFile::saveText(const std::string& filepath)
 {
-    file = fopen(filepath.c_str(), "w");
+    _file = fopen(filepath.c_str(), "w");
 
-    fprintf(file, "<root>\n");
+    fprintf(_file, "<root>\n");
 
     // write refs
-    refTable.writeText(file);
+    _refTable.writeText(_file);
 
     // meshes
-    for (std::list<Mesh*>::const_iterator i = geometry.begin(); i != geometry.end(); i++)
+    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); i++)
     {
-        (*i)->writeText(file);
+        (*i)->writeText(_file);
     }
 
     // Objects
-    for (std::list<Object*>::const_iterator i = objects.begin(); i != objects.end(); i++)
+    for (std::list<Object*>::const_iterator i = _objects.begin(); i != _objects.end(); i++)
     {
-        (*i)->writeText(file);
+        (*i)->writeText(_file);
     }
 
-    fprintf(file, "</root>");
+    fprintf(_file, "</root>");
 
-    fclose(file);
+    fclose(_file);
 }
 
 void GPBFile::add(Object* obj)
 {
-    objects.push_back(obj);
+    _objects.push_back(obj);
 }
 
 void GPBFile::addScene(Scene* scene)
 {
     addToRefTable(scene);
-    objects.push_back(scene);
+    _objects.push_back(scene);
 }
 
 void GPBFile::addCamera(Camera* camera)
 {
     addToRefTable(camera);
-    cameras.push_back(camera);
+    _cameras.push_back(camera);
 }
 
 void GPBFile::addLight(Light* light)
 {
     addToRefTable(light);
-    lights.push_back(light);
+    _lights.push_back(light);
 }
 
 void GPBFile::addMesh(Mesh* mesh)
 {
     addToRefTable(mesh);
-    geometry.push_back(mesh);
+    _geometry.push_back(mesh);
 }
 
 void GPBFile::addNode(Node* node)
 {
     addToRefTable(node);
-    nodes.push_back(node);
+    _nodes.push_back(node);
 }
 
 void GPBFile::addAnimation(Animation* animation)
 {
-    if (!idExists(animation->getId()))
+    _animations.add(animation);
+
+    if (!_animationsAdded)
     {
-        addToRefTable(animation);
-        objects.push_back(animation);
+        // The animations container should only be added once and only if the file has at least one animation.
+        _animationsAdded = true;
+        addToRefTable(&_animations);
+        add(&_animations);
     }
 }
 
@@ -122,26 +126,28 @@ void GPBFile::addToRefTable(Object* obj)
         const std::string& id = obj->getId();
         if (id.length() > 0)
         {
-            if (refTable.get(id) == NULL)
-                refTable.add(id, obj);
+            if (_refTable.get(id) == NULL)
+            {
+                _refTable.add(id, obj);
+            }
         }
     }
 }
 
 Object* GPBFile::getFromRefTable(const std::string& id)
 {
-    return refTable.get(id);
+    return _refTable.get(id);
 }
 
 bool GPBFile::idExists(const std::string& id)
 {
-    return refTable.get(id) != NULL;
+    return _refTable.get(id) != NULL;
 }
 
 Camera* GPBFile::getCamera(const char* id)
 {
     // TODO: O(n) search is not ideal
-    for (std::list<Camera*>::const_iterator i = cameras.begin(); i != cameras.end(); i++)
+    for (std::list<Camera*>::const_iterator i = _cameras.begin(); i != _cameras.end(); i++)
     {
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -155,7 +161,7 @@ Camera* GPBFile::getCamera(const char* id)
 Light* GPBFile::getLight(const char* id)
 {
     // TODO: O(n) search is not ideal
-    for (std::list<Light*>::const_iterator i = lights.begin(); i != lights.end(); i++)
+    for (std::list<Light*>::const_iterator i = _lights.begin(); i != _lights.end(); i++)
     {
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -169,7 +175,7 @@ Light* GPBFile::getLight(const char* id)
 Mesh* GPBFile::getMesh(const char* id)
 {
     // TODO: O(n) search is not ideal
-    for (std::list<Mesh*>::const_iterator i = geometry.begin(); i != geometry.end(); i++)
+    for (std::list<Mesh*>::const_iterator i = _geometry.begin(); i != _geometry.end(); i++)
     {
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -183,7 +189,7 @@ Mesh* GPBFile::getMesh(const char* id)
 Node* GPBFile::getNode(const char* id)
 {
     // TODO: O(n) search is not ideal
-    for (std::list<Node*>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
     {
         const std::string& _id = (*i)->getId();
         if (_id.length() > 0 && strncmp(id, _id.c_str(), 255) == 0)
@@ -197,7 +203,7 @@ Node* GPBFile::getNode(const char* id)
 void GPBFile::adjust()
 {
     // calculate the ambient color for each scene
-    for (std::list<Object*>::iterator i = objects.begin(); i != objects.end(); i++)
+    for (std::list<Object*>::iterator i = _objects.begin(); i != _objects.end(); i++)
     {
         Object* obj = *i;
         if (obj->getTypeId() == Object::SCENE_ID)
@@ -208,43 +214,18 @@ void GPBFile::adjust()
     }
 
     // TODO:
-    // remove ambient lights
+    // remove ambient _lights
     // for each node
     //   if node has ambient light
     //     if node has no camera, mesh or children but 1 ambient light
     //       delete node and remove from ref table
     //     delete light and remove from ref table
-    // 
+    //
     // merge animations if possible
     //   Search for animations that have the same target and key times and see if they can be merged.
     //   Blender will output a simple translation animation to 3 separate animations with the same key times but targetting X, Y and Z.
     //   This can be merged into one animation. Same for scale animations.
 }
 
-Animation* GPBFile::findAnimationForJoint(const char* id)
-{
-    for (std::map<std::string, Reference>::iterator i = refTable.begin(); i != refTable.end(); i++)
-    {
-        Reference& ref = i->second;
-        Object* obj = ref.getObj();
-        if (obj->getTypeId() == Object::NODE_ID)
-        {
-            Node* node = (Node*)obj;
-            Model* model = node->getModel();
-            if (model)
-            {
-                MeshSkin* skin = model->getSkin();
-                if (skin)
-                {
-                    if (skin->hasJoint(id))
-                    {
-                        return skin->getAnimation();
-                    }
-                }
-            }
-        }
-    }
-    return NULL;
-}
 
 }

+ 17 - 16
gameplay-encoder/src/GPBFile.h

@@ -17,6 +17,7 @@
 #include "Mesh.h"
 #include "Reference.h"
 #include "ReferenceTable.h"
+#include "Animations.h"
 #include "Animation.h"
 #include "AnimationChannel.h"
 
@@ -28,6 +29,9 @@ namespace gameplay
      */
     const unsigned char VERSION[2] = {1, 0};
 
+/**
+ * The GamePlay Binary file class handles writing the GamePlay Binary file.
+ */
 class GPBFile
 {
 public:
@@ -48,8 +52,9 @@ public:
      * @param filepath The file name and path to save to.
      */
     void saveBinary(const std::string& filepath);
+
     /**
-     * Saves the GPBFile as a text file at filepath.
+     * Saves the GPBFile as a text file at filepath. Useful for debugging.
      *
      * @param filepath The file name and path to save to.
      */
@@ -67,6 +72,7 @@ public:
      * Adds the given object to the ref table.
      */
     void addToRefTable(Object* obj);
+
     /**
      * Returns the object with the given id. Returns NULL if not found.
      */
@@ -87,23 +93,18 @@ public:
      */
     void adjust();
 
-    /**
-     * Returns the animation that the given joint's animation channel's should be added to.
-     * 
-     * @param id The ID of the joint.
-     * @return The animation belonging to the skin that the joint is part of.
-     */
-    Animation* findAnimationForJoint(const char* id);
-
 private:
 
-    FILE* file;
-    std::list<Object*> objects;
-    std::list<Camera*> cameras;
-    std::list<Light*> lights;
-    std::list<Mesh*> geometry;
-    std::list<Node*> nodes; 
-    ReferenceTable refTable;
+    FILE* _file;
+    std::list<Object*> _objects;
+    std::list<Camera*> _cameras;
+    std::list<Light*> _lights;
+    std::list<Mesh*> _geometry;
+    std::list<Node*> _nodes;
+    Animations _animations;
+    bool _animationsAdded;
+
+    ReferenceTable _refTable;
 };
 
 }

+ 142 - 49
gameplay-encoder/src/Light.cpp

@@ -1,17 +1,21 @@
 #include "Light.h"
+#include "DAESceneEncoder.h"
 
 namespace gameplay
 {
 
 Light::Light(void) :
-    lightType(0),
-    constantAttenuation(0.0f),
-    linearAttenuation(0.0f),
-    quadraticAttenuation(0.0f),
-    falloffAngle(0.0f),
-    falloffExponent(0.0f)
-{
-    fillArray(color, 0.0f, COLOR_SIZE);
+    _lightType(0),
+    _constantAttenuation(0.0f),
+    _linearAttenuation(0.0f),
+    _quadraticAttenuation(0.0f),
+    _falloffAngle(0.0f),
+    _falloffExponent(0.0f),
+    _range(-1.0f),
+    _innerAngle(-1.0f),
+    _outerAngle(0.0f)
+{
+    fillArray(_color, 0.0f, COLOR_SIZE);
 }
 
 Light::~Light(void)
@@ -26,112 +30,201 @@ const char* Light::getElementName(void) const
 {
     return "Light";
 }
+
+float Light::computeRange(float constantAttenuation, float linearAttenuation, float quadraticAttenuation)
+{
+    if (constantAttenuation == 0.0f && linearAttenuation == 0.0f && quadraticAttenuation == 0.0f)
+    {
+        return 0.0f;
+    }
+
+    // Constant Attenuation is currently not supported.
+    if (constantAttenuation == 1.0f)
+    {
+        return 1.0f;
+    }
+
+    const float step = 0.01f;
+    float range = 0.01f;
+    float att = 1.0f;
+    while (att < 0.1f)
+    {
+        att = 1 / (constantAttenuation + (range * linearAttenuation) + (range * range * quadraticAttenuation));
+        range += step;
+    }
+    return range;
+}
+
+float lerpstep( float lower, float upper, float s)
+{
+    float lerpstep = ( s - lower ) / ( upper - lower );
+    
+    if (lerpstep < 0.0f)
+        lerpstep = 0.0f;
+    else if (lerpstep > 1.0f)
+        lerpstep = 1.0f;
+    
+    return lerpstep;
+}
+
+float Light::computeInnerAngle(float outerAngle)
+{
+    const float epsilon = 0.15f;
+
+    // Set inner angle to half of outer angle.
+    float innerAngle = outerAngle / 2.0f;
+
+    // Try to find the inner angle by sampling the attenuation with steps of angle.
+    for (float angle = 0.0; angle < outerAngle; angle += epsilon)
+    {
+        float outerCosAngle = cos(MATH_DEG_TO_RAD(outerAngle));
+        float innerCosAngle = cos(MATH_DEG_TO_RAD(innerAngle));
+            
+        float cosAngle = cos(MATH_DEG_TO_RAD(angle));
+        float att = lerpstep(outerCosAngle, innerCosAngle, cosAngle);
+        
+        if (att < 1.0f)
+        {
+            innerAngle = angle;
+            break;
+        }
+    }
+
+    return innerAngle;
+}
+
 void Light::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    write(lightType, file);
-    write(color, COLOR_SIZE, file);
+    write(_lightType, file);
+    write(_color, COLOR_SIZE, file);
 
-    if (lightType == SpotLight)
+    // Compute an approximate light range with Collada's attenuation parameters.
+    // This facilitates bringing in the light nodes directly from maya to gameplay.
+    if (_range == -1.0f)
     {
-        write(constantAttenuation, file);
-        write(linearAttenuation, file);
-        write(quadraticAttenuation, file);
-        write(falloffAngle, file);
-        write(falloffExponent, file);
+        _range = computeRange(_constantAttenuation, _linearAttenuation, _quadraticAttenuation);
     }
-    else if (lightType == PointLight)
+
+    if (_lightType == SpotLight)
     {
-        write(constantAttenuation, file);
-        write(linearAttenuation, file);
-        write(quadraticAttenuation, file);
-    }
+        // Compute an approximate inner angle of the spot light using Collada's outer angle.
+        _outerAngle = _falloffAngle / 2.0f;
+        
+        if (_range == -1.0f)
+        {
+            _innerAngle = computeInnerAngle(_outerAngle);
+        }
 
+        write(_range, file);
+        write(MATH_DEG_TO_RAD(_innerAngle), file);
+        write(MATH_DEG_TO_RAD(_outerAngle), file);
+    }
+    else if (_lightType == PointLight)
+    {
+        write(_range, file);
+    }
 }
+
 void Light::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "lightType", lightType);
-    fprintfElement(file, "color", color, COLOR_SIZE);
+    fprintfElement(file, "lightType", _lightType);
+    fprintfElement(file, "color", _color, COLOR_SIZE);
 
-    if (lightType == SpotLight)
+    // Compute an approximate light range with Collada's attenuation parameters.
+    // This facilitates bringing in the light nodes directly from maya to gameplay.
+    if (_range == -1.0f)
     {
-        fprintfElement(file, "constantAttenuation", constantAttenuation);
-        fprintfElement(file, "linearAttenuation", linearAttenuation);
-        fprintfElement(file, "quadraticAttenuation", quadraticAttenuation);
-        fprintfElement(file, "falloffAngle", falloffAngle);
-        fprintfElement(file, "falloffExponent", falloffExponent);
+        _range = computeRange(_constantAttenuation, _linearAttenuation, _quadraticAttenuation);
     }
-    else if (lightType == PointLight)
+
+    if (_lightType == SpotLight)
     {
-        fprintfElement(file, "constantAttenuation", constantAttenuation);
-        fprintfElement(file, "linearAttenuation", linearAttenuation);
-        fprintfElement(file, "quadraticAttenuation", quadraticAttenuation);
+        // Compute an approximate inner angle of the spot light using Collada's outer angle.
+        _outerAngle = _falloffAngle / 2.0f;
+        if (_innerAngle == -1.0f)
+        {
+            _innerAngle = computeInnerAngle(_outerAngle);
+        }
+
+        fprintfElement(file, "range", _range);
+        fprintfElement(file, "innerAngle", MATH_DEG_TO_RAD(_innerAngle));
+        fprintfElement(file, "outerAngle", MATH_DEG_TO_RAD(_outerAngle));
     }
+    else if (_lightType == PointLight)
+    {
+        fprintfElement(file, "range", _range);
+    }
+
     fprintElementEnd(file);
 }
 
 float Light::getRed() const
 {
-    return color[0];
+    return _color[0];
 }
 float Light::getGreen() const
 {
-    return color[1];
+    return _color[1];
 }
 float Light::getBlue() const
 {
-    return color[2];
+    return _color[2];
 }
 
 bool Light::isAmbient() const
 {
-    return lightType == AmbientLight;
+    return _lightType == AmbientLight;
 }
 
 void Light::setAmbientLight()
 {
-    lightType = AmbientLight;
+    _lightType = AmbientLight;
 }
 void Light::setDirectionalLight()
 {
-    lightType = DirectionalLight;
+    _lightType = DirectionalLight;
 }
 void Light::setPointLight()
 {
-    lightType = PointLight;
+    _lightType = PointLight;
 }
 void Light::setSpotLight()
 {
-    lightType = SpotLight;
+    _lightType = SpotLight;
 }
 
 void Light::setColor(float r, float g, float b)
 {
-    color[0] = r;
-    color[1] = g;
-    color[2] = b;
+    _color[0] = r;
+    _color[1] = g;
+    _color[2] = b;
 }
 
 void Light::setConstantAttenuation(float value)
 {
-    constantAttenuation = value;
+    _constantAttenuation = value;
 }
 void Light::setLinearAttenuation(float value)
 {
-    linearAttenuation = value;
+    _linearAttenuation = value;
 }
 void Light::setQuadraticAttenuation(float value)
 {
-    quadraticAttenuation = value;
+    _quadraticAttenuation = value;
 }
 void Light::setFalloffAngle(float value)
 {
-    falloffAngle = value;
+    _falloffAngle = value;
 }
 void Light::setFalloffExponent(float value)
 {
-    falloffExponent = value;
+    _falloffExponent = value;
+    if ( value != 1.0)
+    {
+        printf("Warning: spot light falloff_exponent must be 1.0. \n");
+    }
 }
 
 }

+ 16 - 9
gameplay-encoder/src/Light.h

@@ -51,7 +51,7 @@ public:
     void setFalloffExponent(float value);
 
     enum LightType
-    {   
+    {
         DirectionalLight = 1,
         PointLight = 2,
         SpotLight = 3,
@@ -60,14 +60,21 @@ public:
 
 private:
 
-    unsigned char lightType;
-    float color[COLOR_SIZE];
-
-    float constantAttenuation;
-    float linearAttenuation;
-    float quadraticAttenuation;
-    float falloffAngle;
-    float falloffExponent;
+    static float computeRange(float constantAttenuation, float linearAttenuation, float quadraticAttenuation);
+    static float computeInnerAngle(float outerAngle);
+    
+    unsigned char _lightType;
+    float _color[COLOR_SIZE];
+
+    float _constantAttenuation;
+    float _linearAttenuation;
+    float _quadraticAttenuation;
+    float _falloffAngle;
+    float _falloffExponent;
+
+    float _range;
+    float _innerAngle;
+    float _outerAngle;
 };
 
 

+ 12 - 9
gameplay-encoder/src/LightInstance.cpp

@@ -4,7 +4,7 @@
 namespace gameplay
 {
 
-LightInstance::LightInstance(void) : ref(NULL)
+LightInstance::LightInstance(void) : _ref(NULL)
 {
 
 }
@@ -24,29 +24,32 @@ const char* LightInstance::getElementName(void) const
 
 void LightInstance::writeBinary(FILE* file)
 {
-    //assert(ref != NULL);
-    if (ref != NULL)
-        ref->writeBinary(file);
+    if (_ref != NULL)
+    {
+        _ref->writeBinary(file);
+    }
 }
 void LightInstance::writeText(FILE* file)
 {
-    if (ref != NULL)
-        ref->writeText(file);
+    if (_ref != NULL)
+    {
+        _ref->writeText(file);
+    }
 }
 
 Light* LightInstance::getLight() const
 {
-    return ref;
+    return _ref;
 }
 
 void LightInstance::setLight(Light* light)
 {
-    ref = light;
+    _ref = light;
 }
 
 bool LightInstance::isAmbient() const
 {
-    return ref != NULL && ref->isAmbient();
+    return _ref != NULL && _ref->isAmbient();
 }
 
 }

+ 1 - 1
gameplay-encoder/src/LightInstance.h

@@ -32,7 +32,7 @@ public:
     bool isAmbient() const;
 
 private:
-    Light* ref;
+    Light* _ref;
 };
 
 }

+ 5 - 5
gameplay-encoder/src/Material.cpp

@@ -4,7 +4,7 @@ namespace gameplay
 {
 
 Material::Material(void) :
-    effect(NULL)
+    _effect(NULL)
 {
 }
 
@@ -24,14 +24,14 @@ const char* Material::getElementName(void) const
 void Material::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    //write(parameters, file);
-    //write(effect, file);
+    //write(_parameters, file);
+    //write(_effect, file);
 }
 void Material::writeText(FILE* file)
 {
     fprintElementStart(file);
-    //fprintfElement(file, "parameters", parameters);
-    //fprintfElement(file, "effect", effect);
+    //fprintfElement(file, "parameters", _parameters);
+    //fprintfElement(file, "effect", _effect);
     fprintElementEnd(file);
 }
 

+ 3 - 2
gameplay-encoder/src/Material.h

@@ -27,8 +27,9 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
 
-    std::list<MaterialParameter> parameters;
-    Effect* effect;
+private:
+    std::list<MaterialParameter> _parameters;
+    Effect* _effect;
 };
 
 

+ 5 - 5
gameplay-encoder/src/MaterialParameter.cpp

@@ -4,7 +4,7 @@ namespace gameplay
 {
 
 MaterialParameter::MaterialParameter(void) :
-    type(0)
+    _type(0)
 {
 }
 
@@ -24,14 +24,14 @@ const char* MaterialParameter::getElementName(void) const
 void MaterialParameter::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    write(value, file);
-    write(type, file);
+    write(_value, file);
+    write(_type, file);
 }
 void MaterialParameter::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "%f ", "value", value);
-    fprintfElement(file, "type", type);
+    fprintfElement(file, "%f ", "value", _value);
+    fprintfElement(file, "type", _type);
     fprintElementEnd(file);
 }
 

+ 3 - 2
gameplay-encoder/src/MaterialParameter.h

@@ -25,8 +25,9 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
 
-    std::vector<float> value;
-    unsigned int type;
+private:
+    std::vector<float> _value;
+    unsigned int _type;
 };
 
 

+ 7 - 3
gameplay-encoder/src/Matrix.cpp

@@ -9,9 +9,9 @@ Matrix::Matrix(void)
     setIdentity(m);
 }
 
-Matrix::Matrix(float m0, float m1, float m2, float m3, 
-               float m4, float m5, float m6, float m7, 
-               float m8, float m9, float m10, float m11, 
+Matrix::Matrix(float m0, float m1, float m2, float m3,
+               float m4, float m5, float m6, float m7,
+               float m8, float m9, float m10, float m11,
                float m12, float m13, float m14, float m15)
 {
     m[0] = m0;
@@ -233,7 +233,9 @@ bool Matrix::decompose(Vector3* scale, Quaternion* rotation, Vector3* translatio
 
     // nothing left to do
     if (scale == NULL && rotation == NULL)
+    {
         return true;
+    }
 
     // Extract the scale.
     // This is simply the length of each axis (row/column) in the matrix.
@@ -250,7 +252,9 @@ bool Matrix::decompose(Vector3* scale, Quaternion* rotation, Vector3* translatio
     // In this case, we simply negate a single axis of the scale.
     float det = determinant();
     if (det < 0)
+    {
         scaleZ = -scaleZ;
+    }
 
     if (scale)
     {

+ 5 - 5
gameplay-encoder/src/Matrix.h

@@ -19,7 +19,7 @@ namespace gameplay
 /**
  * The identify matrix.
  */
-static const float MATRIX4F_IDENTITY[16] = 
+static const float MATRIX4F_IDENTITY[16] =
 {
     1.0f, 0.0f, 0.0f, 0.0f,
     0.0f, 1.0f, 0.0f, 0.0f,
@@ -39,9 +39,9 @@ public:
     /**
      * Constructor.
      */
-    Matrix(float m0, float m1, float m2, float m3, 
-           float m4, float m5, float m6, float m7, 
-           float m8, float m9, float m10, float m11, 
+    Matrix(float m0, float m1, float m2, float m3,
+           float m4, float m5, float m6, float m7,
+           float m8, float m9, float m10, float m11,
            float m12, float m13, float m14, float m15);
 
     /**
@@ -71,7 +71,7 @@ public:
     static void setIdentity(float* matrix);
 
     /**
-     * Multiplies two matrices and stores the results in dst. 
+     * Multiplies two matrices and stores the results in dst.
      * m1 and m2 may be the same as dst.
      */
     static void multiply(const float* m1, const float* m2, float* dst);

+ 6 - 4
gameplay-encoder/src/Mesh.cpp

@@ -26,8 +26,8 @@ void Mesh::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
     // vertex formats
-    write(vertexFormats.size(), file);
-    for (std::vector<VertexElement>::iterator i = vertexFormats.begin(); i != vertexFormats.end(); i++)
+    write(_vertexFormats.size(), file);
+    for (std::vector<VertexElement>::iterator i = _vertexFormats.begin(); i != _vertexFormats.end(); i++)
     {
         i->writeBinary(file);
     }
@@ -74,7 +74,7 @@ void Mesh::writeText(FILE* file)
     // for each VertexFormat
     if (vertices.size() > 0 )
     {
-        for (std::vector<VertexElement>::iterator i = vertexFormats.begin(); i != vertexFormats.end(); i++)
+        for (std::vector<VertexElement>::iterator i = _vertexFormats.begin(); i != _vertexFormats.end(); i++)
         {
             i->writeText(file);
         }
@@ -124,7 +124,7 @@ void Mesh::addMeshPart(Vertex* vertex)
 
 void Mesh::addVetexAttribute(unsigned int usage, unsigned int count)
 {
-    vertexFormats.push_back(VertexElement(usage, count));
+    _vertexFormats.push_back(VertexElement(usage, count));
 }
 
 size_t Mesh::getVertexCount() const
@@ -194,7 +194,9 @@ void Mesh::computeBounds()
     {
         float d = Vector3::distanceSquared(bounds.center, i->position);
         if (d > bounds.radius)
+        {
             bounds.radius = d;
+        }
     }
 
     // Convert squared distance to distance for radius

+ 2 - 1
gameplay-encoder/src/Mesh.h

@@ -65,7 +65,8 @@ private:
 
     void computeBounds();
 
-    std::vector<VertexElement> vertexFormats;
+private:
+    std::vector<VertexElement> _vertexFormats;
 
 };
 

+ 20 - 16
gameplay-encoder/src/MeshPart.cpp

@@ -4,8 +4,8 @@ namespace gameplay
 {
 
 MeshPart::MeshPart(void) :
-    primitiveType(TRIANGLES),
-    indexFormat(INDEX8)
+    _primitiveType(TRIANGLES),
+    _indexFormat(INDEX8)
 {
 }
 
@@ -25,13 +25,13 @@ void MeshPart::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
 
-    write(primitiveType, file);
-    write(indexFormat, file);
+    write(_primitiveType, file);
+    write(_indexFormat, file);
 
     // write the number of bytes
     write(indicesByteSize(), file);
     // for each index
-    for (std::vector<unsigned int>::const_iterator i = indices.begin(); i != indices.end(); i++)
+    for (std::vector<unsigned int>::const_iterator i = _indices.begin(); i != _indices.end(); i++)
     {
         writeBinaryIndex(*i, file);
     }
@@ -39,31 +39,31 @@ void MeshPart::writeBinary(FILE* file)
 void MeshPart::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "primitiveType", primitiveType);
-    fprintfElement(file, "indexFormat", indexFormat);
-    fprintfElement(file, "%d ", "indices", indices);
+    fprintfElement(file, "primitiveType", _primitiveType);
+    fprintfElement(file, "indexFormat", _indexFormat);
+    fprintfElement(file, "%d ", "indices", _indices);
     fprintElementEnd(file);
 }
 
 void MeshPart::addIndex(unsigned int index)
 {
     updateIndexFormat(index);
-    indices.push_back(index);
+    _indices.push_back(index);
 }
 
 size_t MeshPart::getIndicesCount() const
 {
-    return indices.size();
+    return _indices.size();
 }
 
 unsigned int MeshPart::indicesByteSize() const
 {
-    return indices.size() * indexFormatSize();
+    return _indices.size() * indexFormatSize();
 }
 
 unsigned int MeshPart::indexFormatSize() const
 {
-    switch (indexFormat)
+    switch (_indexFormat)
     {
     case INDEX32:
         return 4;
@@ -77,7 +77,7 @@ unsigned int MeshPart::indexFormatSize() const
 
 void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
 {
-    switch (indexFormat)
+    switch (_indexFormat)
     {
     case INDEX32:
         write(index, file);
@@ -95,9 +95,13 @@ void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
 void MeshPart::updateIndexFormat(unsigned int newIndex)
 {
     if (newIndex >= 65536)
-        indexFormat = INDEX32;
-    else if (newIndex >= 256 && indexFormat != INDEX32)
-        indexFormat = INDEX16;
+    {
+        _indexFormat = INDEX32;
+    }
+    else if (newIndex >= 256 && _indexFormat != INDEX32)
+    {
+        _indexFormat = INDEX16;
+    }
 }
 
 }

+ 3 - 3
gameplay-encoder/src/MeshPart.h

@@ -80,9 +80,9 @@ private:
     void writeBinaryIndex(unsigned int index, FILE* file);
 
 private:
-    unsigned int primitiveType;
-    unsigned int indexFormat;
-    std::vector<unsigned int> indices;
+    unsigned int _primitiveType;
+    unsigned int _indexFormat;
+    std::vector<unsigned int> _indices;
 };
 
 

+ 18 - 58
gameplay-encoder/src/MeshSkin.cpp

@@ -6,11 +6,9 @@ namespace gameplay
 {
 
 MeshSkin::MeshSkin(void) :
-    influences(NULL),
-    vertexInfluenceCount(0),
-    animation(NULL)
+    _vertexInfluenceCount(0)
 {
-    setIdentityMatrix(bindShape);
+    setIdentityMatrix(_bindShape);
 }
 
 MeshSkin::~MeshSkin(void)
@@ -30,48 +28,29 @@ const char* MeshSkin::getElementName(void) const
 void MeshSkin::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    // bindShape
-    write(bindShape, 16, file);
-    // root joint
-    write(influences->getId(), file);
-    /*
-    if (influences != NULL)
-    {
-        influences->writeBinaryXref(file);
-    }
-    else
-    {
-        write((unsigned int)0, file);
-    }
-    */
-    // joints
-    write(joints.size(), file);
-    for (std::list<Node*>::const_iterator i = joints.begin(); i != joints.end(); i++)
+    write(_bindShape, 16, file);
+    write(_joints.size(), file);
+    for (std::list<Node*>::const_iterator i = _joints.begin(); i != _joints.end(); i++)
     {
         (*i)->writeBinaryXref(file);
     }
-    // bindPoses
-    write(bindPoses, file);
+    write(_bindPoses, file);
 }
 
 void MeshSkin::writeText(FILE* file)
 {
     fprintElementStart(file);
     fprintf(file, "<bindShape>");
-    fprintfMatrix4f(file, bindShape);
+    fprintfMatrix4f(file, _bindShape);
     fprintf(file, "</bindShape>");
-    if (influences != NULL)
-    {
-        fprintf(file, "<ref xref=\"#%s\"/>", influences->getId().c_str());
-    }
     fprintf(file, "<joints>");
-    for (std::list<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
+    for (std::list<std::string>::const_iterator i = _jointNames.begin(); i != _jointNames.end(); i++)
     {
         fprintf(file, "%s ", i->c_str());
     }
     fprintf(file, "</joints>\n");
-    fprintf(file, "<bindPoses count=\"%u\">", bindPoses.size());
-    for (std::list<float>::const_iterator i = bindPoses.begin(); i != bindPoses.end(); i++)
+    fprintf(file, "<bindPoses count=\"%u\">", _bindPoses.size());
+    for (std::list<float>::const_iterator i = _bindPoses.begin(); i != _bindPoses.end(); i++)
     {
         fprintf(file, "%f ", *i);
     }
@@ -83,50 +62,45 @@ void MeshSkin::setBindShape(const float data[])
 {
     for (int i = 0; i < 16; i++)
     {
-        bindShape[i] = data[i];
+        _bindShape[i] = data[i];
     }
 }
 
 void MeshSkin::setVertexInfluenceCount(unsigned int count)
 {
-    vertexInfluenceCount = count;
-}
-
-void MeshSkin::setNode(Node* node)
-{
-    influences = node;
+    _vertexInfluenceCount = count;
 }
 
 void MeshSkin::setJointNames(const std::list<std::string>& list)
 {
-    jointNames = list;
+    _jointNames = list;
 }
 
 const std::list<std::string>& MeshSkin::getJointNames()
 {
-    return jointNames;
+    return _jointNames;
 }
 
 void MeshSkin::setJoints(const std::list<Node*>& list)
 {
-    joints = list;
+    _joints = list;
 }
 
 void MeshSkin::setBindPoses(std::vector<Matrix>& list)
 {
     for (std::vector<Matrix>::iterator i = list.begin(); i != list.end(); i++)
-    {   
+    {
         float* a = i->m;
         for (int j = 0; j < 16; j++)
         {
-            bindPoses.push_back(a[j]);
+            _bindPoses.push_back(a[j]);
         }
     }
 }
 
 bool MeshSkin::hasJoint(const char* id)
 {
-    for (std::list<std::string>::iterator i = jointNames.begin(); i != jointNames.end(); i++)
+    for (std::list<std::string>::iterator i = _jointNames.begin(); i != _jointNames.end(); i++)
     {
         if (equals(*i, id))
         {
@@ -136,18 +110,4 @@ bool MeshSkin::hasJoint(const char* id)
     return false;
 }
 
-Animation* MeshSkin::getAnimation()
-{
-    if (!animation)
-    {
-        animation = new Animation();
-    }
-    return animation;
-}
-
-void MeshSkin::setAnimationId(const char* id)
-{
-    getAnimation()->setId(id);
-}
-
 }

+ 6 - 24
gameplay-encoder/src/MeshSkin.h

@@ -36,8 +36,6 @@ public:
 
     void setVertexInfluenceCount(unsigned int count);
 
-    void setNode(Node* node);
-
     void setJointNames(const std::list<std::string>& list);
 
     const std::list<std::string>& getJointNames();
@@ -50,36 +48,20 @@ public:
      * Returns true if the MeshSkin contains a joint with the given ID.
      * 
      * @param id The ID of the joint to search for.
+     * 
      * @return True if the joint belongs to this skin, false otherwise.
      */
     bool hasJoint(const char* id);
 
-    /**
-     * Returns the animation that contains the animation channels that target this skin's joints.
-     * 
-     * @return The animation for this skin.
-     */
-    Animation* getAnimation();
-
-    /**
-     * Sets the id of the skin's animation.
-     * 
-     * @param id The new ID.
-     */
-    void setAnimationId(const char* id);
-
 private:
 
-    Node* influences;
-    float bindShape[16];
-    std::list<Node*> joints;
-    std::list<float> bindPoses;
-
-    std::list<std::string> jointNames;
+    float _bindShape[16];
+    std::list<Node*> _joints;
+    std::list<float> _bindPoses;
 
-    unsigned int vertexInfluenceCount;
+    std::list<std::string> _jointNames;
 
-    Animation* animation;
+    unsigned int _vertexInfluenceCount;
 };
 
 }

+ 19 - 15
gameplay-encoder/src/Model.cpp

@@ -4,8 +4,8 @@ namespace gameplay
 {
 
 Model::Model(void) :
-    ref(NULL),
-    meshSkin(NULL)
+    _ref(NULL),
+    _meshSkin(NULL)
 {
 }
 
@@ -26,52 +26,56 @@ void Model::writeBinary(FILE* file)
     Object::writeBinary(file);
 
     // xref:Mesh
-    if (ref != NULL)
-        ref->writeBinaryXref(file);
+    if (_ref != NULL)
+    {
+        _ref->writeBinaryXref(file);
+    }
     else
+    {
         write((unsigned int)0, file);
-    // meshSkin
+    }
+    // _meshSkin
     // Write one unsigned char to indicate if this model has a skin
-    if (meshSkin != NULL)
+    if (_meshSkin != NULL)
     {
         write((bool)true, file); // has a skin
-        meshSkin->writeBinary(file);
+        _meshSkin->writeBinary(file);
     }
     else
     {
         write((bool)false, file); // doesn't have a skin
     }
     // materials[]
-    writeBinaryObjects(materials, file);
+    writeBinaryObjects(_materials, file);
 
 }
 void Model::writeText(FILE* file)
 {
     fprintElementStart(file);
-    if (ref != NULL)
+    if (_ref != NULL)
     {
-        fprintfElement(file, "ref", ref->getId());
+        fprintfElement(file, "ref", _ref->getId());
     }
-    if (meshSkin != NULL)
+    if (_meshSkin != NULL)
     {
-        meshSkin->writeText(file);
+        _meshSkin->writeText(file);
     }
     fprintElementEnd(file);
 }
 
 MeshSkin* Model::getSkin()
 {
-    return meshSkin;
+    return _meshSkin;
 }
 
 void Model::setMesh(Mesh* mesh)
 {
-    ref = mesh;
+    _ref = mesh;
 }
 
 void Model::setSkin(MeshSkin* skin)
 {
-    meshSkin = skin;
+    _meshSkin = skin;
 }
 
 }

+ 4 - 3
gameplay-encoder/src/Model.h

@@ -33,10 +33,11 @@ public:
     void setMesh(Mesh* mesh);
     MeshSkin* getSkin();
     void setSkin(MeshSkin* skin);
+
 private:
-    Mesh* ref;
-    MeshSkin* meshSkin;
-    std::list<Material*> materials;
+    Mesh* _ref;
+    MeshSkin* _meshSkin;
+    std::list<Material*> _materials;
 };
 
 }

+ 38 - 34
gameplay-encoder/src/Node.cpp

@@ -8,11 +8,11 @@ namespace gameplay
 
 Node::Node(void) :
     _childCount(0),
-    _nextSibling(NULL), _previousSibling(NULL), 
+    _nextSibling(NULL), _previousSibling(NULL),
     _firstChild(NULL), _lastChild(NULL), _parent(NULL),
-    camera(NULL), light(NULL), model(NULL), joint(false)
+    _camera(NULL), _light(NULL), _model(NULL), _joint(false)
 {
-    setIdentityMatrix(transform);
+    setIdentityMatrix(_transform);
 }
 
 Node::~Node(void)
@@ -34,10 +34,10 @@ void Node::writeBinary(FILE* file)
     Object::writeBinary(file);
 
     // node type
-    unsigned int type = joint ? JOINT : NODE;
+    unsigned int type = _joint ? JOINT : NODE;
     write(type, file);
 
-    write(transform, 16, file);
+    write(_transform, 16, file);
     // children
     write(getChildCount(), file); // write number of children
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
@@ -46,27 +46,27 @@ void Node::writeBinary(FILE* file)
     }
 
     // camera
-    if (camera != NULL)
+    if (_camera != NULL)
     {
-        camera->writeBinary(file);
+        _camera->writeBinary(file);
     }
     else
     {
         write((unsigned char)0, file);
     }
     // light
-    if (light != NULL && !light->isAmbient())
+    if (_light != NULL && !_light->isAmbient())
     {
-        light->writeBinary(file);
+        _light->writeBinary(file);
     }
     else
     {
         write((unsigned char)0, file);
     }
     // mesh
-    if (model != NULL)
+    if (_model != NULL)
     {
-        model->writeBinary(file);
+        _model->writeBinary(file);
     }
     else
     {
@@ -77,14 +77,14 @@ void Node::writeText(FILE* file)
 {
     if (isJoint())
     {
-        fprintf(file, "<%s id=\"%s\" type=\"%s\">\n", getElementName(), id.c_str(), "JOINT");
+        fprintf(file, "<%s id=\"%s\" type=\"%s\">\n", getElementName(), getId().c_str(), "JOINT");
     }
     else
     {
         fprintElementStart(file);
     }
     fprintf(file, "<transform>");
-    fprintfMatrix4f(file, transform);
+    fprintfMatrix4f(file, _transform);
     fprintf(file, "</transform>\n");
 
     // children
@@ -93,19 +93,19 @@ void Node::writeText(FILE* file)
         node->writeText(file);
     }
     // camera
-    if (camera != NULL)
+    if (_camera != NULL)
     {
-        camera->writeText(file);
+        _camera->writeText(file);
     }
     // light
-    if (light != NULL && !light->isAmbient())
+    if (_light != NULL && !_light->isAmbient())
     {
-        light->writeText(file);
+        _light->writeText(file);
     }
     // mesh
-    if (model != NULL)
+    if (_model != NULL)
     {
-        model->writeText(file);
+        _model->writeText(file);
     }
     fprintElementEnd(file);
 }
@@ -159,9 +159,13 @@ void Node::removeChild(Node* child)
 
     // Was this child our first or last child?
     if (child == _firstChild)
+    {
         _firstChild = child->_nextSibling;
+    }
     if (child == _lastChild)
+    {
         _lastChild = child->_previousSibling;
+    }
 
     // Remove parent and sibling info from the child, now that it is no longer parented
     child->_parent = NULL;
@@ -217,58 +221,58 @@ Node* Node::getParent() const
 
 void Node::setCameraInstance(CameraInstance* cameraInstance)
 {
-    camera = cameraInstance;
+    _camera = cameraInstance;
 }
 void Node::setLightInstance(LightInstance* lightInstance)
 {
-    light = lightInstance;
+    _light = lightInstance;
 }
 void Node::setModel(Model* model)
 {
-    this->model = model;
+    _model = model;
 }
 
 void Node::setTransformMatrix(float matrix[])
 {
     for (int i = 0; i < 16; i++)
     {
-        transform[i] = matrix[i];
+        _transform[i] = matrix[i];
     }
 }
 
 void Node::setIsJoint(bool value)
 {
-    joint = value;
+    _joint = value;
 }
 
 bool Node::isJoint()
 {
-    return joint;
+    return _joint;
 }
 
 Camera* Node::getCamera() const
 {
-    if (camera)
+    if (_camera)
     {
-        return camera->getCamera();
+        return _camera->getCamera();
     }
     return NULL;
 }
 
 Light* Node::getLight() const
 {
-    if (light)
+    if (_light)
     {
-        return light->getLight();
+        return _light->getLight();
     }
     return NULL;
 }
 
 Model* Node::getModel() const
 {
-    if (model)
+    if (_model)
     {
-        return model;
+        return _model;
     }
     return NULL;
 }
@@ -292,12 +296,12 @@ Node* Node::getFirstCameraNode() const
 
 bool Node::hasCamera() const
 {
-    return camera != NULL;
+    return _camera != NULL;
 }
 
 bool Node::hasLight() const
 {
-    return light != NULL;
+    return _light != NULL;
 }
 
-} 
+}

+ 6 - 5
gameplay-encoder/src/Node.h

@@ -138,6 +138,7 @@ public:
      * Sets if this node is a joint node.
      */
     void setIsJoint(bool value);
+
     /**
      * Returns true if this is a joint node.
      */
@@ -156,7 +157,7 @@ public:
     bool hasLight() const;
     
 private:
-    float transform[16];
+    float _transform[16];
 
     int _childCount;
     Node* _nextSibling;
@@ -165,11 +166,11 @@ private:
     Node* _lastChild;
     Node* _parent;
 
-    CameraInstance* camera;
-    LightInstance* light;
-    Model* model;
+    CameraInstance* _camera;
+    LightInstance* _light;
+    Model* _model;
 
-    bool joint;
+    bool _joint;
 };
 
 

+ 0 - 49
gameplay-encoder/src/NodeInstance.cpp

@@ -1,49 +0,0 @@
-#include "NodeInstance.h"
-#include "Node.h"
-
-namespace gameplay
-{
-
-NodeInstance::NodeInstance(void) : ref(NULL)
-{
-}
-
-NodeInstance::~NodeInstance(void)
-{
-}
-
-unsigned int NodeInstance::getTypeId(void) const
-{
-    return NODEINSTANCE_ID;
-}
-
-const char* NodeInstance::getElementName(void) const
-{
-    return "NodeInstance";
-}
-
-void NodeInstance::writeBinary(FILE* file)
-{
-    Object::writeBinary(file);
-    if (ref != NULL)
-        ref->writeBinaryXref(file);
-    else
-        write((unsigned int)0, file);
-}
-
-void NodeInstance::writeText(FILE* file)
-{
-    fprintElementStart(file);
-    if (ref != NULL)
-    {
-        fprintfElement(file, "ref", ref->getId());
-    }
-    fprintElementEnd(file);
-}
-
-void NodeInstance::setNode(Node* node)
-{
-    ref = node;
-}
-
-}

+ 0 - 28
gameplay-encoder/src/NodeInstance.h

@@ -1,28 +0,0 @@
-#ifndef NODEINSTANCE_H_
-#define NODEINSTANCE_H_
-
-#include "Object.h"
-
-namespace gameplay
-{
-
-class Node;
-
-class NodeInstance : public Object
-{
-public:
-    NodeInstance(void);
-    virtual ~NodeInstance(void);
-
-    virtual unsigned int getTypeId(void) const;
-    virtual const char* getElementName(void) const;
-    virtual void writeBinary(FILE* file);
-    virtual void writeText(FILE* file);
-
-    void setNode(Node* node);
-private:
-    Node* ref;
-};
-
-}
-#endif

+ 16 - 8
gameplay-encoder/src/Object.cpp

@@ -3,7 +3,7 @@
 namespace gameplay
 {
 
-Object::Object(void) : fposition(0)
+Object::Object(void) : _fposition(0)
 {
 }
 
@@ -23,27 +23,35 @@ void Object::writeBinary(FILE* file)
 
 const std::string& Object::getId() const
 {
-    return id;
+    return _id;
 }
 
 void Object::setId(const char* idStr)
 {
     if (idStr)
-        id = idStr;
+    {
+        _id = idStr;
+    }
 }
 
 void Object::setId(const std::string& newId)
 {
     if (newId.length() > 0)
-        id = newId;
+    {
+        _id = newId;
+    }
 }
 
 void Object::fprintElementStart(FILE* file)
 {
-    if (id.length() > 0)
-        fprintf(file, "<%s id=\"%s\">\n", getElementName(), id.c_str());
+    if (_id.length() > 0)
+    {
+        fprintf(file, "<%s id=\"%s\">\n", getElementName(), _id.c_str());
+    }
     else
+    {
         fprintf(file, "<%s>\n", getElementName());
+    }
 }
 
 void Object::fprintElementEnd(FILE* file)
@@ -53,12 +61,12 @@ void Object::fprintElementEnd(FILE* file)
 
 unsigned int Object::getFilePosition()
 {
-    return (unsigned int)fposition;
+    return (unsigned int)_fposition;
 }
 
 void Object::saveFilePosition(FILE* file)
 {
-    fposition = ftell(file);
+    _fposition = ftell(file);
 }
 
 void Object::writeBinaryXref(FILE* file)

+ 17 - 8
gameplay-encoder/src/Object.h

@@ -11,7 +11,9 @@
 
 namespace gameplay
 {
-
+/**
+ * Object is the abstract base class of all the objects that can be written in the GamePlay Binary file.
+ */
 class Object
 {
 public:
@@ -21,8 +23,9 @@ public:
     {
         SCENE_ID = 1,
         NODE_ID = 2,
-        ANIMATION_ID = 3,
-        ANIMATIONCHANNEL_ID = 4,
+        ANIMATIONS_ID = 3,
+        ANIMATION_ID = 4,
+        ANIMATIONCHANNEL_ID = 5,
         NODEINSTANCE_ID = 8,
         CAMERAINSTANCE_ID = 9,
         LIGHTINSTANCE_ID = 10,
@@ -47,19 +50,23 @@ public:
      * Destructor.
      */
     virtual ~Object(void);
+
     /**
      * Returns the Object TypeID.
      */
     virtual unsigned int getTypeId(void) const;
+
     /**
      * Returns the string element name of the object.
      * Used for printing the gameplayfile as text.
      */
     virtual const char* getElementName(void) const = 0;
+
     /**
      * Writes this object to the file stream as binary.
      */
     virtual void writeBinary(FILE* file);
+
     /**
      * Writes this object to the file stream as text.
      */
@@ -69,23 +76,28 @@ public:
      * Returns this objects id string.
      */
     const std::string& getId() const;
+
     /**
      * Sets this object's id string.
      */
     void setId(const char* id);
+
     /**
      * Sets this object's id string.
      */
     void setId(const std::string& id);
+
     /**
      * Prints an XML start element with the name of this object to the text file stream.
      * Also prints the id as an attribute if the id length is greater than zero.
      */
     void fprintElementStart(FILE* file);
+
     /**
      * Prints an XML end element with the name of this object to the text file stream.
      */
     void fprintElementEnd(FILE* file);
+
     /**
      * Writes the xref of this object to the binary file stream.
      */
@@ -135,12 +147,9 @@ private:
      */
     void saveFilePosition(FILE* file);
 
-protected:
-
-    std::string id;
-
 private:
-    long fposition;
+    std::string _id;
+    long _fposition;
 };
 
 }

+ 2 - 0
gameplay-encoder/src/Quaternion.h

@@ -173,6 +173,7 @@ public:
      * quaternion is already unit-length.
      *
      * @param dst A quaternion to store the inverse in.
+     * 
      * @return true if the inverse can be computed, false otherwise.
      */
     bool inverse(Quaternion* dst) const;
@@ -245,6 +246,7 @@ public:
      * Converts this Quaternion4f to axis-angle notation. The axis is normalized.
      *
      * @param e The Vector3f which stores the axis.
+     * 
      * @return The angle (in radians).
      */
     float toAxisAngle(Vector3* e) const;

+ 17 - 17
gameplay-encoder/src/Reference.cpp

@@ -4,17 +4,17 @@ namespace gameplay
 {
 
 Reference::Reference(void) :
-    type(0),
-    offset(0),
-    ref(NULL)
+    _type(0),
+    _offset(0),
+    _ref(NULL)
 {
 }
 
 Reference::Reference(std::string _xref, Object* _ref) :
-    xref(_xref),
-    type(_ref->getTypeId()),
-    offset(0),
-    ref(_ref)
+    _xref(_xref),
+    _type(_ref->getTypeId()),
+    _offset(0),
+    _ref(_ref)
 {
 }
 
@@ -30,22 +30,22 @@ const char* Reference::getElementName(void) const
 void Reference::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    write(xref, file);
-    write(type, file);
-    write(offset, file);
+    write(_xref, file);
+    write(_type, file);
+    write(_offset, file);
 }
 void Reference::writeText(FILE* file)
 {
     fprintElementStart(file);
-    fprintfElement(file, "xref", xref);
-    fprintfElement(file, "type", type);
-    fprintfElement(file, "offset", offset);
+    fprintfElement(file, "xref", _xref);
+    fprintfElement(file, "type", _type);
+    fprintfElement(file, "offset", _offset);
     fprintElementEnd(file);
 }
 
 bool Reference::updateOffset(FILE* file)
 {
-    long newOffset = ref->getFilePosition();
+    long newOffset = _ref->getFilePosition();
     return updateOffset(file, newOffset);
 }
 
@@ -57,7 +57,7 @@ bool Reference::updateOffset(FILE* file, long newOffset)
         long savedOffset = ftell(file);
 
         // update the offset data for this
-        offset = newOffset;
+        _offset = newOffset;
         // seek this Reference object in the file
         fseek(file, getFilePosition(), SEEK_SET);
 
@@ -69,7 +69,7 @@ bool Reference::updateOffset(FILE* file, long newOffset)
         //skipUint(file);
 
         // write over the old offset
-        write(offset, file);
+        write(_offset, file);
 
         // restore the offset
         fseek(file, savedOffset, SEEK_SET);
@@ -80,7 +80,7 @@ bool Reference::updateOffset(FILE* file, long newOffset)
 
 Object* Reference::getObj()
 {
-    return ref;
+    return _ref;
 }
 
 }

+ 6 - 4
gameplay-encoder/src/Reference.h

@@ -28,6 +28,7 @@ public:
     /**
      * Updates the offset of this Reference object if it has already need written to file.
      * @param file The file stream.
+     * 
      * @return True if the offset was updates, false otherwise.
      */
     bool updateOffset(FILE* file);
@@ -36,6 +37,7 @@ public:
      * Updates the offset of this Reference object if it has already need written to file.
      * @param file The file stream.
      * @param newOffset The new file offset.
+     * 
      * @return True if the offset in the binary file was updated. False if this ref hasn't been written to file yet.
      */
     bool updateOffset(FILE* file, long newOffset);
@@ -43,11 +45,11 @@ public:
     Object* getObj();
 
 private:
-    std::string xref;
-    unsigned int type;
-    unsigned int offset;
+    std::string _xref;
+    unsigned int _type;
+    unsigned int _offset;
 
-    Object* ref;
+    Object* _ref;
 };
 
 }

+ 9 - 9
gameplay-encoder/src/ReferenceTable.cpp

@@ -13,13 +13,13 @@ ReferenceTable::~ReferenceTable(void)
 
 void ReferenceTable::add(std::string xref, Object* obj)
 {
-    table[xref] = Reference(xref, obj);
+    _table[xref] = Reference(xref, obj);
 }
 
 Object* ReferenceTable::get(const std::string& xref)
 {
-    std::map<std::string, Reference>::iterator it = table.find(xref);
-    if (it != table.end())
+    std::map<std::string, Reference>::iterator it = _table.find(xref);
+    if (it != _table.end())
     {
         Reference ref = it->second;
         return ref.getObj();
@@ -29,8 +29,8 @@ Object* ReferenceTable::get(const std::string& xref)
 
 void ReferenceTable::writeBinary(FILE* file)
 {
-    write(table.size(), file);
-    for ( std::map<std::string, Reference>::iterator i=table.begin() ; i != table.end(); i++ )
+    write(_table.size(), file);
+    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); i++ )
     {
         i->second.writeBinary(file);
     }
@@ -39,7 +39,7 @@ void ReferenceTable::writeBinary(FILE* file)
 void ReferenceTable::writeText(FILE* file)
 {
     fprintf(file, "<RefTable>\n");
-    for ( std::map<std::string, Reference>::iterator i=table.begin() ; i != table.end(); i++ )
+    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); i++ )
     {
         i->second.writeText(file);
     }
@@ -48,7 +48,7 @@ void ReferenceTable::writeText(FILE* file)
 
 void ReferenceTable::updateOffsets(FILE* file)
 {
-    for (std::map<std::string, Reference>::iterator i = table.begin(); i != table.end(); i++)
+    for (std::map<std::string, Reference>::iterator i = _table.begin(); i != _table.end(); i++)
     {
         Reference& ref = i->second;
         ref.updateOffset(file);
@@ -57,12 +57,12 @@ void ReferenceTable::updateOffsets(FILE* file)
 
 std::map<std::string, Reference>::iterator ReferenceTable::begin()
 {
-    return table.begin();
+    return _table.begin();
 }
 
 std::map<std::string, Reference>::iterator ReferenceTable::end()
 {
-    return table.end();
+    return _table.end();
 }
 
 }

+ 14 - 1
gameplay-encoder/src/ReferenceTable.h

@@ -27,19 +27,32 @@ public:
      */
     virtual ~ReferenceTable(void);
 
+    /**
+     * Adds an object to the reference table.
+     * 
+     * @param xref The xref for the object.
+     * @param obj The object to be added.
+     */
     void add(std::string xref, Object* obj);
+
     Object* get(const std::string& xref);
 
     void writeBinary(FILE* file);
     void writeText(FILE* file);
 
+    /**
+     * Updates the file positon offsets of the Reference objects in the GamePlay binary file.
+     * This needs to be called after all of the objects have been written.
+     * 
+     * @param file The file pointer.
+     */
     void updateOffsets(FILE* file);
 
     std::map<std::string, Reference>::iterator begin();
     std::map<std::string, Reference>::iterator end();
 
 private:
-    std::map<std::string, Reference> table;
+    std::map<std::string, Reference> _table;
 };
 
 }

+ 19 - 19
gameplay-encoder/src/Scene.cpp

@@ -5,11 +5,11 @@
 namespace gameplay
 {
 
-Scene::Scene(void) : cameraNode(NULL)
+Scene::Scene(void) : _cameraNode(NULL)
 {
-    ambientColor[0] = 0.0f;
-    ambientColor[1] = 0.0f;
-    ambientColor[2] = 0.0f;
+    _ambientColor[0] = 0.0f;
+    _ambientColor[1] = 0.0f;
+    _ambientColor[2] = 0.0f;
 }
 
 Scene::~Scene(void)
@@ -29,45 +29,45 @@ const char* Scene::getElementName(void) const
 void Scene::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
-    writeBinaryObjects(nodes, file);
-    if (cameraNode)
+    writeBinaryObjects(_nodes, file);
+    if (_cameraNode)
     {
-        cameraNode->writeBinaryXref(file);
+        _cameraNode->writeBinaryXref(file);
     }
     else
     {
         writeZero(file);
     }
-    write(ambientColor, Light::COLOR_SIZE, file);
+    write(_ambientColor, Light::COLOR_SIZE, file);
 }
 void Scene::writeText(FILE* file)
 {
     fprintElementStart(file);
-    for (std::list<Node*>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
     {
         (*i)->writeText(file);
     }
-    if (cameraNode)
+    if (_cameraNode)
     {
-        fprintfElement(file, "activeCamera", cameraNode->getId());
+        fprintfElement(file, "activeCamera", _cameraNode->getId());
     }
-    fprintfElement(file, "ambientColor", ambientColor, Light::COLOR_SIZE);
+    fprintfElement(file, "ambientColor", _ambientColor, Light::COLOR_SIZE);
     fprintElementEnd(file);
 }
 
 void Scene::add(Node* node)
 {
-    nodes.push_back(node);
+    _nodes.push_back(node);
 }
 
 void Scene::setActiveCameraNode(Node* node)
 {
-    cameraNode = node;
+    _cameraNode = node;
 }
 
 Node* Scene::getFirstCameraNode() const
 {
-    for (std::list<Node*>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
     {
         Node* n = (*i)->getFirstCameraNode();
         if (n)
@@ -81,14 +81,14 @@ Node* Scene::getFirstCameraNode() const
 void Scene::calcAmbientColor()
 {
     float values[3] = {0.0f, 0.0f, 0.0f};
-    for (std::list<Node*>::const_iterator i = nodes.begin(); i != nodes.end(); i++)
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); i++)
     {
         calcAmbientColor(*i, values);
     }
     
-    ambientColor[0] = std::min(values[0], 1.0f);
-    ambientColor[1] = std::min(values[1], 1.0f);
-    ambientColor[2] = std::min(values[2], 1.0f);
+    _ambientColor[0] = std::min(values[0], 1.0f);
+    _ambientColor[1] = std::min(values[1], 1.0f);
+    _ambientColor[2] = std::min(values[2], 1.0f);
 }
 
 void Scene::calcAmbientColor(const Node* node, float* values) const

+ 4 - 3
gameplay-encoder/src/Scene.h

@@ -61,9 +61,10 @@ private:
      */
     void calcAmbientColor(const Node* node, float* values) const;
 
-    std::list<Node*> nodes;
-    Node* cameraNode;
-    float ambientColor[Light::COLOR_SIZE];
+private:
+    std::list<Node*> _nodes;
+    Node* _cameraNode;
+    float _ambientColor[Light::COLOR_SIZE];
 };
 
 }

+ 32 - 1
gameplay-encoder/src/StringUtil.cpp

@@ -14,6 +14,37 @@ inline char lowercase(char c)
     return c;
 }
 
+bool startsWith(const char* str, const char* prefix, bool ignoreCase)
+{
+    size_t length = strlen(str);
+    size_t prefixLength = strlen(prefix);
+
+    if (prefixLength > length)
+    {
+        return false;
+    }
+
+    const char* p = str;
+    while (*p != '\0' && *prefix != '\0')
+    {
+        if (ignoreCase)
+        {
+            if (lowercase(*p) != lowercase(*prefix))
+            {
+                return false;
+            }
+        }
+        else if (*p != *prefix)
+        {
+            return false;
+        }
+        
+        ++p;
+        ++prefix;
+    }
+    return true;
+}
+
 bool endsWith(const char* str, const char* suffix, bool ignoreCase)
 {
     size_t length = strlen(str);
@@ -27,7 +58,7 @@ bool endsWith(const char* str, const char* suffix, bool ignoreCase)
     size_t offset = length - suffixLength;
 
     const char* p = str + offset;
-    while (*p != '\0')
+    while (*p != '\0' && *suffix != '\0')
     {
         if (ignoreCase)
         {

+ 1 - 0
gameplay-encoder/src/StringUtil.h

@@ -6,6 +6,7 @@
 namespace gameplay
 {
 
+bool startsWith(const char* str, const char* prefix, bool ignoreCase = true);
 bool endsWith(const char* str, const char* suffix, bool ignoreCase = true);
 
 /**

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

@@ -89,16 +89,20 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     // Find the width of the image.
     for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
     {
-        // Load glyph image into the slot (erase previous one) 
+        // Load glyph image into the slot (erase previous one)
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
         if (error)
+        {
             fprintf(stderr, "FT_Load_Char error : %d \n", error);
+        }
         
         int bitmapRows = slot->bitmap.rows;
         actualfontHeight = (actualfontHeight < bitmapRows) ? bitmapRows : actualfontHeight;
         
         if (slot->bitmap.rows > slot->bitmap_top)
-          bitmapRows += (slot->bitmap.rows - slot->bitmap_top);
+        {
+            bitmapRows += (slot->bitmap.rows - slot->bitmap_top);
+        }
         rowSize = (rowSize < bitmapRows) ? bitmapRows : rowSize;
     }
 
@@ -133,7 +137,9 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
             // Load glyph image into the slot (erase the previous one).
             error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
             if (error)
+            {
                 fprintf(stderr, "FT_Load_Char error : %d \n", error);
+            }
 
             // Glyph image.
             int glyphWidth = slot->bitmap.pitch;
@@ -163,7 +169,9 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
             penY = row * rowSize;
 
             if (ascii == (END_INDEX-1))
+            {
                 textureSizeFound = true;
+            }
 
             i++;
         }
@@ -174,7 +182,9 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     for (;;)
     {
         if ((penY + rowSize) >= pow(2.0, powerOf2))
+        {
             powerOf2++;
+        }
         else
         {
             imageHeight = (int)pow(2.0, powerOf2);
@@ -194,7 +204,9 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
         // Load glyph image into the slot (erase the previous one).
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
         if (error)
+        {
             fprintf(stderr, "FT_Load_Char error : %d \n", error);
+        }
 
         // Glyph image.
         unsigned char* glyphBuffer =  slot->bitmap.buffer;

+ 1 - 1
gameplay-encoder/src/TTFFontEncoder.h

@@ -14,7 +14,7 @@
 
 // Structure of Glyph.
 class Glyph
-{   
+{
 public:
     unsigned int index;
     unsigned int width;

+ 7 - 0
gameplay-encoder/src/Vector2.h

@@ -115,6 +115,7 @@ public:
      *
      * @param v1 The first vector.
      * @param v2 The second vector.
+     * 
      * @return The angle between the two vectors, in radians.
      */
     static float angle(const Vector2& v1, const Vector2& v2);
@@ -157,6 +158,7 @@ public:
      * Returns the distance between this vector and v.
      *
      * @param v The other vector.
+     * 
      * @return The distance between this vector and v.
      * @see distanceSquared
      */
@@ -171,6 +173,7 @@ public:
      * this method instead of distance.
      *
      * @param v The other vector.
+     * 
      * @return The squared distance between this vector and v.
      * @see distance
      */
@@ -180,6 +183,7 @@ public:
      * Returns the dot product of this vector and the specified vector.
      *
      * @param v The vector to compute the dot product with.
+     * 
      * @return The dot product.
      */
     float dot(const Vector2& v);
@@ -189,6 +193,7 @@ public:
      *
      * @param v1 The first vector.
      * @param v2 The second vector.
+     * 
      * @return The dot product between the vectors.
      */
     static float dot(const Vector2& v1, const Vector2& v2);
@@ -311,7 +316,9 @@ public:
     inline bool operator<(const Vector2& v) const
     {
         if (x == v.x)
+        {
             return y < v.y;
+        }
         return x < v.x;
     }
     inline bool operator==(const Vector2& v) const

+ 5 - 0
gameplay-encoder/src/Vector3.h

@@ -136,6 +136,7 @@ public:
      *
      * @param v1 The first vector.
      * @param v2 The second vector.
+     * 
      * @return The angle between the two vectors, in radians.
      */
     static float angle(const Vector3& v1, const Vector3& v2);
@@ -195,6 +196,7 @@ public:
      * Returns the distance between this vector and v.
      *
      * @param v The other vector.
+     * 
      * @return The distance between this vector and v.
      * @see distanceSquared
      */
@@ -209,6 +211,7 @@ public:
      * this method instead of distance.
      *
      * @param v The other vector.
+     * 
      * @return The squared distance between this vector and v.
      * @see distance
      */
@@ -218,6 +221,7 @@ public:
      * Returns the dot product of this vector and the specified vector.
      *
      * @param v The vector to compute the dot product with.
+     * 
      * @return The dot product.
      */
     float dot(const Vector3& v);
@@ -227,6 +231,7 @@ public:
      *
      * @param v1 The first vector.
      * @param v2 The second vector.
+     * 
      * @return The dot product between the vectors.
      */
     static float dot(const Vector3& v1, const Vector3& v2);

+ 5 - 0
gameplay-encoder/src/Vector4.h

@@ -145,6 +145,7 @@ public:
      *
      * @param v1 The first vector.
      * @param v2 The second vector.
+     * 
      * @return The angle between the two vectors, in radians.
      */
     static float angle(const Vector4& v1, const Vector4& v2);
@@ -187,6 +188,7 @@ public:
      * Returns the distance between this vector and v.
      *
      * @param v The other vector.
+     * 
      * @return The distance between this vector and v.
      * @see distanceSquared
      */
@@ -201,6 +203,7 @@ public:
      * this method instead of distance.
      *
      * @param v The other vector.
+     * 
      * @return The squared distance between this vector and v.
      * @see distance
      */
@@ -210,6 +213,7 @@ public:
      * Returns the dot product of this vector and the specified vector.
      *
      * @param v The vector to compute the dot product with.
+     * 
      * @return The dot product.
      */
     float dot(const Vector4& v);
@@ -219,6 +223,7 @@ public:
      *
      * @param v1 The first vector.
      * @param v2 The second vector.
+     * 
      * @return The dot product between the vectors.
      */
     static float dot(const Vector4& v1, const Vector4& v2);

+ 1 - 1
gameplay-encoder/src/Vertex.h

@@ -69,7 +69,7 @@ public:
 
     inline bool operator==(const Vertex& v) const
     {
-        return position==v.position && normal==v.normal && tangent==v.tangent && binormal==v.binormal && texCoord==v.texCoord && 
+        return position==v.position && normal==v.normal && tangent==v.tangent && binormal==v.binormal && texCoord==v.texCoord &&
             blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
 

+ 21 - 169
gameplay-encoder/src/main.cpp

@@ -1,120 +1,24 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <iostream>
 #include <string>
-#include <sys/stat.h>
-#ifdef WIN32
-    #define PATH_MAX    _MAX_PATH
-    #define realpath(A,B)    _fullpath(B,A,PATH_MAX)
-#endif
 
 #include "DAESceneEncoder.h"
 #include "TTFFontEncoder.h"
-#include "StringUtil.h"
 #include "GPBDecoder.h"
+#include "EncoderArguments.h"
 
-using namespace std;
 using namespace gameplay;
 
-enum FileFormat
-{
-    FILEFORMAT_UNKNOWN,
-    FILEFORMAT_DAE,
-    FILEFORMAT_TTF,
-    FILEFORMAT_GPB
-};
-
-
-/**
- * Gets the file format from the file path based on extension.
- */
-FileFormat getFileFormat(const std::string& filename)
-{
-    // Extract the extension
-    std::string ext = "";
-    size_t pos = filename.find_last_of(".");
-    if (pos != std::string::npos)
-        ext = filename.substr(pos + 1);
-    
-    // Match every supported extension with its format constant
-    if (ext.compare("dae") == 0 || ext.compare("DAE") == 0)
-    {
-        return FILEFORMAT_DAE;
-    }
-    if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
-    {
-        return FILEFORMAT_TTF;
-    }
-    if (ext.compare("gpb") == 0 || ext.compare("GPB") == 0)
-    {
-        return FILEFORMAT_GPB;
-    }
-
-    return FILEFORMAT_UNKNOWN;
-}
-
-
-/**
- * Tests if a file exists on the file system.
- */
-bool fileExists(const std::string& filename)
-{
-    struct stat buf;
-    if (stat(filename.c_str(), &buf) != -1)
-    {
-        return true;
-    }
-    return false;
-}
-
-
-/**
- * Replaces all instance of oldChar with newChar in str.
- */
-void replace_char(char* str, char oldChar, char newChar)
-{
-    for (; *str != '\0'; str++)
-    {
-        if (*str == oldChar)
-            *str = newChar;
-    }
-}
-
 std::string getFileName(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();
-    string filename = filepath.substr(index + 1, length);
+    std::string filename = filepath.substr(index + 1, length);
     length = filename.length();
-    string output = filename.substr(0, (length-4));
+    std::string output = filename.substr(0, (length-4));
     return output;
-    
-}
-
-
-std::string getRealpath(const std::string& filepath)
-{
-    char path[PATH_MAX + 1]; /* not sure about the "+ 1" */
-    realpath(filepath.c_str(), path);
-    replace_char(path, '\\', '/');
-    return std::string(path);
-}
-
-
-void usage()
-{
-    fprintf(stderr,"Usage: gameplay-encoder [options] <filepath>\n");
-    fprintf(stderr,".dae file options:\n");
-    fprintf(stderr," -i<id>\tFilter by node ID\n");
-    fprintf(stderr," -t\tWrite text/xml\n");
-    fprintf(stderr,".ttf file options:\n");
-    fprintf(stderr,"-s<size of font> -p \n");
-    exit(8);
 }
 
-
 /**
  * Main application entry point.
  *
@@ -129,102 +33,50 @@ void usage()
  */
 int main(int argc, const char** argv)
 {
-    std::string filepath;
-    const char* id = NULL;
-    unsigned int size = 0;
-    bool fontpreview = false;
-    bool text = false;
-
-    if (argc <= 1)
-    {
-        usage();
-    }
+    EncoderArguments arguments(argc, argv);
 
-    if ( endsWith(argv[1], ".dae") || endsWith(argv[1], ".gpb"))
+    if (arguments.parseErrorOccured())
     {
-        filepath = argv[1];
-    }
-    else
-    {
-        if (argc < 3)
-        {
-            usage();
-        }
-        else
-        {   
-            filepath = argv[argc-1];
-        }
+        arguments.printUsage();
+        return 0;
     }
 
     // Check if the file exists.
-    if (!fileExists(filepath))
+    if (!arguments.fileExists())
     {
-        fprintf(stderr, "Error: File not found: %s\n", filepath.c_str());
+        fprintf(stderr, "Error: File not found: %s\n", arguments.getFilePathPointer());
         return -1;
     }
-    // File exists
-    fprintf(stderr, "Encoding file: %s\n", filepath.c_str());
-    
-    // Get the file format
-    FileFormat fileFormat = getFileFormat(filepath);
-
-    // Parse arguments
-    while ((argc > 1) && (argv[1][0] == '-'))
-    {
-        switch (argv[1][1])
-        {
-            case 'i':
-            case 'o':
-                id = &argv[1][2];
-                break;
 
-            case 's':
-                size = atoi(&argv[1][2]);
-                break;
-            
-            case 'p':
-                fontpreview = true;
-                break;
-            case 't':
-                text = true;
-                break;
-
-            default:
-                usage();
-        }
-        ++argv;
-        --argc;
-    }
-    
+    // File exists
+    fprintf(stderr, "Encoding file: %s\n", arguments.getFilePathPointer());
 
-    switch (fileFormat)
+    switch (arguments.getFileFormat())
     {
-    case FILEFORMAT_DAE:
+    case EncoderArguments::FILEFORMAT_DAE:
         {
-            std::string realpath = getRealpath(filepath);
+            std::string realpath = arguments.getFilePath();
             DAESceneEncoder daeEncoder;
-            daeEncoder.write(realpath, id, text);
+            daeEncoder.write(realpath, arguments);
             break;
         }
-    case FILEFORMAT_TTF:
+    case EncoderArguments::FILEFORMAT_TTF:
         {
-            std::string realpath = getRealpath(filepath);
+            std::string realpath = arguments.getFilePath();
             std::string id = getFileName(realpath);
-            writeFont(realpath.c_str(), size, id.c_str(), fontpreview);
+            writeFont(realpath.c_str(), arguments.getFontSize(), id.c_str(), arguments.fontPreviewEnabled());
             break;
         }
-
-    case FILEFORMAT_GPB:
+    case EncoderArguments::FILEFORMAT_GPB:
         {
-            std::string realpath = getRealpath(filepath);
+            std::string realpath = arguments.getFilePath();
             GPBDecoder decoder;
             decoder.readBinary(realpath);
             break;
         }
-               
    default:
         {
-            fprintf(stderr, "Error: Unsupported file format: %s\n", filepath.c_str());
+            fprintf(stderr, "Error: Unsupported file format: %s\n", arguments.getFilePathPointer());
             return -1;
         }
     }

+ 99 - 26
gameplay-resources/res/shaders/bumped-specular.fsh

@@ -1,41 +1,114 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightColor;                        // RGB color of the light
-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
+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.
 
 // Inputs
-varying vec2 v_texCoord;                        // Texture Coordinate (u,v)
-varying vec3 v_lightDirectionTangentSpace;        // Direction of the light in tangent space
-varying vec3 v_cameraDirectionTangentSpace;     // Direction the camera is looking at in tangent space
+varying vec2 v_texCoord;                    // Texture Coordinate.
+varying vec3 v_cameraDirection;             // Direction the camera is looking at in tangent space.
 
-void main()
+// 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)
 {
-    // Fetch diffuse color from texture
-    vec4 diffuseColor = texture2D(u_diffuseTexture, v_texCoord);
-    
-    // Normalize vectors
-    vec3 cameraDirection = normalize(v_cameraDirectionTangentSpace);
-    vec3 lightDirection = normalize(v_lightDirectionTangentSpace);
-    // Fetch normals from the normal map
-    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0);
-    
     // Ambient
-    vec3 lightColor = u_ambientColor;
+    _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = max(0.0, dot(normalVector, lightDirection));
-    lightColor += (u_lightColor * diffuseIntensity);
+    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 = pow(max(0.0, dot(normalVector, halfVector)), u_specularExponent);
+    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);
     
-    // Light the pixel.
-    gl_FragColor = diffuseColor;
-    gl_FragColor.rgb *= lightColor;
-    gl_FragColor.rgb += vec3(diffuseColor.rgb * specularIntensity);
+    // Fetch point light attenuation.
+    lighting(normalVector, cameraDirection, vertexToPointLightDirection, v_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.
+
+float lerpstep( float lower, float upper, float s)
+{
+    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
+}
+
+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 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 part of the cone the light direction points to (inner or outer).
+    float spotLightAttenuation = lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
+
+    lighting(normalVector, cameraDirection, vertexToSpotLightDirection, spotLightAttenuation);
+}
+
+#else
+
+varying vec3 v_directionalLightDirection;    // Direction of light in tangent space.
+
+void applyLight()
+{
+    // Normalize 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 lightDirection = normalize(v_directionalLightDirection);
+
+    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;
 }

+ 79 - 17
gameplay-resources/res/shaders/bumped-specular.vsh

@@ -1,21 +1,83 @@
 // Uniforms
-uniform    vec3 u_lightDirection;                        // Direction of the light
-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.
+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 mat4 u_worldViewMatrix;                 // Matrix to tranform a position 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)
+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_lightDirectionTangentSpace;            // Direction of the light in tangent space.
-varying vec3 v_cameraDirectionTangentSpace;         // Direction the camera is looking at in tangent space.
+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_pointLightRadius;               // Radius 
+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 vertexToPointLightDirection = tangentSpaceTransformMatrix * lightDirection;
+
+    // Attenuation
+    v_pointLightAttenuation = 1 - dot (lightDirection * u_pointLightRadius, lightDirection * u_pointLightRadius);
+
+    // Output light direction.
+    v_vertexToPointLightDirection =  vertexToPointLightDirection;
+}
+
+#elif defined(SPOT_LIGHT)
+
+uniform vec3 u_spotLightPosition;               // Position
+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.
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    // World space position.
+    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;
+
+    // Output light direction.
+    v_vertexToSpotLightDirection = lightDirection;
+}
+
+#else
+
+uniform vec3 u_lightDirection;                    // Direction
+varying vec3 v_directionalLightDirection;         // Direction of light in tangent space.
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    // Transform light direction to tangent space.
+    v_directionalLightDirection = tangentSpaceTransformMatrix * u_lightDirection;
+}
+
+#endif
 
 void main()
 {
@@ -31,12 +93,12 @@ void main()
     // Create a transform to convert a vector to tangent space.
     mat3 tangentSpaceTransformMatrix = mat3(tangentVector, binormalVector, normalVector);
 
-    // Transform light direction to tangent space.
-    v_lightDirectionTangentSpace = tangentSpaceTransformMatrix * u_lightDirection;
-
     // Compute camera direction and transform it to tangent space.
     vec4 positionWorldSpace = u_worldMatrix * a_position;
-    v_cameraDirectionTangentSpace = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldSpace.xyz);
+    v_cameraDirection = tangentSpaceTransformMatrix * (u_cameraPosition - positionWorldSpace.xyz);
+
+    // Apply light.
+    applyLight(tangentSpaceTransformMatrix);
 
     // Pass on the texture coordinates to Fragment shader.
     v_texCoord = a_texCoord;

+ 90 - 20
gameplay-resources/res/shaders/bumped.fsh

@@ -1,32 +1,102 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightColor;                    // RGB color of the light
-uniform vec3 u_ambientColor;                // Ambient color
-uniform sampler2D u_diffuseTexture;            // Texture
-uniform sampler2D u_normalMapTexture;        // Normalmap
+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.
 
 // Inputs
-varying vec3 v_lightDirectionTangentSpace;    // light direction
-varying vec2 v_texCoord;                    // Texture coordinate.
+varying vec2 v_texCoord;                    // Texture Coordinate.
 
-void main()
+// Common colors
+vec4 _baseColor;                            // Base color
+vec3 _ambientColor;                         // Ambient Color
+vec3 _diffuseColor;                         // Diffuse Color
+
+void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
 {
-    // Fetch normals from the normal map
-    vec3 normalVector = texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0;
-    normalVector = normalize(normalVector);
-    
-    // Fetch diffuse color from texture
-    gl_FragColor = texture2D(u_diffuseTexture, v_texCoord);
-    
     // Ambient
-    vec3 lightColor = u_ambientColor;
+    _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    vec3 lightDirection = normalize(v_lightDirectionTangentSpace);
-    float diffuseIntensity = clamp(dot(normalVector, lightDirection), 0.0, 1.0);
-    lightColor += (u_lightColor * diffuseIntensity);
+    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);
+    
+    // Fetch point light attenuation.
+    lighting(normalVector, vertexToPointLightDirection, v_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.
+
+float lerpstep( float lower, float upper, float s)
+{
+    return clamp( ( s - lower ) / ( upper - lower ), 0.0, 1.0 );
+}
+
+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 spotLightDirection =normalize(v_spotLightDirection);
+    vec3 vertexToSpotLightDirection = normalize(v_spotLightDirectionCurrent);
+    
+    // "-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 part of the cone the light direction points to (inner or outer).
+    float spotLightAttenuation = lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
+
+    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
+}
+
+#else
+
+varying vec3 v_directionalLightDirection;    // Direction of light in tangent space.
+
+void applyLight()
+{
+    // Normalize vectors.
+    // Fetch normals from the normal map
+    vec3 normalVector = normalize(texture2D(u_normalMapTexture, v_texCoord).rgb * 2.0 - 1.0);
+    vec3 lightDirection = normalize(v_directionalLightDirection);
+
+    lighting(normalVector, -lightDirection, 1.0);
+}
+#endif
+
+void main()
+{
+    // Fetch diffuse color from texture.
+    _baseColor = texture2D(u_diffuseTexture, v_texCoord);
+
+    // Apply light
+    applyLight();
 
-    // Light the fragment.
-    gl_FragColor.rgb *= lightColor;
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = _ambientColor + _diffuseColor;
 }

+ 82 - 19
gameplay-resources/res/shaders/bumped.vsh

@@ -1,36 +1,99 @@
 // Uniforms
-uniform vec3 u_lightDirection;                        // Direction of the light
-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_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)
+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 vec3 v_lightDirectionTangentSpace;            // Direction of light in tangent space.
-varying vec2 v_texCoord;                            // Texture coordinate (u, v).
+varying vec2 v_texCoord;                        // Texture Coordinate (u,v)
+
+#if defined(POINT_LIGHT)
+
+uniform mat4 u_worldViewMatrix;                 // Matrix to tranform a position to view space.
+uniform vec3 u_pointLightPosition;              // Position
+uniform float u_pointLightRadius;               // Radius 
+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 - dot (lightDirection * u_pointLightRadius, lightDirection * u_pointLightRadius);
+
+    // Output light direction.
+    v_vertexToSpotLightDirection =  vertexToSpotLightDirection;
+}
+
+#elif defined(SPOT_LIGHT)
+
+uniform mat4 u_worldViewMatrix;                  // Matrix to tranform a position to view space.
+uniform vec3 u_spotLightPosition;                // Position
+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.
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    // World space position.
+    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;
+
+    // Output light direction.
+    v_vertexToSpotLightDirection = lightDirection;
+}
+
+#else
+
+uniform vec3 u_lightDirection;                    // Direction
+varying vec3 v_directionalLightDirection;         // Direction of light in tangent space.
+
+void applyLight(mat3 tangentSpaceTransformMatrix)
+{
+    // Transform light direction to tangent space.
+    v_directionalLightDirection = tangentSpaceTransformMatrix * u_lightDirection;
+}
+
+#endif
 
 void main()
 {
     // Transform position to clip space.
     gl_Position = u_worldViewProjectionMatrix * a_position;
 
-    // Transform normal, tangent and binormal to view space.
+    // Transform the normal, tangent and binormals to  view space.
     mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix);
-    vec3 tangent  = inverseTransposeWorldViewMatrix * a_tangent;
-    vec3 normal = inverseTransposeWorldViewMatrix * a_normal;
-    vec3 binormal = inverseTransposeWorldViewMatrix * a_binormal;
+    vec3 tangentVector  = 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(tangent, binormal, normal);
-    
-    // Transform light direction to tangent space.
-    v_lightDirectionTangentSpace = tangentSpaceTransformMatrix * u_lightDirection;
+    mat3 tangentSpaceTransformMatrix = mat3(tangentVector, binormalVector, normalVector);
+
+    // Apply light.
+    applyLight(tangentSpaceTransformMatrix);
 
     // Pass on the texture coordinates to Fragment shader.
     v_texCoord = a_texCoord;
-}
+}

+ 95 - 21
gameplay-resources/res/shaders/colored-specular.fsh

@@ -1,36 +1,110 @@
 precision highp float;
 
 // Uniforms
-uniform    vec3 u_lightDirection;        // Direction of the light
-uniform vec3 u_lightColor;            // RGB color of the light
-uniform vec3 u_ambientColor;        // Ambient color
-uniform vec4 u_diffuseColor;        // Diffuse color
-uniform float u_specularExponent;    // Specular exponent or shininess property.
+uniform vec3 u_lightColor;                      // Light color
+uniform vec3 u_ambientColor;                    // Ambient color
+uniform float u_specularExponent;               // Specular exponent or shininess property.
+uniform vec4 u_diffuseColor;                    // Diffuse color
 
 // Inputs
-varying vec3 v_normalVector;        // Normal vector in view space.
-varying vec3 v_cameraDirection;        // Camera direction.
+varying vec3 v_normalVector;                    // NormalVector in view space.
+varying vec3 v_cameraDirection;                 // Camera direction
 
-void main()
+// 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)
 {
-    // Normalize the vectors.
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(u_lightDirection);
-    vec3 normalVector = normalize(v_normalVector);
-    
     // Ambient
-    vec3 lightColor = u_ambientColor;
+    _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = max(0.0, dot(normalVector, lightDirection));
-    lightColor += (u_lightColor * diffuseIntensity);
+    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 = pow(max(0.0, dot(normalVector, halfVector)), u_specularExponent);
+    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.
+
+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 part of the cone the light direction points to (inner or outer).
+    float 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 = u_diffuseColor;
+
+    // Apply light
+    applyLight();
 
-    // Light the pixel.
-    gl_FragColor = u_diffuseColor;
-    gl_FragColor.rgb *= lightColor;
-    gl_FragColor.rgb += (u_diffuseColor.rgb * specularIntensity);
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
 }

+ 166 - 9
gameplay-resources/res/shaders/colored-specular.vsh

@@ -1,27 +1,184 @@
 // 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.
+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 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 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[2]) * 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[2]) * 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_pointLightRadius;                   // Radius 
+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 - dot (lightDirection * u_pointLightRadius, lightDirection * u_pointLightRadius);
+
+    // 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
+varying vec3 v_vertexToSpotLightDirection;          // 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.
+    v_vertexToSpotLightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
+}
+
+#else
+
+void applyLight(vec4 position)
+{
+}
+
+#endif
+
 void main()
 {
+    vec4 position = getPosition();
+    vec3 normal = getNormal();
+
     // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * a_position;
+    gl_Position = u_worldViewProjectionMatrix * position;
 
     // Transform normal to view space.
     mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix);
-    v_normalVector = inverseTransposeWorldViewMatrix * a_normal;
+    v_normalVector = inverseTransposeWorldViewMatrix * normal;
 
     // Compute the camera direction.
-    vec4 positionWorldSpace = u_worldMatrix * a_position;
+    vec4 positionWorldSpace = u_worldMatrix * position;
     v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
-}
+
+    // Apply light.
+    applyLight(position);
+}

+ 86 - 12
gameplay-resources/res/shaders/colored.fsh

@@ -1,24 +1,98 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightDirection;        // Direction of the light
-uniform vec3 u_lightColor;            // RGB color of the light
-uniform vec3 u_ambientColor;        // Ambient color
-uniform vec4 u_diffuseColor;        // Diffuse color
+uniform vec3 u_lightColor;                  // Light color
+uniform vec3 u_ambientColor;                // Ambient color
+uniform vec4 u_diffuseColor;                // Diffuse color
 
 // Inputs
-varying vec3 v_normalVector;        // NormalVector in view space (Normalized).
+varying vec3 v_normalVector;                // NormalVector in view space.
 
-void main()
+// Global variables
+vec4 _baseColor;                            // Base color
+vec3 _ambientColor;                         // Ambient Color
+vec3 _diffuseColor;                         // Diffuse Color
+
+void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
 {
     // Ambient
-    vec3 lightColor = u_ambientColor;
+    _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = max(dot(v_normalVector, u_lightDirection), 0.0);
-    lightColor += (u_lightColor * diffuseIntensity);
+    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 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.
+
+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 part of the cone the light direction points to (inner or outer).
+    float 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 = u_diffuseColor;
-    gl_FragColor.rgb *= lightColor;
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = _ambientColor + _diffuseColor;
 }

+ 165 - 7
gameplay-resources/res/shaders/colored.vsh

@@ -1,20 +1,178 @@
 // Uniforms
-uniform mat4 u_worldViewProjectionMatrix;            // Matrix to transform a position to clip 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.
 
 // Inputs
-attribute vec4 a_position;                            // Vertex Position (x, y, z, w).
-attribute vec3 a_normal;                            // Vertex Normal (x, y, z).
+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 (Normalized).
+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[2]) * 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[2]) * 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_pointLightRadius;                   // Radius 
+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 - dot (lightDirection * u_pointLightRadius, lightDirection * u_pointLightRadius);
+
+    // 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
+varying vec3 v_vertexToSpotLightDirection;          // 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_spotLightPosition - positionWorldViewSpace.xyz;
+
+    // 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 * a_position;
+    gl_Position = u_worldViewProjectionMatrix * position;
 
     // Transform normal to view space.
     mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix);
-    v_normalVector = normalize(inverseTransposeWorldViewMatrix * a_normal);
-}
+    v_normalVector = inverseTransposeWorldViewMatrix * normal;
+
+    // Apply light.
+    applyLight(position);
+}

+ 96 - 25
gameplay-resources/res/shaders/diffuse-specular.fsh

@@ -1,40 +1,111 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightDirection;            // Direction of the light
-uniform vec3 u_lightColor;                // RGB color of the light
-uniform vec3 u_ambientColor;            // Ambient color
-uniform float u_specularExponent;        // Specular exponent or shininess property.
-uniform sampler2D u_diffuseTexture;        // Diffuse texture.
+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.
 
 // Inputs
-varying vec3 v_normalVector;            // NormalVector in view space.
-varying vec2 v_texCoord;                // Texture coordinate (u, v).
-varying vec3 v_cameraDirection;         // Camera direction
+varying vec3 v_normalVector;                    // NormalVector in view space.
+varying vec2 v_texCoord;                        // Texture coordinate (u, v).
+varying vec3 v_cameraDirection;                 // Camera direction
 
-void main()
+// 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)
 {
-    // Fetch diffuse color from texture.
-    vec4 diffuseColor = texture2D(u_diffuseTexture, v_texCoord);
-    
-    // Normalize the vectors.
-    vec3 cameraDirection = normalize(v_cameraDirection);
-    vec3 lightDirection = normalize(u_lightDirection);
-    vec3 normalVector = normalize(v_normalVector);
-    
     // Ambient
-    vec3 lightColor = u_ambientColor;
+    _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = max(0.0, dot(normalVector, lightDirection));
-    lightColor += (u_lightColor * diffuseIntensity);
+    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 = pow(max(0.0, dot(normalVector, halfVector)), u_specularExponent);
+    float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
+    specularIntensity = max(0.0, specularIntensity);
+    _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
+}
 
-    // Light the pixel
-    gl_FragColor = diffuseColor;
-    gl_FragColor.rgb *= lightColor;
-    gl_FragColor.rgb += vec3(diffuseColor.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.
+
+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 part of the cone the light direction points to (inner or outer).
+    float 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;
+}

+ 164 - 9
gameplay-resources/res/shaders/diffuse-specular.vsh

@@ -1,32 +1,187 @@
 // 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.
+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 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 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[2]) * 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[2]) * 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_pointLightRadius;                   // Radius 
+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 - dot (lightDirection * u_pointLightRadius, lightDirection * u_pointLightRadius);
+
+    // 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
+varying vec3 v_vertexToSpotLightDirection;          // 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.
+    v_vertexToSpotLightDirection = u_spotLightPosition - positionWorldViewSpace.xyz;
+}
+
+#else
+
+void applyLight(vec4 position)
+{
+}
+
+#endif
+
 void main()
 {
+    vec4 position = getPosition();
+    vec3 normal = getNormal();
+
     // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * a_position;
+    gl_Position = u_worldViewProjectionMatrix * position;
 
     // Transform normal to view space.
     mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix);
-    v_normalVector = inverseTransposeWorldViewMatrix * a_normal;
+    v_normalVector = inverseTransposeWorldViewMatrix * normal;
 
     // Compute the camera direction.
-    vec4 positionWorldSpace = u_worldMatrix * a_position;
+    vec4 positionWorldSpace = u_worldMatrix * position;
     v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
 
+    // Apply light.
+    applyLight(position);
+
     // Pass on the texture coordinates to Fragment shader.
     v_texCoord = a_texCoord;
 }

+ 85 - 11
gameplay-resources/res/shaders/diffuse.fsh

@@ -1,25 +1,99 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightDirection;              // Direction of the light
-uniform vec3 u_lightColor;                  // RGB color of the light
+uniform vec3 u_lightColor;                  // Light color
 uniform vec3 u_ambientColor;                // Ambient color
-uniform sampler2D u_diffuseTexture;         // Diffuse texture
+uniform sampler2D u_diffuseTexture;         // Diffuse texture.
 
 // Inputs
-varying vec3 v_normalVector;                // NormalVector in view space (Normalized).
+varying vec3 v_normalVector;                // NormalVector in view space.
 varying vec2 v_texCoord;                    // Texture coordinate (u, v).
 
-void main()
+// Global variables
+vec4 _baseColor;                            // Base color
+vec3 _ambientColor;                         // Ambient Color
+vec3 _diffuseColor;                         // Diffuse Color
+
+void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
 {
     // Ambient
-    vec3 lightColor = u_ambientColor;
+    _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = max(dot(v_normalVector, u_lightDirection), 0.0);
-    lightColor += (u_lightColor * diffuseIntensity);
+    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 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.
+
+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 part of the cone the light direction points to (inner or outer).
+    float spotLightAttenuation = lerpstep(u_spotLightOuterAngleCos, u_spotLightInnerAngleCos, spotCurrentAngleCos);
+
+    lighting(normalVector, vertexToSpotLightDirection, spotLightAttenuation);
+}
+
+#else
+
+uniform vec3 u_lightDirection;       // Light direction
 
-    // Light the pixel.
-    gl_FragColor = texture2D(u_diffuseTexture, v_texCoord);
-    gl_FragColor.rgb *= lightColor;
+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 = texture2D(u_diffuseTexture, v_texCoord);
+
+    // Apply light
+    applyLight();
+
+    // Light the pixel
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = _ambientColor + _diffuseColor;
+}

+ 169 - 10
gameplay-resources/res/shaders/diffuse.vsh

@@ -1,25 +1,184 @@
 // 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_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 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 (Normalized).
+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[2]) * 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[2]) * 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_pointLightRadius;                   // Radius
+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 - dot (lightDirection * u_pointLightRadius, lightDirection * u_pointLightRadius);
+
+    // 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
+varying vec3 v_vertexToSpotLightDirection;          // 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_spotLightPosition - positionWorldViewSpace.xyz;
+
+    // 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 * a_position;
+    gl_Position = u_worldViewProjectionMatrix * position;
 
     // Transform normal to view space.
     mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix);
-    v_normalVector = normalize(inverseTransposeWorldViewMatrix * a_normal);
+    v_normalVector = inverseTransposeWorldViewMatrix * normal;
+
+    // Apply light.
+    applyLight(position);
 
-    // Pass on texture coordinate to fragment shader.
+    // Pass on the texture coordinates to Fragment shader.
     v_texCoord = a_texCoord;
-}
+}

+ 8 - 8
gameplay-resources/res/shaders/parallax-specular.fsh

@@ -1,18 +1,18 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightColor;                        // RGB color of the light
+uniform vec3 u_lightColor;                      // RGB color of the light
 uniform vec3 u_ambientColor;                    // Ambient color
-uniform float u_specularExponent;                // Specular exponent or shininess property.
-uniform float u_parallaxHeight;                    // Parallax height
-uniform sampler2D u_diffuseTexture;                // Diffuse texture
-uniform sampler2D u_bumpMapTexture;                // Height map texture
-uniform sampler2D u_normalMapTexture;            // Normal map texture    
+uniform float u_specularExponent;               // Specular exponent or shininess property.
+uniform float u_parallaxHeight;                 // Parallax height
+uniform sampler2D u_diffuseTexture;             // Diffuse texture
+uniform sampler2D u_bumpMapTexture;             // Height map texture
+uniform sampler2D u_normalMapTexture;           // Normal map texture    
 
 // Inputs
 varying vec2 v_texCoord;                        // Texture coordinates (u,v)
-varying vec3 v_lightDirectionTangentSpace;        // Light direction in tangent space
-varying vec3 v_cameraDirectionTangentSpace;        // Camera direction in tangent space
+varying vec3 v_lightDirectionTangentSpace;      // Light direction in tangent space
+varying vec3 v_cameraDirectionTangentSpace;     // Camera direction in tangent space
 
 void main()
 {

+ 11 - 11
gameplay-resources/res/shaders/parallax-specular.vsh

@@ -1,21 +1,21 @@
 // Uniforms
-uniform    vec3 u_lightDirection;                        // Direction of the light
+uniform    vec3 u_lightDirection;                    // Direction of the light
 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.
+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)
-attribute vec2 a_texCoord;                            // Vertex Texture Coordinate (u, v)
+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)
+attribute vec3 a_binormal;                           // Vertex Binormal (actually Bi-tangent) (x, y, z)
 
 // Outputs
-varying vec2 v_texCoord;                            // Texture Coordinate (u,v)
-varying vec3 v_lightDirectionTangentSpace;            // Direction of the light in tangent space.
-varying vec3 v_cameraDirectionTangentSpace;         // Direction the camera is looking at in tangent space.
+varying vec2 v_texCoord;                             // Texture Coordinate (u,v)
+varying vec3 v_lightDirectionTangentSpace;           // Direction of the light in tangent space.
+varying vec3 v_cameraDirectionTangentSpace;          // Direction the camera is looking at in tangent space.
 
 void main()
 {

+ 7 - 7
gameplay-resources/res/shaders/parallax.fsh

@@ -1,17 +1,17 @@
 precision highp float;
 
 // Uniforms
-uniform vec3 u_lightColor;                        // RGB color of the light
+uniform vec3 u_lightColor;                      // RGB color of the light
 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
+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
 
 // Inputs
 varying vec2 v_texCoord;                        // Texture coordinates (u,v)
-varying vec3 v_lightDirectionTangentSpace;        // Light direction in tangent space
-varying vec3 v_cameraDirectionTangentSpace;        // Camera direction in tangent space
+varying vec3 v_lightDirectionTangentSpace;      // Light direction in tangent space
+varying vec3 v_cameraDirectionTangentSpace;     // Camera direction in tangent space
 
 void main()
 {

+ 11 - 11
gameplay-resources/res/shaders/parallax.vsh

@@ -1,21 +1,21 @@
 // Uniforms
-uniform    vec3 u_lightDirection;                        // Direction of the light
+uniform    vec3 u_lightDirection;                    // Direction of the light
 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.
+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)
-attribute vec2 a_texCoord;                            // Vertex Texture Coordinate (u, v)
+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)
+attribute vec3 a_binormal;                           // Vertex Binormal (actually Bi-tangent) (x, y, z)
 
 // Outputs
-varying vec2 v_texCoord;                            // Texture Coordinate (u,v)
-varying vec3 v_lightDirectionTangentSpace;            // Direction of the light in tangent space.
-varying vec3 v_cameraDirectionTangentSpace;         // Direction the camera is looking at in tangent space.
+varying vec2 v_texCoord;                             // Texture Coordinate (u,v)
+varying vec3 v_lightDirectionTangentSpace;           // Direction of the light in tangent space.
+varying vec3 v_cameraDirectionTangentSpace;          // Direction the camera is looking at in tangent space.
 
 void main()
 {

+ 3 - 3
gameplay-resources/res/shaders/textured.fsh

@@ -1,11 +1,11 @@
 precision highp float;
 
 // Uniforms
-uniform sampler2D u_diffuseTexture;         // Diffuse texture
-uniform vec4 u_diffuseColor;                // Diffuse color/tint
+uniform sampler2D u_diffuseTexture;     // Diffuse texture
+uniform vec4 u_diffuseColor;            // Diffuse color/tint
 
 // Inputs
-varying vec2 v_texCoord;                    // Texture coordinate (u, v).
+varying vec2 v_texCoord;                // Texture coordinate (u, v).
 
 void main()
 {

+ 65 - 5
gameplay-resources/res/shaders/textured.vsh

@@ -1,17 +1,77 @@
 // Uniforms
-uniform mat4 u_worldViewProjectionMatrix;    // Matrix to transform a position to clip space.
+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).
+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).
+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[2]) * 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 * a_position;
+    gl_Position = u_worldViewProjectionMatrix * position;
 
     // Pass on texture coordinate to fragment shader.
     v_texCoord = a_texCoord;

BIN
gameplay-tutorials/sample01-longboard.pdf


BIN
gameplay-tutorials/sample02-spaceship.pdf


+ 0 - 7
gameplay/.cproject

@@ -27,7 +27,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.2133604142" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.997142816" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -79,7 +78,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1670164593" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1380846613" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -130,7 +128,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1503059677" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.81809638" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -184,7 +181,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1769677874" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.2007171407" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -236,7 +232,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.847642559" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1038720310" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -288,7 +283,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.513622172" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1961855927" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -341,7 +335,6 @@
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1685994750" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-									<listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1658185881" superClass="com.qnx.qcc.inputType.compiler"/>

+ 6 - 3
gameplay/gameplay.vcxproj

@@ -23,7 +23,6 @@
     <ClCompile Include="src\BoundingBox.cpp" />
     <ClCompile Include="src\BoundingSphere.cpp" />
     <ClCompile Include="src\Camera.cpp" />
-    <ClCompile Include="src\Color.cpp" />
     <ClCompile Include="src\Curve.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\FileSystem.cpp" />
@@ -34,6 +33,7 @@
     <ClCompile Include="src\Joint.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\Material.cpp" />
+    <ClCompile Include="src\Pass.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
     <ClCompile Include="src\Matrix.cpp" />
     <ClCompile Include="src\Mesh.cpp" />
@@ -51,8 +51,10 @@
     <ClCompile Include="src\Ray.cpp" />
     <ClCompile Include="src\Rectangle.cpp" />
     <ClCompile Include="src\Ref.cpp" />
+    <ClCompile Include="src\RenderState.cpp" />
     <ClCompile Include="src\Scene.cpp" />
     <ClCompile Include="src\SpriteBatch.cpp" />
+    <ClCompile Include="src\Technique.cpp" />
     <ClCompile Include="src\Texture.cpp" />
     <ClCompile Include="src\Transform.cpp" />
     <ClCompile Include="src\Vector2.cpp" />
@@ -76,7 +78,6 @@
     <ClInclude Include="src\BoundingBox.h" />
     <ClInclude Include="src\BoundingSphere.h" />
     <ClInclude Include="src\Camera.h" />
-    <ClInclude Include="src\Color.h" />
     <ClInclude Include="src\Curve.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\FileSystem.h" />
@@ -91,6 +92,7 @@
     <ClInclude Include="src\Joint.h" />
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\Material.h" />
+    <ClInclude Include="src\Pass.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />
     <ClInclude Include="src\Mesh.h" />
@@ -107,11 +109,12 @@
     <ClInclude Include="src\Ray.h" />
     <ClInclude Include="src\Rectangle.h" />
     <ClInclude Include="src\Ref.h" />
+    <ClInclude Include="src\RenderState.h" />
     <ClInclude Include="src\Scene.h" />
     <ClInclude Include="src\SpriteBatch.h" />
+    <ClInclude Include="src\Technique.h" />
     <ClInclude Include="src\Texture.h" />
     <ClInclude Include="src\Transform.h" />
-    <ClInclude Include="src\Tree.h" />
     <ClInclude Include="src\Vector2.h" />
     <ClInclude Include="src\Vector3.h" />
     <ClInclude Include="src\Vector4.h" />

+ 24 - 12
gameplay/gameplay.vcxproj.filters

@@ -27,9 +27,6 @@
     <ClCompile Include="src\Camera.cpp">
       <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Color.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
     <ClCompile Include="src\Curve.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -54,9 +51,6 @@
     <ClCompile Include="src\Light.cpp">
       <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Material.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
     <ClCompile Include="src\Matrix.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -156,6 +150,18 @@
     <ClCompile Include="src\Properties.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\Material.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Technique.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Pass.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\RenderState.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -185,9 +191,6 @@
     <ClInclude Include="src\Camera.h">
       <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Color.h">
-      <Filter>src</Filter>
-    </ClInclude>
     <ClInclude Include="src\Curve.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -224,9 +227,6 @@
     <ClInclude Include="src\Light.h">
       <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Material.h">
-      <Filter>src</Filter>
-    </ClInclude>
     <ClInclude Include="src\Matrix.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -320,6 +320,18 @@
     <ClInclude Include="src\Properties.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Material.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Technique.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Pass.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\RenderState.h">
+      <Filter>src</Filter>
+    </ClInclude>
     <ClInclude Include="src\Tree.h">
       <Filter>src</Filter>
     </ClInclude>

+ 74 - 84
gameplay/src/Animation.cpp

@@ -21,17 +21,17 @@
 namespace gameplay
 {
 
-Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, float* keyTimes, float* keyValues, unsigned int type)
+Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, unsigned int type)
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0)
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
     createDefaultClip();
 }
 
-Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, float* keyTimes, float* keyValues, float* keyTangentIn, float* keyTangentOut, unsigned int type)
+Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, unsigned int type)
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0)
 {
-    createChannel(target, propertyId, keyCount, keyTimes, keyValues, keyTangentIn, keyTangentOut, type);
+    createChannel(target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
     createDefaultClip();
 }
 
@@ -93,29 +93,23 @@ void Animation::createClips(const char* animationFile)
     Properties* pAnim = Properties::create(animationFile);
     assert(pAnim);
 
-    const vector<Properties*>* vAnim = pAnim->getProperties();
-    
-    Properties* animation = vAnim->front();
+    Properties* animation = pAnim->getNextNamespace();
     int frameCount = animation->getInt("frameCount");
 
-    const std::vector<Properties*>* clips = animation->getProperties();
-    vector<Properties*>::const_iterator itr;
-
-    for (itr = clips->begin(); itr < clips->end(); itr++)
+    const Properties* pClip = animation->getNextNamespace();
+    while (pClip != NULL)
     {
-        Properties* pClip = *itr;
-
         int begin = pClip->getInt("begin");
         int end = pClip->getInt("end");
 
-        AnimationClip* clip = createClip(pClip->getID(), ((float) begin / frameCount) * _duration, ((float) end / frameCount) * _duration);
+        AnimationClip* clip = createClip(pClip->getId(), ((float) begin / frameCount) * _duration, ((float) end / frameCount) * _duration);
 
         const char* repeat = pClip->getString("repeatCount");
         if (repeat)
         {
             if (((std::string)repeat).compare(ANIMATION_INDEFINITE_STR) == 0)
             {
-                clip->setRepeatCount(ANIMATION_REPEAT_COUNT_INDEFINITE);
+                clip->setRepeatCount(AnimationClip::REPEAT_INDEFINITE);
             }
             else
             {
@@ -124,6 +118,16 @@ void Animation::createClips(const char* animationFile)
                 clip->setRepeatCount(value);
             }
         }
+
+        const char* speed = pClip->getString("speed");
+        if (speed)
+        {
+            float value;
+            sscanf(speed, "%f", &value);
+            clip->setSpeed(value);
+        }
+
+        pClip = animation->getNextNamespace();
     }
 
     SAFE_DELETE(pAnim);
@@ -186,11 +190,13 @@ void Animation::stop(const char* id)
         // Find animation clip.. and play.
         AnimationClip* clip = findClip(id);
         if (clip != NULL)
+        {
             clip->stop();
+        }
     }
 }
 
-Animation::Channel* Animation::createChannel(AnimationTarget* target, int propertyId, unsigned int keyCount, float* keyTimes, float* keyValues, unsigned int type)
+Animation::Channel* Animation::createChannel(AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, unsigned int type)
 {
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
@@ -200,26 +206,37 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     {
         switch (propertyId)
         {
-            case TRANSFORM_ANIMATE_ROTATE: 
-            case TRANSFORM_ANIMATE_ROTATE_TRANSLATE:
-                curve->_rotationOffset = ANIMATION_ROTATE_OFFSET;
-                break;
-            case TRANSFORM_ANIMATE_SCALE_ROTATE_TRANSLATE:
-                curve->_rotationOffset = ANIMATION_SRT_OFFSET;
-                break;
+        case Transform::ANIMATE_ROTATE:
+        case Transform::ANIMATE_ROTATE_TRANSLATE:
+            curve->addQuaternionOffset(ANIMATION_ROTATE_OFFSET);
+            break;
+        case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
+            curve->addQuaternionOffset(ANIMATION_SRT_OFFSET);
+            break;
         }
     }
 
-    float lowest = keyTimes[0];
-    float duration = keyTimes[keyCount-1] - lowest;
+    unsigned long lowest = keyTimes[0];
+    unsigned long duration = keyTimes[keyCount-1] - lowest;
 
-    unsigned int pointOffset = 0;
-    for (unsigned int i = 0; i < keyCount; i++)
+    float* normalizedKeyTimes = new float[keyCount];
+
+    normalizedKeyTimes[0] = 0.0f;
+    curve->setPoint(0, normalizedKeyTimes[0], keyValues, (Curve::InterpolationType) type);
+
+    unsigned int pointOffset = propertyComponentCount;
+    unsigned int i = 1;
+    for (; i < keyCount - 1; i++)
     {
-        pointOffset = i * propertyComponentCount;
-        keyTimes[i] = (keyTimes[i] - lowest) / duration;
-        curve->setPoint(i, keyTimes[i], keyValues + pointOffset, (Curve::InterpolationType) type);
+        normalizedKeyTimes[i] = (float) (keyTimes[i] - lowest) / (float) duration;
+        curve->setPoint(i, normalizedKeyTimes[i], (keyValues + pointOffset), (Curve::InterpolationType) type);
+        pointOffset += propertyComponentCount;
     }
+    i = keyCount - 1;
+    normalizedKeyTimes[i] = 1.0f;
+    curve->setPoint(i, normalizedKeyTimes[i], keyValues + pointOffset, (Curve::InterpolationType) type);
+
+    SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(target, propertyId, curve, duration);
 
@@ -228,7 +245,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     return channel;
 }
 
-Animation::Channel* Animation::createChannel(AnimationTarget* target, int propertyId, unsigned int keyCount, float* keyTimes, float* keyValues, float* keyTangentIn, float* keyTangentOut, unsigned int type)
+Animation::Channel* Animation::createChannel(AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, unsigned int type)
 {
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
@@ -238,26 +255,37 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     {
         switch (propertyId)
         {
-            case TRANSFORM_ANIMATE_ROTATE: 
-            case TRANSFORM_ANIMATE_ROTATE_TRANSLATE:
-                curve->_rotationOffset = ANIMATION_ROTATE_OFFSET;
-                break;
-            case TRANSFORM_ANIMATE_SCALE_ROTATE_TRANSLATE:
-                curve->_rotationOffset = ANIMATION_SRT_OFFSET;
-                break;
+        case Transform::ANIMATE_ROTATE:
+        case Transform::ANIMATE_ROTATE_TRANSLATE:
+            curve->addQuaternionOffset(ANIMATION_ROTATE_OFFSET);
+            break;
+        case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
+            curve->addQuaternionOffset(ANIMATION_SRT_OFFSET);
+            break;
         }
     }
+    
+    unsigned long lowest = keyTimes[0];
+    unsigned long duration = keyTimes[keyCount-1] - lowest;
 
-    float lowest = keyTimes[0];
-    float duration = keyTimes[keyCount-1] - lowest;
+    float* normalizedKeyTimes = new float[keyCount];
+    
+    normalizedKeyTimes[0] = 0.0f;
+    curve->setPoint(0, normalizedKeyTimes[0], keyValues, (Curve::InterpolationType) type, keyInValue, keyOutValue);
 
-    unsigned int pointOffset = 0;
-    for (unsigned int i = 0; i < keyCount; i++)
+    unsigned int pointOffset = propertyComponentCount;
+    unsigned int i = 1;
+    for (; i < keyCount - 1; i++)
     {
-        pointOffset = i * propertyComponentCount;
-        keyTimes[i] = (keyTimes[i] - lowest) / duration;
-        curve->setPoint(i, keyTimes[i], keyValues + pointOffset, (Curve::InterpolationType) type, keyTangentIn + pointOffset, keyTangentOut + pointOffset);
+        normalizedKeyTimes[i] = (float) (keyTimes[i] - lowest) / (float) duration;
+        curve->setPoint(i, normalizedKeyTimes[i], (keyValues + pointOffset), (Curve::InterpolationType) type, (keyInValue + pointOffset), (keyOutValue + pointOffset));
+        pointOffset += propertyComponentCount;
     }
+    i = keyCount - 1;
+    normalizedKeyTimes[i] = 1.0f;
+    curve->setPoint(i, normalizedKeyTimes[i], keyValues + pointOffset, (Curve::InterpolationType) type, keyInValue + pointOffset, keyOutValue + pointOffset);
+
+    SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(target, propertyId, curve, duration);
 
@@ -291,49 +319,11 @@ AnimationClip* Animation::findClip(const char* id) const
     for (unsigned int i = 0; i < clipCount; i++)
     {
         if (_clips.at(i)->_id.compare(id) == 0)
+        {
             return _clips.at(i);
+        }
     }
     return NULL;
 }
 
-void Animation::transfer(Animation* animation)
-{
-    // WARNING: This function is leaking some memory, but it should be removed when this hack is removed!
-
-    unsigned int count = animation->_channels.size();
-    for (unsigned int i = 0; i < count; i++)
-    {
-        Channel* channel = animation->_channels[i];
-        addChannel(channel);
-    }
-
-    // AnimationChannel is not reference counted so they should not belong to two Animations.
-    // Delete the AnimationChannel array and all of the clips.
-    /*std::vector<Channel*>::iterator channelIter = animation->_channels.begin();
-    
-    while (channelIter != animation->_channels.end())
-    {
-        Channel* channel = *channelIter;
-        channelIter = animation->_channels.erase(channelIter);
-        SAFE_DELETE(channel);
-    }
-    */
-    /*std::vector<AnimationClip*>::iterator clipIter = animation->_clips.begin();
-    
-    while (clipIter != animation->_clips.end())
-    {
-        AnimationClip* clip = *clipIter;
-        clipIter = animation->_clips.erase(clipIter);
-        SAFE_RELEASE(clip);
-    }*/
-    /*
-    animation->_channelCount = 0;
-    SAFE_DELETE_ARRAY(animation->_channels);
-    for (unsigned int i = 0; i < animation->_channelCount; i++)
-    {
-        SAFE_RELEASE(animation->_clips[i]);
-    }
-    SAFE_DELETE_ARRAY(animation->_clips);*/
-}
-
 }

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio