Parcourir la source

Merge branch 'next' of https://github.com/blackberry-gaming/GamePlay into next-rmadhavan

Conflicts:
	gameplay/gameplay.vcxproj
Ramprasad Madhavan il y a 14 ans
Parent
commit
617e969121
100 fichiers modifiés avec 6377 ajouts et 2064 suppressions
  1. 11 10
      .gitignore
  2. 57 0
      gameplay-encoder/README.md
  3. 22 14
      gameplay-encoder/gameplay-encoder.vcxproj
  4. 192 149
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  5. 5 0
      gameplay-encoder/gameplay-encoder.vcxproj.user
  6. 22 12
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  7. 2 2
      gameplay-encoder/src/Animation.cpp
  8. 126 2
      gameplay-encoder/src/AnimationChannel.cpp
  9. 16 0
      gameplay-encoder/src/AnimationChannel.h
  10. 2 2
      gameplay-encoder/src/Animations.cpp
  11. 1 21
      gameplay-encoder/src/Base.cpp
  12. 3 1
      gameplay-encoder/src/Base.h
  13. 0 54
      gameplay-encoder/src/CameraInstance.cpp
  14. 0 39
      gameplay-encoder/src/CameraInstance.h
  15. 2 2
      gameplay-encoder/src/DAEChannelTarget.cpp
  16. 4 54
      gameplay-encoder/src/DAEOptimizer.cpp
  17. 0 8
      gameplay-encoder/src/DAEOptimizer.h
  18. 211 232
      gameplay-encoder/src/DAESceneEncoder.cpp
  19. 2 4
      gameplay-encoder/src/DAESceneEncoder.h
  20. 60 10
      gameplay-encoder/src/DAEUtil.cpp
  21. 9 1
      gameplay-encoder/src/DAEUtil.h
  22. 97 12
      gameplay-encoder/src/EncoderArguments.cpp
  23. 18 0
      gameplay-encoder/src/EncoderArguments.h
  24. 1336 0
      gameplay-encoder/src/FBXSceneEncoder.cpp
  25. 222 0
      gameplay-encoder/src/FBXSceneEncoder.h
  26. 39 3
      gameplay-encoder/src/FileIO.cpp
  27. 30 8
      gameplay-encoder/src/FileIO.h
  28. 2 2
      gameplay-encoder/src/GPBDecoder.cpp
  29. 18 10
      gameplay-encoder/src/GPBFile.cpp
  30. 1 1
      gameplay-encoder/src/GPBFile.h
  31. 0 55
      gameplay-encoder/src/LightInstance.cpp
  32. 0 42
      gameplay-encoder/src/LightInstance.h
  33. 221 10
      gameplay-encoder/src/Mesh.cpp
  34. 5 0
      gameplay-encoder/src/Mesh.h
  35. 19 13
      gameplay-encoder/src/MeshPart.cpp
  36. 12 3
      gameplay-encoder/src/MeshPart.h
  37. 5 4
      gameplay-encoder/src/MeshSkin.cpp
  38. 14 9
      gameplay-encoder/src/Model.cpp
  39. 2 1
      gameplay-encoder/src/Model.h
  40. 41 15
      gameplay-encoder/src/Node.cpp
  41. 17 6
      gameplay-encoder/src/Node.h
  42. 2 4
      gameplay-encoder/src/Object.h
  43. 3 3
      gameplay-encoder/src/ReferenceTable.cpp
  44. 10 3
      gameplay-encoder/src/Scene.cpp
  45. 5 0
      gameplay-encoder/src/Scene.h
  46. 20 1
      gameplay-encoder/src/StringUtil.cpp
  47. 4 0
      gameplay-encoder/src/StringUtil.h
  48. 5 5
      gameplay-encoder/src/TTFFontEncoder.cpp
  49. 20 16
      gameplay-encoder/src/Transform.h
  50. 15 61
      gameplay-encoder/src/Vector2.cpp
  51. 108 33
      gameplay-encoder/src/Vector2.h
  52. 77 0
      gameplay-encoder/src/Vector2.inl
  53. 31 72
      gameplay-encoder/src/Vector3.cpp
  54. 117 39
      gameplay-encoder/src/Vector3.h
  55. 82 0
      gameplay-encoder/src/Vector3.inl
  56. 33 65
      gameplay-encoder/src/Vector4.cpp
  57. 118 46
      gameplay-encoder/src/Vector4.h
  58. 89 0
      gameplay-encoder/src/Vector4.inl
  59. 28 26
      gameplay-encoder/src/Vertex.cpp
  60. 6 4
      gameplay-encoder/src/Vertex.h
  61. 16 3
      gameplay-encoder/src/main.cpp
  62. 271 0
      gameplay-newproject.bat
  63. 34 0
      gameplay-template/gameplay-template-macos.plist
  64. 171 0
      gameplay-template/gameplay-template.vcxproj
  65. 17 0
      gameplay-template/gameplay-template.vcxproj.filters
  66. 15 0
      gameplay-template/gameplay-template.vcxproj.user
  67. 343 0
      gameplay-template/gameplay-template.xcodeproj/project.pbxproj
  68. BIN
      gameplay-template/icon.png
  69. 183 0
      gameplay-template/res/box.dae
  70. BIN
      gameplay-template/res/box.gpb
  71. 25 0
      gameplay-template/res/box.material
  72. 72 0
      gameplay-template/src/TemplateGame.cpp
  73. 57 0
      gameplay-template/src/TemplateGame.h
  74. 110 0
      gameplay-template/template.bar-descriptor.xml
  75. 600 0
      gameplay-template/template.cproject
  76. 87 0
      gameplay-template/template.project
  77. 18 5
      gameplay/gameplay.vcxproj
  78. 181 519
      gameplay/gameplay.vcxproj.filters
  79. 32 8
      gameplay/gameplay.xcodeproj/project.pbxproj
  80. 2 2
      gameplay/res/shaders/bumped-specular.vsh
  81. 2 2
      gameplay/res/shaders/bumped.vsh
  82. 2 2
      gameplay/res/shaders/colored-specular.vsh
  83. 2 2
      gameplay/res/shaders/colored.vsh
  84. 2 2
      gameplay/res/shaders/diffuse-specular.vsh
  85. 2 2
      gameplay/res/shaders/diffuse.vsh
  86. 1 1
      gameplay/res/shaders/textured.vsh
  87. BIN
      gameplay/res/textures/particle-default.png
  88. 101 112
      gameplay/src/Animation.cpp
  89. 16 5
      gameplay/src/Animation.h
  90. 49 87
      gameplay/src/AnimationClip.cpp
  91. 0 1
      gameplay/src/AnimationClip.h
  92. 160 32
      gameplay/src/AnimationController.cpp
  93. 20 8
      gameplay/src/AnimationController.h
  94. 63 1
      gameplay/src/AnimationTarget.cpp
  95. 10 0
      gameplay/src/AnimationTarget.h
  96. 59 2
      gameplay/src/AudioSource.cpp
  97. 3 3
      gameplay/src/AudioSource.h
  98. 12 55
      gameplay/src/Base.h
  99. 12 12
      gameplay/src/BoundingBox.cpp
  100. 8 9
      gameplay/src/BoundingSphere.cpp

+ 11 - 10
.gitignore

@@ -13,6 +13,7 @@
 /Device-Coverage
 /Device-Profile
 /Device-Release
+/gameplay.xcworkspace/xcuserdata
 /gameplay/Debug
 /gameplay/DebugMem
 /gameplay/Release
@@ -23,8 +24,10 @@
 /gameplay/Device-Coverage
 /gameplay/Device-Profile
 /gameplay/Device-Release
+/gameplay/gameplay.xcodeproj/xcuserdata
 /gameplay-encoder/Debug
 /gameplay-encoder/Release
+/gameplay-encoder/gameplay-encoder.xcodeproj/xcuserdata
 /gameplay-internal
 /gameplay-samples/sample00-mesh/Debug
 /gameplay-samples/sample00-mesh/DebugMem
@@ -36,6 +39,8 @@
 /gameplay-samples/sample00-mesh/Device-Coverage
 /gameplay-samples/sample00-mesh/Device-Profile
 /gameplay-samples/sample00-mesh/Device-Release
+/gameplay-samples/sample00-mesh/res/shaders
+/gameplay-samples/sample00-mesh/sample00-mesh.xcodeproj/xcuserdata
 /gameplay-samples/sample01-longboard/Debug
 /gameplay-samples/sample01-longboard/DebugMem
 /gameplay-samples/sample01-longboard/Release
@@ -46,6 +51,8 @@
 /gameplay-samples/sample01-longboard/Device-Coverage
 /gameplay-samples/sample01-longboard/Device-Profile
 /gameplay-samples/sample01-longboard/Device-Release
+/gameplay-samples/sample01-longboard/res/shaders
+/gameplay-samples/sample01-longboard/sample01-longboard.xcodeproj/xcuserdata
 /gameplay-samples/sample02-spaceship/Debug
 /gameplay-samples/sample02-spaceship/DebugMem
 /gameplay-samples/sample02-spaceship/Release
@@ -56,6 +63,8 @@
 /gameplay-samples/sample02-spaceship/Device-Coverage
 /gameplay-samples/sample02-spaceship/Device-Profile
 /gameplay-samples/sample02-spaceship/Device-Release
+/gameplay-samples/sample02-spaceship/res/shaders
+/gameplay-samples/sample02-spaceship/sample02-spaceship.xcodeproj/xcuserdata
 /gameplay-samples/sample03-character/Debug
 /gameplay-samples/sample03-character/DebugMem
 /gameplay-samples/sample03-character/Release
@@ -66,13 +75,5 @@
 /gameplay-samples/sample03-character/Device-Coverage
 /gameplay-samples/sample03-character/Device-Profile
 /gameplay-samples/sample03-character/Device-Release
-/gameplay-samples/sample04-sandbox/Debug
-/gameplay-samples/sample04-sandbox/DebugMem
-/gameplay-samples/sample04-sandbox/Release
-/gameplay-samples/sample04-sandbox/Simulator
-/gameplay-samples/sample04-sandbox/Simulator-Coverage
-/gameplay-samples/sample04-sandbox/Simulator-Profile
-/gameplay-samples/sample04-sandbox/Device-Debug
-/gameplay-samples/sample04-sandbox/Device-Coverage
-/gameplay-samples/sample04-sandbox/Device-Profile
-/gameplay-samples/sample04-sandbox/Device-Release
+/gameplay-samples/sample03-character/res/shaders
+/gameplay-samples/sample03-character/sample03-character.xcodeproj/xcuserdata

+ 57 - 0
gameplay-encoder/README.md

@@ -0,0 +1,57 @@
+## GamePlay Encoder
+GamePlay Encoder is a command-line tool for encoding/packaging games assets like fonts and 3D scene files
+into a binary package file format for the GamePlay runtime framework. 
+
+## TrueType Font Support
+TrueType Fonts conversion is enabled/built-in by default into gameplay-encoder via freetype 2 library.
+
+## COLLADA Scene Support
+COLLADA is enabled/built-in by default into gameplay-encoder via COLLADA-DOM library.
+Most major 3D DCC tools support the export of COLLADA 1.4.
+We also recommend you download and use OpenCOLADA (http://opencollada.org/)
+for Autodesk Maya and 3DS Max.
+
+## FBX Scene Support
+FBX support can easily be enabled in gameplay-encoder but requires an 
+additional installation of Autodesk FBX SDK. (http://www.autodesk.com/fbx).
+You must then rebuild gameplay-encoder with the follow platform/tooling instructions:
+
+### Building FBX Support on Windows 7 using Visual Studio 2010
+- Download and install the FBX SDK for Window VS2010. (http://www.autodesk.com/fbx)
+- Edit the project properties of "gameplay-encoder"
+- Add Preprocessor Definition "USE_FBX" (C++/Preprocessor)
+- Add the FBX SDK include directory to Additional Include Directories (C++/General)
+  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/include
+- Add the FBX lib directory to the Additional Library Directories (Linker/General)
+  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86
+- Add "fbxsdk-2012.2-mdd.lib" and "wininet.lib" to the Additional Dependencies (Linker/Input)
+  * Example: fbxsdk-2012.2-mdd.lib;wininet.lib
+- Add a post build event to copy the DLL (Build Events/Post-Build Event)
+  * Example: copy /Y "C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86/fbxsdk-2012.2d.dll" "$(TargetDir)"
+- Build gameplay-encoder
+
+### Building FBX Support on Mac OS X using XCode 4
+- Download and install the FBX SDK for Mac OS X (http://www.autodesk.com/fbx)
+- Edit the project properties of target "gameplay-encoder".
+- Add Preprocessor Macro "USE_FBX" to both Debug/Release sections. (Build Settings)
+- Add the FBX include directory to Header Search Paths: (Build Settings)
+  * Example: /Applications/Autodesk/FBXSDK20122/include
+- Add the FBX library and dependency Library/Frameworks: (Build Phases -> Link Binary with Libraries)
+  * Example: /Applications/Autodesk/FBXSDK20122/lib/gcc4/ub/libfbxsdk-2012.2-static.a  (Add Other)
+  * Example: libiconv.dylib, Cocoa.framework, SystemConfiguration.framework
+- Build gameplay-encoder
+
+## Binary Format
+The GamePlay binary package format is well defined in the gameplay-encoder/gameplay-binary.txt file.
+
+## Binary Loading
+GamePlay binary package files can easily be loaded using the gameplay/Package.h which is part
+of the GamePlay runtime framework.
+
+## 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.

+ 22 - 14
gameplay-encoder/gameplay-encoder.vcxproj

@@ -17,13 +17,13 @@
     <ClCompile Include="src\Base.cpp" />
     <ClCompile Include="src\BoundingVolume.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\FBXSceneEncoder.cpp" />
     <ClCompile Include="src\FileIO.cpp" />
     <ClCompile Include="src\Font.cpp" />
     <ClCompile Include="src\GPBFile.cpp" />
@@ -31,7 +31,6 @@
     <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" />
     <ClCompile Include="src\Material.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
@@ -62,13 +61,13 @@
     <ClInclude Include="src\Base.h" />
     <ClInclude Include="src\BoundingVolume.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\FBXSceneEncoder.h" />
     <ClInclude Include="src\FileIO.h" />
     <ClInclude Include="src\Font.h" />
     <ClInclude Include="src\GPBFile.h" />
@@ -76,7 +75,6 @@
     <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" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />
@@ -99,6 +97,11 @@
     <ClInclude Include="src\Vertex.h" />
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="src\Vector2.inl" />
+    <None Include="src\Vector3.inl" />
+    <None Include="src\Vector4.inl" />
+  </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{9D69B743-4872-4DD1-8E30-0087C64298D7}</ProjectGuid>
     <Keyword>Win32Proj</Keyword>
@@ -142,20 +145,22 @@
       </PrecompiledHeader>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;USE_FBX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4;../external-deps/libpng/include;../external-deps/zlib/include;C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/include</AdditionalIncludeDirectories>
       <DisableLanguageExtensions>
       </DisableLanguageExtensions>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalLibraryDirectories>;../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32</AdditionalLibraryDirectories>
-      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32;C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86</AdditionalLibraryDirectories>
+      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;fbxsdk-2012.2-mdd.lib;wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
     </Link>
     <PostBuildEvent>
-      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\win32\*.dll" "$(TargetDir)"</Command>
+      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\win32\*.dll" "$(TargetDir)"
+copy /Y "$(ProjectDir)..\external-deps\zlib\lib\win32\*.dll" "$(TargetDir)"
+</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -167,19 +172,22 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NO_BOOST;NO_ZAE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>../external-deps/freetype2/include;../external-deps/collada-dom/include;../external-deps/collada-dom/include/1.4;../external-deps/libpng/include;../external-deps/zlib/include</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>;../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32</AdditionalLibraryDirectories>
-      <IgnoreSpecificDefaultLibraries>MSVCRT</IgnoreSpecificDefaultLibraries>
+      <AdditionalDependencies>freetype245.lib;libcollada14dom22-d.lib;libpng14.lib;zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>../external-deps/freetype2/lib/win32;../external-deps/collada-dom/lib/win32;../external-deps/libpng/lib/win32;../external-deps/zlib/lib/win32</AdditionalLibraryDirectories>
+      <IgnoreSpecificDefaultLibraries>
+      </IgnoreSpecificDefaultLibraries>
     </Link>
     <PostBuildEvent>
-      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\win32\*.dll" "$(TargetDir)"</Command>
+      <Command>copy /Y "$(ProjectDir)..\external-deps\collada-dom\lib\win32\*.dll" "$(TargetDir)"
+copy /Y "$(ProjectDir)..\external-deps\zlib\lib\win32\*.dll" "$(TargetDir)"
+</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 192 - 149
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -1,229 +1,272 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="src\DAESceneEncoder.cpp" />
-    <ClCompile Include="src\main.cpp" />
-    <ClCompile Include="src\ReferenceTable.cpp" />
-    <ClCompile Include="src\TTFFontEncoder.cpp" />
+    <ClCompile Include="src\Animation.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AnimationChannel.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Animations.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Base.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\BoundingVolume.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
     <ClCompile Include="src\Camera.cpp">
-      <Filter>Objects\Camera</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\gameplay\src\Curve.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DAEChannelTarget.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\CameraInstance.cpp">
-      <Filter>Objects\Camera</Filter>
+    <ClCompile Include="src\DAEOptimizer.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DAESceneEncoder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DAEUtil.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Effect.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\EncoderArguments.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FBXSceneEncoder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FileIO.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Font.cpp">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Glyph.cpp">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\GPBDecoder.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\GPBFile.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Light.cpp">
-      <Filter>Objects\Light</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\LightInstance.cpp">
-      <Filter>Objects\Light</Filter>
+    <ClCompile Include="src\main.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Material.cpp">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\MaterialParameter.cpp">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Matrix.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Mesh.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\MeshPart.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\MeshSkin.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Node.cpp">
-      <Filter>Objects\Node</Filter>
+    <ClCompile Include="src\Model.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Reference.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\Node.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Object.cpp">
-      <Filter>Objects</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Model.cpp">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Scene.cpp">
-      <Filter>Objects</Filter>
+    <ClCompile Include="src\Quaternion.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\GPBDecoder.cpp" />
-    <ClCompile Include="src\Animation.cpp">
-      <Filter>Objects\Animation</Filter>
+    <ClCompile Include="src\Reference.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\AnimationChannel.cpp">
-      <Filter>Objects\Animation</Filter>
+    <ClCompile Include="src\ReferenceTable.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\GPBFile.cpp" />
-    <ClCompile Include="src\DAEChannelTarget.cpp" />
-    <ClCompile Include="src\FileIO.cpp" />
-    <ClCompile Include="src\StringUtil.cpp" />
-    <ClCompile Include="src\Effect.cpp">
-      <Filter>Objects\Material</Filter>
+    <ClCompile Include="src\Scene.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Vertex.cpp" />
-    <ClCompile Include="src\VertexElement.cpp" />
-    <ClCompile Include="src\Quaternion.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\StringUtil.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Vector4.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Transform.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Vector3.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\TTFFontEncoder.cpp">
+      <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="src\Vector2.cpp">
-      <Filter>Math</Filter>
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Transform.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vector3.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Matrix.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\Vector4.cpp">
+      <Filter>src</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 Include="src\Vertex.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="..\gameplay\src\Curve.cpp" />
-    <ClCompile Include="src\BoundingVolume.cpp">
-      <Filter>Math</Filter>
+    <ClCompile Include="src\VertexElement.cpp">
+      <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Base.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="src\DAESceneEncoder.h" />
-    <ClInclude Include="src\ReferenceTable.h" />
-    <ClInclude Include="src\TTFFontEncoder.h" />
-    <ClInclude Include="src\CameraInstance.h">
-      <Filter>Objects\Camera</Filter>
+    <ClInclude Include="src\VertexElement.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Animation.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AnimationChannel.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Animations.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Base.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\BoundingVolume.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Camera.h">
-      <Filter>Objects\Camera</Filter>
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\gameplay\src\Curve.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAEChannelTarget.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAEOptimizer.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAESceneEncoder.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DAEUtil.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Effect.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\EncoderArguments.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FBXSceneEncoder.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FileIO.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Font.h">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Glyph.h">
-      <Filter>Objects\Font</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\LightInstance.h">
-      <Filter>Objects\Light</Filter>
+    <ClInclude Include="src\GPBDecoder.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Light.h">
-      <Filter>Objects\Light</Filter>
+    <ClInclude Include="src\GPBFile.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\MaterialParameter.h">
-      <Filter>Objects\Material</Filter>
+    <ClInclude Include="src\Light.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Material.h">
-      <Filter>Objects\Material</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\MeshSkin.h">
-      <Filter>Objects\Mesh</Filter>
+    <ClInclude Include="src\MaterialParameter.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Matrix.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Mesh.h">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\MeshPart.h">
-      <Filter>Objects\Mesh</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Node.h">
-      <Filter>Objects\Node</Filter>
+    <ClInclude Include="src\MeshSkin.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Reference.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\Model.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Object.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\Node.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Model.h">
-      <Filter>Objects\Mesh</Filter>
+    <ClInclude Include="src\Object.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Scene.h">
-      <Filter>Objects</Filter>
+    <ClInclude Include="src\Quaternion.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\GPBDecoder.h" />
-    <ClInclude Include="src\AnimationChannel.h">
-      <Filter>Objects\Animation</Filter>
+    <ClInclude Include="src\Reference.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Animation.h">
-      <Filter>Objects\Animation</Filter>
+    <ClInclude Include="src\ReferenceTable.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\GPBFile.h" />
-    <ClInclude Include="src\DAEChannelTarget.h" />
-    <ClInclude Include="src\FileIO.h" />
-    <ClInclude Include="src\StringUtil.h" />
-    <ClInclude Include="src\Effect.h">
-      <Filter>Objects\Material</Filter>
+    <ClInclude Include="src\Scene.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Vertex.h" />
-    <ClInclude Include="src\VertexElement.h" />
-    <ClInclude Include="src\Quaternion.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\StringUtil.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Vector4.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Transform.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Vector3.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\TTFFontEncoder.h">
+      <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="src\Vector2.h">
-      <Filter>Math</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Transform.h">
-      <Filter>Math</Filter>
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Matrix.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Vector3.h">
+      <Filter>src</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 Include="src\Vector4.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="..\gameplay\src\Curve.h" />
-    <ClInclude Include="src\BoundingVolume.h">
-      <Filter>Math</Filter>
+    <ClInclude Include="src\Vertex.h">
+      <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Base.h" />
   </ItemGroup>
   <ItemGroup>
-    <Filter Include="Objects">
-      <UniqueIdentifier>{3be0a9f1-9de7-42e9-b264-89400ccf3236}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Camera">
-      <UniqueIdentifier>{d2b8cf21-20ee-4838-8bb6-5adab779dc10}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Font">
-      <UniqueIdentifier>{1c4dbad5-5351-4fd0-b498-745f7afcf866}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Light">
-      <UniqueIdentifier>{c41a1929-d921-4d2a-9713-12831c0e3ce1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Material">
-      <UniqueIdentifier>{1d8618d6-dbed-40c0-bb22-43350b195ee1}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Mesh">
-      <UniqueIdentifier>{80e09f25-6954-4415-b712-62a4a64174c3}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Node">
-      <UniqueIdentifier>{a74ab546-c248-4bf8-b212-b590514e23e0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Objects\Animation">
-      <UniqueIdentifier>{dc9b3d2e-25ae-4613-83ce-844abf4f9bf5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="Math">
-      <UniqueIdentifier>{4368ed2b-7fce-423a-a9cb-76a0fdc42858}</UniqueIdentifier>
+    <None Include="src\Vector2.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector3.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector4.inl">
+      <Filter>src</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{6393521c-00fb-48f6-b480-87f8d978a74f}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>

+ 5 - 0
gameplay-encoder/gameplay-encoder.vcxproj.user

@@ -4,5 +4,10 @@
     <LocalDebuggerCommandArguments>
     </LocalDebuggerCommandArguments>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+    <LocalDebuggerEnvironment>PATH=%PATH%;../external-deps/zlib/lib/win32;../external-deps/libpng/lib/win32</LocalDebuggerEnvironment>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LocalDebuggerEnvironment>PATH=%PATH%;../external-deps/zlib/lib/win32;../external-deps/libpng/lib/win32</LocalDebuggerEnvironment>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
   </PropertyGroup>
 </Project>

+ 22 - 12
gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj

@@ -8,6 +8,7 @@
 
 /* Begin PBXBuildFile section */
 		42475D7C14720ECE00610A6A /* libdom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42475D7B14720ECE00610A6A /* libdom.a */; };
+		42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */; };
 		4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4283905714896E6C00E2B2F5 /* BoundingVolume.cpp */; };
 		4283906314896F1600E2B2F5 /* Curve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4283906114896F1600E2B2F5 /* Curve.cpp */; };
 		42C8EE0A14724CD700E43619 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB714724CD700E43619 /* Animation.cpp */; };
@@ -15,7 +16,6 @@
 		42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBB14724CD700E43619 /* Animations.cpp */; };
 		42C8EE0D14724CD700E43619 /* Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBD14724CD700E43619 /* Base.cpp */; };
 		42C8EE0E14724CD700E43619 /* Camera.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBF14724CD700E43619 /* Camera.cpp */; };
-		42C8EE0F14724CD700E43619 /* CameraInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC114724CD700E43619 /* CameraInstance.cpp */; };
 		42C8EE1014724CD700E43619 /* DAEChannelTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */; };
 		42C8EE1114724CD700E43619 /* DAEOptimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */; };
 		42C8EE1214724CD700E43619 /* DAESceneEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDC714724CD700E43619 /* DAESceneEncoder.cpp */; };
@@ -28,7 +28,6 @@
 		42C8EE1914724CD700E43619 /* GPBDecoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD514724CD700E43619 /* GPBDecoder.cpp */; };
 		42C8EE1A14724CD700E43619 /* GPBFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD714724CD700E43619 /* GPBFile.cpp */; };
 		42C8EE1B14724CD700E43619 /* Light.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDD914724CD700E43619 /* Light.cpp */; };
-		42C8EE1C14724CD700E43619 /* LightInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDDB14724CD700E43619 /* LightInstance.cpp */; };
 		42C8EE1D14724CD700E43619 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDDD14724CD700E43619 /* main.cpp */; };
 		42C8EE1E14724CD700E43619 /* Material.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDDE14724CD700E43619 /* Material.cpp */; };
 		42C8EE1F14724CD700E43619 /* MaterialParameter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDE014724CD700E43619 /* MaterialParameter.cpp */; };
@@ -75,6 +74,11 @@
 /* Begin PBXFileReference section */
 		42475CE6147208A000610A6A /* gameplay-encoder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gameplay-encoder"; sourceTree = BUILT_PRODUCTS_DIR; };
 		42475D7B14720ECE00610A6A /* libdom.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdom.a; path = "../external-deps/collada-dom/lib/macos/libdom.a"; sourceTree = "<group>"; };
+		4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FBXSceneEncoder.cpp; path = src/FBXSceneEncoder.cpp; sourceTree = SOURCE_ROOT; };
+		4278341F148D6F7500A6E27F /* FBXSceneEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FBXSceneEncoder.h; path = src/FBXSceneEncoder.h; sourceTree = SOURCE_ROOT; };
+		42783420148D6F7500A6E27F /* Vector2.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Vector2.inl; path = src/Vector2.inl; sourceTree = SOURCE_ROOT; };
+		42783421148D6F7500A6E27F /* Vector3.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Vector3.inl; path = src/Vector3.inl; sourceTree = SOURCE_ROOT; };
+		42783422148D6F7500A6E27F /* Vector4.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Vector4.inl; path = src/Vector4.inl; sourceTree = SOURCE_ROOT; };
 		4283905714896E6C00E2B2F5 /* BoundingVolume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BoundingVolume.cpp; path = src/BoundingVolume.cpp; sourceTree = SOURCE_ROOT; };
 		4283905814896E6C00E2B2F5 /* BoundingVolume.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BoundingVolume.h; path = src/BoundingVolume.h; sourceTree = SOURCE_ROOT; };
 		4283906114896F1600E2B2F5 /* Curve.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Curve.cpp; path = ../gameplay/src/Curve.cpp; sourceTree = "<group>"; };
@@ -89,8 +93,6 @@
 		42C8EDBE14724CD700E43619 /* Base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Base.h; path = src/Base.h; sourceTree = SOURCE_ROOT; };
 		42C8EDBF14724CD700E43619 /* Camera.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Camera.cpp; path = src/Camera.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EDC014724CD700E43619 /* Camera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Camera.h; path = src/Camera.h; sourceTree = SOURCE_ROOT; };
-		42C8EDC114724CD700E43619 /* CameraInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CameraInstance.cpp; path = src/CameraInstance.cpp; sourceTree = SOURCE_ROOT; };
-		42C8EDC214724CD700E43619 /* CameraInstance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CameraInstance.h; path = src/CameraInstance.h; sourceTree = SOURCE_ROOT; };
 		42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DAEChannelTarget.cpp; path = src/DAEChannelTarget.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EDC414724CD700E43619 /* DAEChannelTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAEChannelTarget.h; path = src/DAEChannelTarget.h; sourceTree = SOURCE_ROOT; };
 		42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DAEOptimizer.cpp; path = src/DAEOptimizer.cpp; sourceTree = SOURCE_ROOT; };
@@ -115,8 +117,6 @@
 		42C8EDD814724CD700E43619 /* GPBFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPBFile.h; path = src/GPBFile.h; sourceTree = SOURCE_ROOT; };
 		42C8EDD914724CD700E43619 /* Light.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Light.cpp; path = src/Light.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EDDA14724CD700E43619 /* Light.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Light.h; path = src/Light.h; sourceTree = SOURCE_ROOT; };
-		42C8EDDB14724CD700E43619 /* LightInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LightInstance.cpp; path = src/LightInstance.cpp; sourceTree = SOURCE_ROOT; };
-		42C8EDDC14724CD700E43619 /* LightInstance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LightInstance.h; path = src/LightInstance.h; sourceTree = SOURCE_ROOT; };
 		42C8EDDD14724CD700E43619 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = src/main.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EDDE14724CD700E43619 /* Material.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Material.cpp; path = src/Material.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EDDF14724CD700E43619 /* Material.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Material.h; path = src/Material.h; sourceTree = SOURCE_ROOT; };
@@ -221,8 +221,6 @@
 				4283905814896E6C00E2B2F5 /* BoundingVolume.h */,
 				42C8EDBF14724CD700E43619 /* Camera.cpp */,
 				42C8EDC014724CD700E43619 /* Camera.h */,
-				42C8EDC114724CD700E43619 /* CameraInstance.cpp */,
-				42C8EDC214724CD700E43619 /* CameraInstance.h */,
 				42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */,
 				42C8EDC414724CD700E43619 /* DAEChannelTarget.h */,
 				42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */,
@@ -235,6 +233,8 @@
 				42C8EDCC14724CD700E43619 /* Effect.h */,
 				42C8EDCD14724CD700E43619 /* EncoderArguments.cpp */,
 				42C8EDCE14724CD700E43619 /* EncoderArguments.h */,
+				4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */,
+				4278341F148D6F7500A6E27F /* FBXSceneEncoder.h */,
 				42C8EDCF14724CD700E43619 /* FileIO.cpp */,
 				42C8EDD014724CD700E43619 /* FileIO.h */,
 				42C8EDD114724CD700E43619 /* Font.cpp */,
@@ -247,8 +247,6 @@
 				42C8EDD814724CD700E43619 /* GPBFile.h */,
 				42C8EDD914724CD700E43619 /* Light.cpp */,
 				42C8EDDA14724CD700E43619 /* Light.h */,
-				42C8EDDB14724CD700E43619 /* LightInstance.cpp */,
-				42C8EDDC14724CD700E43619 /* LightInstance.h */,
 				42C8EDDD14724CD700E43619 /* main.cpp */,
 				42C8EDDE14724CD700E43619 /* Material.cpp */,
 				42C8EDDF14724CD700E43619 /* Material.h */,
@@ -286,10 +284,13 @@
 				42C8EDFF14724CD700E43619 /* TTFFontEncoder.h */,
 				42C8EE0014724CD700E43619 /* Vector2.cpp */,
 				42C8EE0114724CD700E43619 /* Vector2.h */,
+				42783420148D6F7500A6E27F /* Vector2.inl */,
 				42C8EE0214724CD700E43619 /* Vector3.cpp */,
 				42C8EE0314724CD700E43619 /* Vector3.h */,
+				42783421148D6F7500A6E27F /* Vector3.inl */,
 				42C8EE0414724CD700E43619 /* Vector4.cpp */,
 				42C8EE0514724CD700E43619 /* Vector4.h */,
+				42783422148D6F7500A6E27F /* Vector4.inl */,
 				42C8EE0614724CD700E43619 /* Vertex.cpp */,
 				42C8EE0714724CD700E43619 /* Vertex.h */,
 				42C8EE0814724CD700E43619 /* VertexElement.cpp */,
@@ -377,7 +378,6 @@
 				42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */,
 				42C8EE0D14724CD700E43619 /* Base.cpp in Sources */,
 				42C8EE0E14724CD700E43619 /* Camera.cpp in Sources */,
-				42C8EE0F14724CD700E43619 /* CameraInstance.cpp in Sources */,
 				42C8EE1014724CD700E43619 /* DAEChannelTarget.cpp in Sources */,
 				42C8EE1114724CD700E43619 /* DAEOptimizer.cpp in Sources */,
 				42C8EE1214724CD700E43619 /* DAESceneEncoder.cpp in Sources */,
@@ -390,7 +390,6 @@
 				42C8EE1914724CD700E43619 /* GPBDecoder.cpp in Sources */,
 				42C8EE1A14724CD700E43619 /* GPBFile.cpp in Sources */,
 				42C8EE1B14724CD700E43619 /* Light.cpp in Sources */,
-				42C8EE1C14724CD700E43619 /* LightInstance.cpp in Sources */,
 				42C8EE1D14724CD700E43619 /* main.cpp in Sources */,
 				42C8EE1E14724CD700E43619 /* Material.cpp in Sources */,
 				42C8EE1F14724CD700E43619 /* MaterialParameter.cpp in Sources */,
@@ -416,6 +415,7 @@
 				42C8EE3314724CD700E43619 /* VertexElement.cpp in Sources */,
 				4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */,
 				4283906314896F1600E2B2F5 /* Curve.cpp in Sources */,
+				42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -455,6 +455,7 @@
 				OTHER_TEST_FLAGS = "";
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4";
 				WARNING_CFLAGS = "";
 			};
 			name = Debug;
@@ -488,6 +489,7 @@
 				OTHER_TEST_FLAGS = "";
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
 				SDKROOT = macosx;
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4";
 				WARNING_CFLAGS = "";
 			};
 			name = Release;
@@ -501,7 +503,9 @@
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
 				GCC_ENABLE_CPP_EXCEPTIONS = NO;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
 					"../external-deps/freetype2/include",
 					"../external-deps/collada-dom/include",
@@ -513,9 +517,11 @@
 					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macos\"",
 					"\"$(SRCROOT)/../external-deps/pcre/lib/macos\"",
 					"\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
+					"\"$(SYSTEM_APPS_DIR)/Autodesk/FBXSDK20122/lib/gcc4/ub\"",
 				);
 				MACH_O_TYPE = mh_execute;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype2/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 /Applications/Autodesk/FBXSDK20122/include";
 			};
 			name = Debug;
 		};
@@ -528,7 +534,9 @@
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
 				GCC_ENABLE_CPP_EXCEPTIONS = NO;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
 					"../external-deps/freetype2/include",
 					"../external-deps/collada-dom/include",
@@ -540,9 +548,11 @@
 					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macos\"",
 					"\"$(SRCROOT)/../external-deps/pcre/lib/macos\"",
 					"\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
+					"\"$(SYSTEM_APPS_DIR)/Autodesk/FBXSDK20122/lib/gcc4/ub\"",
 				);
 				MACH_O_TYPE = mh_execute;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype2/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 /Applications/Autodesk/FBXSDK20122/include";
 			};
 			name = Release;
 		};

+ 2 - 2
gameplay-encoder/src/Animation.cpp

@@ -27,7 +27,7 @@ void Animation::writeBinary(FILE* file)
     // 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++)
+    for (std::vector<AnimationChannel*>::iterator i = _channels.begin(); i != _channels.end(); ++i)
     {
         (*i)->writeBinary(file);
     }
@@ -38,7 +38,7 @@ void Animation::writeText(FILE* file)
     fprintElementStart(file);
     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);
         }

+ 126 - 2
gameplay-encoder/src/AnimationChannel.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "AnimationChannel.h"
+#include "Transform.h"
 
 namespace gameplay
 {
@@ -28,7 +29,7 @@ void AnimationChannel::writeBinary(FILE* file)
     write(_targetId, file);
     write(_targetAttrib, file);
     write(_keytimes.size(), file);
-    for (std::vector<float>::const_iterator i = _keytimes.begin(); i != _keytimes.end(); i++)
+    for (std::vector<float>::const_iterator i = _keytimes.begin(); i != _keytimes.end(); ++i)
     {
         write((unsigned long)*i, file);
     }
@@ -36,7 +37,6 @@ void AnimationChannel::writeBinary(FILE* file)
     write(_tangentsIn, file);
     write(_tangentsOut, file);
     write(_interpolations, file);
-
 }
 
 void AnimationChannel::writeText(FILE* file)
@@ -52,6 +52,12 @@ void AnimationChannel::writeText(FILE* file)
     fprintElementEnd(file);
 }
 
+void AnimationChannel::setInterpolation(unsigned int interpolation)
+{
+    _interpolations.clear();
+    _interpolations.push_back(interpolation);
+}
+
 const std::string& AnimationChannel::getTargetId() const
 {
     return _targetId;
@@ -122,6 +128,103 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values
     _interpolations = values;
 }
 
+void AnimationChannel::removeDuplicates()
+{
+    if (_targetAttrib == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+    {
+        size_t prevIndex = 0;
+
+        std::vector<float>::iterator prevStart = _keyValues.begin();
+        std::vector<float>::iterator prevEnd   = _keyValues.begin() + 9;
+        
+        size_t i = 1;
+        for (i = 1; i < _keytimes.size(); ++i)
+        {
+            std::vector<float>::iterator start = _keyValues.begin() + i * 10;
+            std::vector<float>::iterator end = _keyValues.begin() + (i * 10 + 9);
+
+            if (!equal(prevStart, prevEnd, start))
+            {
+                if (i - prevIndex > 2)
+                {
+                    deleteRange(prevIndex+1, i);
+                    i = prevIndex;
+                    prevStart = _keyValues.begin() + i * 10;
+                    prevEnd = _keyValues.begin() + (i * 10 + 9);
+                }
+                else
+                {
+                    prevStart = start;
+                    prevEnd = end;
+                    prevIndex = i;
+                }
+            }
+        }
+        if (i - 1 - prevIndex >= 2)
+        {
+            deleteRange(prevIndex+1, i);
+        }
+    }
+}
+
+void AnimationChannel::convertToQuaternion()
+{
+    if (_targetAttrib == Transform::ANIMATE_ROTATE_X ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Y ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Z)
+    {
+        std::vector<float> newKeyValues;
+        newKeyValues.resize(_keyValues.size() * 4);
+        const size_t count = _keyValues.size();
+
+        float x = _targetAttrib == Transform::ANIMATE_ROTATE_X ? 1.0f : 0.0f;
+        float y = _targetAttrib == Transform::ANIMATE_ROTATE_Y ? 1.0f : 0.0f;
+        float z = _targetAttrib == Transform::ANIMATE_ROTATE_Z ? 1.0f : 0.0f;
+        for (size_t i = 0; i < count; ++i)
+        {
+            size_t j = i << 2;
+            newKeyValues[j] = x;
+            newKeyValues[j+1] = y;
+            newKeyValues[j+2] = z;
+            newKeyValues[j+3] = _keyValues[i];
+        }
+        setKeyValues(newKeyValues);
+        setTargetAttribute(Transform::ANIMATE_ROTATE);
+    }
+}
+
+void AnimationChannel::convertToTransform()
+{
+    if (_targetAttrib == Transform::ANIMATE_ROTATE_X ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Y ||
+        _targetAttrib == Transform::ANIMATE_ROTATE_Z)
+    {
+        std::vector<float> newKeyValues;
+        newKeyValues.resize(_keyValues.size() * 10);
+        const size_t count = _keyValues.size();
+
+        float x = _targetAttrib == Transform::ANIMATE_ROTATE_X ? 1.0f : 0.0f;
+        float y = _targetAttrib == Transform::ANIMATE_ROTATE_Y ? 1.0f : 0.0f;
+        float z = _targetAttrib == Transform::ANIMATE_ROTATE_Z ? 1.0f : 0.0f;
+        for (size_t i = 0; i < count; ++i)
+        {
+            size_t j = i << 2;
+            newKeyValues[j+0] = 1.0f;
+            newKeyValues[j+1] = 1.0f;
+            newKeyValues[j+2] = 1.0f;
+            newKeyValues[j+3] = x;
+            newKeyValues[j+4] = y;
+            newKeyValues[j+5] = z;
+            newKeyValues[j+6] = _keyValues[i];
+            newKeyValues[j+7] = 0.0f;
+            newKeyValues[j+8] = 0.0f;
+            newKeyValues[j+9] = 0.0f;
+        }
+        setKeyValues(newKeyValues);
+        setTargetAttribute(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE);
+    }
+}
+
 unsigned int AnimationChannel::getInterpolationType(const char* str)
 {
     unsigned int value = 0;
@@ -167,4 +270,25 @@ unsigned int AnimationChannel::getInterpolationType(const char* str)
     return value;
 }
 
+void AnimationChannel::deleteRange(size_t begin, size_t end)
+{
+    // delete range
+    printf("delete %lu to %lu\n", begin, end - 1);
+
+    std::vector<float>::iterator a = _keyValues.begin() + begin * 10;
+    std::vector<float>::iterator b = _keyValues.begin() + end * 10;
+    _keyValues.erase(a, b);
+
+    a = _keytimes.begin() + begin;
+    b = _keytimes.begin() + end;
+    _keytimes.erase(a, b);
+
+    if (_interpolations.size() > 1)
+    {
+        std::vector<unsigned int>::iterator a = _interpolations.begin() + begin;
+        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * 10;
+        _interpolations.erase(a, b);
+    }
+}
+
 }

+ 16 - 0
gameplay-encoder/src/AnimationChannel.h

@@ -36,6 +36,14 @@ public:
     virtual void writeText(FILE* file);
 
     const std::string& getTargetId() const;
+
+    /**
+     * Sets the interpolation type of the entire animation channel.
+     * 
+     * @param interpolation The interpolation type from InterpolationTypes enum.
+     */
+    void setInterpolation(unsigned int interpolation);
+
     void setTargetId(const std::string& str);
     void setTargetAttribute(unsigned int attrib);
 
@@ -52,6 +60,11 @@ public:
     const std::vector<float>& getTangentsOut() const;
     const std::vector<unsigned int>& getInterpolationTypes() const;
 
+    void removeDuplicates();
+
+    void convertToQuaternion();
+    void convertToTransform();
+
     /**
      * Returns the interpolation type value for the given string or zero if not valid.
      * Example: "LINEAR" returns AnimationChannel::LINEAR
@@ -62,6 +75,9 @@ public:
      */
     static unsigned int getInterpolationType(const char* str);
 
+private:
+
+    void deleteRange(size_t begin, size_t end);
 private:
 
     std::string _targetId;

+ 2 - 2
gameplay-encoder/src/Animations.cpp

@@ -28,7 +28,7 @@ void Animations::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
     write(_animations.size(), file);
-    for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); i++)
+    for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); ++i)
     {
         (*i)->writeBinary(file);
     }
@@ -39,7 +39,7 @@ void Animations::writeText(FILE* file)
     fprintElementStart(file);
     if (_animations.size() > 0 )
     {
-        for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); i++)
+        for (std::vector<Animation*>::iterator i = _animations.begin(); i != _animations.end(); ++i)
         {
             (*i)->writeText(file);
         }

+ 1 - 21
gameplay-encoder/src/Base.cpp

@@ -5,30 +5,10 @@ namespace gameplay
 
 void fillArray(float values[], float value, size_t length)
 {
-    for (size_t i = 0; i < length; i++)
+    for (size_t i = 0; i < length; ++i)
     {
         values[i] = value;
     }
 }
 
-void setIdentityMatrix(float values[])
-{
-    values[0] = 1.0f;
-    values[1] = 0.0f;
-    values[2] = 0.0f;
-    values[3] = 0.0f;
-    values[4] = 0.0f;
-    values[5] = 1.0f;
-    values[6] = 0.0f;
-    values[7] = 0.0f;
-    values[8] = 0.0f;
-    values[9] = 0.0f;
-    values[10] = 1.0f;
-    values[11] = 0.0f;
-    values[12] = 0.0f;
-    values[13] = 0.0f;
-    values[14] = 0.0f;
-    values[15] = 1.0f;
-}
-
 }

+ 3 - 1
gameplay-encoder/src/Base.h

@@ -19,6 +19,9 @@
 #include <algorithm>
 #include <sys/stat.h>
 
+// PNG
+#include <png.h>
+
 // Collada includes
 #include <dae.h>
 #include <dae/daeSIDResolver.h>
@@ -72,7 +75,6 @@ enum VertexUsage
 };
 
 void fillArray(float values[], float value, size_t length);
-void setIdentityMatrix(float values[]);
 
 #define ISZERO(x) (fabs(x) < 0.000001f)
 

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

@@ -1,54 +0,0 @@
-#include "Base.h"
-#include "CameraInstance.h"
-
-namespace gameplay
-{
-
-CameraInstance::CameraInstance(void) : _ref(NULL)
-{
-
-}
-
-CameraInstance::~CameraInstance(void)
-{
-}
-
-unsigned int CameraInstance::getTypeId(void) const
-{
-    return CAMERAINSTANCE_ID;
-}
-const char* CameraInstance::getElementName(void) const
-{
-    return "CameraInstance";
-}
-
-void CameraInstance::writeBinary(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeBinary(file);
-    }
-    else
-    {
-        write((unsigned int)0, file);
-    }
-}
-void CameraInstance::writeText(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeText(file);
-    }
-}
-
-Camera* CameraInstance::getCamera()
-{
-    return _ref;
-}
-
-void CameraInstance::setCamera(Camera* camera)
-{
-    _ref = camera;
-}
-
-}

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

@@ -1,39 +0,0 @@
-#ifndef CAMERAINSTANCE_H_
-#define CAMERAINSTANCE_H_
-
-#include "Object.h"
-#include "Camera.h"
-
-namespace gameplay
-{
-
-class CameraInstance : public Object
-{
-public:
-
-    /**
-     * Constructor.
-     */
-    CameraInstance(void);
-
-    /**
-     * Destructor.
-     */
-    virtual ~CameraInstance(void);
-
-    virtual unsigned int getTypeId(void) const;
-    virtual const char* getElementName(void) const;
-    virtual void writeBinary(FILE* file);
-    virtual void writeText(FILE* file);
-
-    Camera* getCamera();
-    void setCamera(Camera* camera);
-
-private:
-
-    Camera* _ref;
-};
-
-}
-
-#endif

+ 2 - 2
gameplay-encoder/src/DAEChannelTarget.cpp

@@ -1,7 +1,7 @@
+
 #include "Base.h"
 #include "DAEChannelTarget.h"
 
-
 namespace gameplay
 {
 
@@ -40,7 +40,7 @@ DAEChannelTarget::DAEChannelTarget(const domChannelRef channelRef) : _channel(ch
                 index = end + 1;
             }
             _attributeIds.push_back(sub);
-        } while(end != std::string::npos);
+        } while (end != std::string::npos);
     }
 
 }

+ 4 - 54
gameplay-encoder/src/DAEOptimizer.cpp

@@ -1,6 +1,5 @@
 #include "Base.h"
 #include "DAEOptimizer.h"
-#include "StringUtil.h"
 
 namespace gameplay
 {
@@ -38,7 +37,7 @@ void DAEOptimizer::combineAnimations(const std::string& nodeId, const std::strin
     // 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++)
+    for (std::list<domChannelRef>::iterator i = channels.begin(); i != channels.end(); ++i)
     {
         moveChannelAndSouresToAnimation(*i, animation);
     }
@@ -47,55 +46,6 @@ void DAEOptimizer::combineAnimations(const std::string& nodeId, const std::strin
     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;
@@ -103,12 +53,12 @@ void DAEOptimizer::deleteEmptyAnimations()
     // 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++)
+    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++)
+        for (size_t j = 0; j < animationCount; ++j)
         {
             domAnimationRef& animation = animationArray.get(j);
             if (isEmptyAnimation(animation))
@@ -119,7 +69,7 @@ void DAEOptimizer::deleteEmptyAnimations()
     }
 
     // Delete all of the empty animations
-    for (std::list<domAnimationRef>::iterator i = animations.begin(); i != animations.end(); i++)
+    for (std::list<domAnimationRef>::iterator i = animations.begin(); i != animations.end(); ++i)
     {
         daeElement::removeFromParent(*i);
     }

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

@@ -33,14 +33,6 @@ public:
 
 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.
      */

+ 211 - 232
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -1,4 +1,8 @@
+/*
+ * DAESceneEncoder.h
+ */
 #include "Base.h"
+
 #include "DAESceneEncoder.h"
 #include "DAEOptimizer.h"
 
@@ -16,28 +20,10 @@ DAESceneEncoder::~DAESceneEncoder()
 {
 }
 
-std::string getFilenameFromFilePath(const std::string& filepath)
-{
-    if (filepath.find_last_of("/") != std::string::npos)
-    {
-        return filepath.substr(filepath.find_last_of("/")+1);
-    }
-    return "";
-}
-
-std::string getFilenameNoExt(const std::string& filename)
-{
-    if (filename.find_last_of(".") != std::string::npos)
-    {
-        return filename.substr(0, filename.find_last_of("."));
-    }
-    return filename;
-}
-
 unsigned int getMaxOffset(domInputLocalOffset_Array& inputArray)
 {
     unsigned int maxOffset = 0;
-    for (unsigned int i = 0; i < (int)inputArray.getCount(); i++ )
+    for (unsigned int i = 0; i < (int)inputArray.getCount(); ++i)
     {
         if ( inputArray[i]->getOffset() > maxOffset )
         {
@@ -58,7 +44,7 @@ void DAESceneEncoder::optimizeCOLLADA(const EncoderArguments& arguments, domCOLL
     if (size > 0)
     {
         begin();
-        for (size_t i = 0; i < size; i++)
+        for (size_t i = 0; i < size; ++i)
         {
             optimizer.combineAnimations(groupAnimatioNodeIds[i], groupAnimatioIds[i]);
         }
@@ -78,7 +64,7 @@ void DAESceneEncoder::triangulate(DAE* dae)
     daeDatabase* dataBase = dae->getDatabase();
 
     int geometryCount = (int)(dataBase->getElementCount(0, "geometry"));
-    for (int i = 0; i < geometryCount; i++)
+    for (int i = 0; i < geometryCount; ++i)
     {
         // Find the next geometry element.
         domGeometry* domGeometry;
@@ -93,14 +79,14 @@ void DAESceneEncoder::triangulate(DAE* dae)
 
         // Loop over all the polygons elements.
         int polygonsCount = (int)(domMesh->getPolygons_array().getCount());
-        for (int j = 0; j < polygonsCount; j++)
+        for (int j = 0; j < polygonsCount; ++j)
         {
             // Get the polygons out of the mesh.
             domPolygons* domPolygons = domMesh->getPolygons_array()[j];
             // Create the triangles from the polygons
             createTrianglesFromPolygons(domMesh, domPolygons);
         }
-        while(domMesh->getPolygons_array().getCount() > 0)
+        while (domMesh->getPolygons_array().getCount() > 0)
         {
             domPolygons* domPolygons = domMesh->getPolygons_array().get(0);
             // Remove the polygons from the mesh.
@@ -109,14 +95,14 @@ void DAESceneEncoder::triangulate(DAE* dae)
 
         // Loop over all the polylist elements.
         int polylistCount = (int)(domMesh->getPolylist_array().getCount());
-        for (int j = 0; j < polylistCount; j++)
+        for (int j = 0; j < polylistCount; ++j)
         {
             // Get the polylist out of the mesh.
             domPolylist* domPolylist = domMesh->getPolylist_array()[j];
             // Create the triangles from the polygon list
             createTrianglesFromPolylist(domMesh, domPolylist);
         }
-        while(domMesh->getPolylist_array().getCount() > 0)
+        while (domMesh->getPolylist_array().getCount() > 0)
         {
             domPolylist* domPolylist = domMesh->getPolylist_array().get(0);
             // Remove the polylist from the mesh.
@@ -134,7 +120,7 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     
     // Give the new <triangles> the same <_dae> and <parameters> as the old  <polygons>.
-    for (unsigned int i = 0; i < domPolygons->getInput_array().getCount(); i++)
+    for (unsigned int i = 0; i < domPolygons->getInput_array().getCount(); ++i)
     {
         triangles->placeElement(domPolygons->getInput_array()[i]->clone());
     }
@@ -144,7 +130,7 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
     unsigned int primitiveCount = domPolygons->getP_array().getCount();
     
     // Triangulate all the primitives, this generates all the triangles in a single <p> element.
-    for (unsigned int j = 0; j < primitiveCount; j++)
+    for (unsigned int j = 0; j < primitiveCount; ++j)
     {
         // Check the polygons for consistancy (some exported files have had the wrong number of indices).
         domP* domCurrentP = domPolygons->getP_array()[j];
@@ -159,21 +145,21 @@ void DAESceneEncoder::createTrianglesFromPolygons(domMesh* domMesh, domPolygons*
             
             // Write out the primitives as triangles, just fan using the first element as the base.
             unsigned int index = inputCount;
-            for (unsigned int k = 0; k < triangleCount; k++)
+            for (unsigned int k = 0; k < triangleCount; ++k)
             {
                 // First vertex.
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[l]);
                 }
                 // Second vertex.
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
                 }
                 // Third vertex.
                 index += inputCount;
-                for (unsigned int l = 0; l < inputCount; l++)
+                for (unsigned int l = 0; l < inputCount; ++l)
                 {
                     domTrianglesP->getValue().append(domCurrentP->getValue()[index + l]);
                 }
@@ -191,7 +177,7 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     domP* domTrianglesP = (domP*)triangles->createAndPlace("p");
     
     // Give the new <triangles> the same <_dae> and <parameters> as the old <polylist>.
-    for (int i = 0; i < (int)(domPolylist->getInput_array().getCount()); i++)
+    for (int i = 0; i < (int)(domPolylist->getInput_array().getCount()); ++i)
     {
         triangles->placeElement(domPolylist->getInput_array()[i]->clone());
     }
@@ -204,27 +190,27 @@ void DAESceneEncoder::createTrianglesFromPolylist(domMesh* domMesh, domPolylist*
     unsigned int trianglesProcessed = 0;
     
     // Triangulate all the primitives, this generates all the triangles in a single <p> element.
-    for (unsigned int j = 0; j < primitiveCount; j++)
+    for (unsigned int j = 0; j < primitiveCount; ++j)
     {
         unsigned int triangleCount = (unsigned int)domPolylist->getVcount()->getValue()[j] - 2;
         
         // Write out the primitives as triangles, just fan using the first element as the base.
         int index = inputCount;
-        for (unsigned int k = 0; k < triangleCount; k++)
+        for (unsigned int k = 0; k < triangleCount; ++k)
         {
             // First vertex.
-            for (unsigned int l = 0; l < inputCount; l++)
+            for (unsigned int l = 0; l < inputCount; ++l)
             {
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + l]);
             }
             // Second vertex.
-            for (unsigned int l = 0; l < inputCount; l++)
+            for (unsigned int l = 0; l < inputCount; ++l)
             {
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
             }
             // Third vertex.
             index += inputCount;
-            for (unsigned int l = 0; l < inputCount; l++)
+            for (unsigned int l = 0; l < inputCount; ++l)
             {
                 domTrianglesP->getValue().append(domPolylist->getP()->getValue()[offset + index + l]);
             }
@@ -359,12 +345,12 @@ void DAESceneEncoder::loadAnimations(const domCOLLADA* dom)
     // Call loadAnimation on all <animation> elements in all <library_animations>
     const domLibrary_animations_Array& animationLibrarys = dom->getLibrary_animations_array();
     size_t animationLibrarysCount = animationLibrarys.getCount();
-    for (size_t i = 0; i < animationLibrarysCount; i++)
+    for (size_t i = 0; i < animationLibrarysCount; ++i)
     {
         const domLibrary_animationsRef& libraryAnimation = animationLibrarys.get(i);
         const domAnimation_Array& animationArray = libraryAnimation->getAnimation_array();
         size_t animationCount = animationArray.getCount();
-        for (size_t j = 0; j < animationCount; j++)
+        for (size_t j = 0; j < animationCount; ++j)
         {
             const domAnimationRef& animationRef = animationArray.get(j);
             loadAnimation(animationRef);
@@ -387,7 +373,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
     // <channel>
     const domChannel_Array& channelArray = animationRef->getChannel_array();
     size_t channelArrayCount = channelArray.getCount();
-    for (size_t i = 0; i < channelArrayCount; i++)
+    for (size_t i = 0; i < channelArrayCount; ++i)
     {
         AnimationChannel* animationChannel = new AnimationChannel();
 
@@ -400,7 +386,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
         // <input>
         const domInputLocal_Array& inputArray = sampler->getInput_array();
         size_t inputArrayCount = inputArray.getCount();
-        for (size_t j = 0; j < inputArrayCount; j++)
+        for (size_t j = 0; j < inputArrayCount; ++j)
         {
             const domInputLocalRef& inputLocal = inputArray.get(j);
 
@@ -421,7 +407,7 @@ void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
                 if (equals(semantic, "INPUT"))
                 {
                     // TODO: Ensure param name is TIME?
-                    for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); k++)
+                    for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); ++k)
                     {
                         // Convert seconds to milliseconds
                         *k = *k * 1000.0f;
@@ -469,7 +455,7 @@ void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChan
     values.resize(count);
     if (count > 0)
     {
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; ++i)
         {
             values[i] = AnimationChannel::getInterpolationType(names.get(i));
         }
@@ -478,7 +464,7 @@ void DAESceneEncoder::loadInterpolation(const domSourceRef source, AnimationChan
         // instead of storing the same type for each key frame.
         unsigned int firstType = values[0];
         bool allEqual = true;
-        for (size_t i = 1; i < count; i++)
+        for (size_t i = 1; i < count; ++i)
         {
             if (firstType != values[i])
             {
@@ -508,7 +494,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
     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++)
+    for (size_t i = 0; i < channelTarget.getTargetAttributeCount(); ++i)
     {
         std::string prop;
         channelTarget.getPropertyName(i, &prop);
@@ -544,7 +530,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                         // Convert (ANGLE ANGLE ANGLE) to (X Y Z ANGLE X Y Z ANGLE X Y Z ANGLE)
                         std::vector<float> floats(size * 4);
                         // Duplicate rotation axis. We will replace only the angle that COLLADA is targeting.
-                        for (size_t j = 0; j < size; j++)
+                        for (size_t j = 0; j < size; ++j)
                         {
                             size_t k = j * 4;
                             floats[k+0] = x;
@@ -620,7 +606,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                 std::vector<float> floats(newSize);
 
                 size_t matrixCount = keyValues.size() / 16;
-                for (size_t i = 0; i < matrixCount; i++)
+                for (size_t i = 0; i < matrixCount; ++i)
                 {
                     size_t j = i * 16;
                     // COLLADA used row-major but the Matrix class uses column-major
@@ -678,7 +664,7 @@ void DAESceneEncoder::copyFloats(const domFloat_array* source, std::vector<float
     size_t count = (size_t)source->getCount();
     t.resize(count);
     const domListOfFloats& listOfFloats = source->getValue();
-    for (size_t i = 0; i < count; i++)
+    for (size_t i = 0; i < count; ++i)
     {
         t[i] = (float)listOfFloats.get(i);
     }
@@ -691,7 +677,7 @@ void DAESceneEncoder::loadScene(const domVisual_scene* visualScene)
     const domNode_Array& nodes = visualScene->getNode_array();
     scene->setId(visualScene->getId());
     size_t childCount = nodes.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
         scene->add(loadNode(nodes[i], NULL));
     }
@@ -713,11 +699,11 @@ Node* DAESceneEncoder::findSceneActiveCameraNode(const domVisual_scene* visualSc
     // Find the active camera
     const domVisual_scene::domEvaluate_scene_Array& evaluateScenes = visualScene->getEvaluate_scene_array();
     size_t evaluateSceneCount = evaluateScenes.getCount();
-    for (size_t i = 0; i < evaluateSceneCount; i++)
+    for (size_t i = 0; i < evaluateSceneCount; ++i)
     {
         const domVisual_scene::domEvaluate_scene::domRender_Array& renders = evaluateScenes[i]->getRender_array();
         size_t renderCount = renders.getCount();
-        for (size_t j = 0; j < renderCount; j++)
+        for (size_t j = 0; j < renderCount; ++j)
         {
             xsAnyURI cameraNodeURI = renders[i]->getCamera_node();
             domNode* nodeRef = daeSafeCast<domNode>(cameraNodeURI.getElement());
@@ -779,7 +765,7 @@ Node* DAESceneEncoder::loadNode(domNode* n, Node* parent)
     // Load child nodes
     const domNode_Array& childNodes = n->getNode_array();
     size_t childCount = childNodes.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
         loadNode(childNodes.get(i), node);
     }
@@ -830,7 +816,7 @@ void DAESceneEncoder::calcTransform(domNode* domNode, Matrix& dstTransform)
     daeTArray<daeSmartRef<daeElement> > children;
     domNode->getChildren(children);
     size_t childCount = children.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
         daeElementRef childElement = children[i];
         switch (childElement->getElementType())
@@ -895,7 +881,7 @@ void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
     // Does this node have any camera instances?
     const domInstance_camera_Array& instanceCameras = n->getInstance_camera_array();
     size_t instanceCameraCount = instanceCameras.getCount();
-    for (size_t i = 0; i < instanceCameraCount; i++)
+    for (size_t i = 0; i < instanceCameraCount; ++i)
     {
         // Get the camrea object
         const domInstance_camera* cameraInstanceRef = instanceCameras.get(i);
@@ -904,10 +890,10 @@ void DAESceneEncoder::loadCameraInstance(const domNode* n, Node* node)
 
         if (cameraRef)
         {
-            CameraInstance* cameraInstance = loadCamera(cameraRef);
-            if (cameraInstance)
+            Camera* camera = loadCamera(cameraRef);
+            if (camera)
             {
-                node->setCameraInstance(cameraInstance);
+                node->setCamera(camera);
             }
         }
         else
@@ -922,7 +908,7 @@ void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
     // Does this node have any light instances?
     const domInstance_light_Array& instanceLights = n->getInstance_light_array();
     size_t instanceLightCount = instanceLights.getCount();
-    for (size_t i = 0; i < instanceLightCount; i++)
+    for (size_t i = 0; i < instanceLightCount; ++i)
     {
         // Get the camrea object
         const domInstance_light* lightInstanceRef = instanceLights.get(i);
@@ -931,10 +917,10 @@ void DAESceneEncoder::loadLightInstance(const domNode* n, Node* node)
 
         if (lightRef)
         {
-            LightInstance* lightInstance = loadLight(lightRef);
-            if (lightInstance)
+            Light* light = loadLight(lightRef);
+            if (light)
             {
-                node->setLightInstance(lightInstance);
+                node->setLight(light);
             }
         }
         else
@@ -949,7 +935,7 @@ void DAESceneEncoder::loadGeometryInstance(const domNode* n, Node* node)
     // Does this node have any geometry instances?
     const domInstance_geometry_Array& instanceGeometries = n->getInstance_geometry_array();
     size_t instanceGeometryCount = instanceGeometries.getCount();
-    for (size_t i = 0; i < instanceGeometryCount; i++)
+    for (size_t i = 0; i < instanceGeometryCount; ++i)
     {
         // Get the geometry object
         const domInstance_geometryRef geometryInstanceRef = instanceGeometries.get(i);
@@ -977,7 +963,7 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
     // Does this node have any controller instances?
     const domInstance_controller_Array& instanceControllers = n->getInstance_controller_array();
     size_t instanceControllerCount = instanceControllers.getCount();
-    for (size_t i = 0; i < instanceControllerCount; i++)
+    for (size_t i = 0; i < instanceControllerCount; ++i)
     {
         const domInstance_controllerRef instanceControllerRef = instanceControllers.get(i);
         xsAnyURI controllerURI = instanceControllerRef->getUrl();
@@ -1016,202 +1002,181 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
     }
 }
 
-CameraInstance* DAESceneEncoder::loadCamera(const domCamera* cameraRef)
+Camera* DAESceneEncoder::loadCamera(const domCamera* cameraRef)
 {
-    ///////////////////////////// CAMERA
+    Camera* camera = new Camera();
+    camera->setId(cameraRef->getId());
 
-    // check if camera is already added to gamePlayFile
-    const char* id = cameraRef->getId();
-    Camera* camera = _gamePlayFile.getCamera(id);
-    if (camera == NULL)
+    // Optics
+    const domCamera::domOpticsRef opticsRef = cameraRef->getOptics();
+    if (opticsRef.cast())
     {
-        camera = new Camera();
-        camera->setId(id);
+        const domCamera::domOptics::domTechnique_commonRef techRef = opticsRef->getTechnique_common();
 
-        // Optics
-        const domCamera::domOpticsRef opticsRef = cameraRef->getOptics();
-        if (opticsRef.cast())
+        // Orthographics
+        const domCamera::domOptics::domTechnique_common::domOrthographicRef orthographicRef = techRef->getOrthographic();
+        if (orthographicRef.cast())
         {
-            const domCamera::domOptics::domTechnique_commonRef techRef = opticsRef->getTechnique_common();
-
-            // Orthographics
-            const domCamera::domOptics::domTechnique_common::domOrthographicRef orthographicRef = techRef->getOrthographic();
-            if (orthographicRef.cast())
+            camera->setOrthographic();
+            camera->setAspectRatio((float)orthographicRef->getAspect_ratio()->getValue());
+            camera->setNearPlane((float)orthographicRef->getZnear()->getValue());
+            camera->setFarPlane((float)orthographicRef->getZfar()->getValue());
+
+            const domTargetableFloatRef xmag = orthographicRef->getXmag();
+            const domTargetableFloatRef ymag = orthographicRef->getYmag();
+            // Viewport width
+            if (xmag.cast())
             {
-                camera->setOrthographic();
-                camera->setNearPlane((float)orthographicRef->getZnear()->getValue());
-                camera->setFarPlane((float)orthographicRef->getZfar()->getValue());
-
-                const domTargetableFloatRef xmag = orthographicRef->getXmag();
-                const domTargetableFloatRef ymag = orthographicRef->getYmag();
-                // Viewport width
-                if (xmag.cast())
-                {
-                    camera->setViewportWidth((float)xmag->getValue());
-                }
-                // Viewport height
-                if (ymag.cast())
-                {
-                    camera->setViewportHeight((float)ymag->getValue());
-                }
-                // TODO: Viewport x and y?
+                camera->setViewportWidth((float)xmag->getValue());
             }
-
-            // Perspective
-            const domCamera::domOptics::domTechnique_common::domPerspectiveRef perspectiveRef = techRef->getPerspective();
-            if (perspectiveRef.cast())
+            // Viewport height
+            if (ymag.cast())
             {
-                camera->setPerspective();
-                camera->setNearPlane((float)perspectiveRef->getZnear()->getValue());
-                camera->setFarPlane((float)perspectiveRef->getZfar()->getValue());
+                camera->setViewportHeight((float)ymag->getValue());
+            }
+            // TODO: Viewport x and y?
+        }
 
-                float aspectRatio = -1.0f;
-                if (perspectiveRef->getAspect_ratio().cast())
-                {
-                    aspectRatio = (float)perspectiveRef->getAspect_ratio()->getValue();
-                    camera->setAspectRatio(aspectRatio);
-                }
-                if (perspectiveRef->getYfov().cast())
-                {
-                    camera->setFieldOfView((float)perspectiveRef->getYfov()->getValue());
-                }
-                else if (perspectiveRef->getXfov().cast() && aspectRatio > 0.0f)
-                {
-                    // The gameplaybinary stores the yfov but collada might have specified
-                    // an xfov and an aspect ratio. So use those to calculate the yfov.
-                    float xfov = (float)perspectiveRef->getXfov()->getValue();
-                    float yfov = xfov / aspectRatio;
-                    camera->setFieldOfView(yfov);
-                }
+        // Perspective
+        const domCamera::domOptics::domTechnique_common::domPerspectiveRef perspectiveRef = techRef->getPerspective();
+        if (perspectiveRef.cast())
+        {
+            camera->setPerspective();
+            camera->setNearPlane((float)perspectiveRef->getZnear()->getValue());
+            camera->setFarPlane((float)perspectiveRef->getZfar()->getValue());
+
+            float aspectRatio = -1.0f;
+            if (perspectiveRef->getAspect_ratio().cast())
+            {
+                aspectRatio = (float)perspectiveRef->getAspect_ratio()->getValue();
+                camera->setAspectRatio(aspectRatio);
+            }
+            if (perspectiveRef->getYfov().cast())
+            {
+                camera->setFieldOfView((float)perspectiveRef->getYfov()->getValue());
+            }
+            else if (perspectiveRef->getXfov().cast() && aspectRatio > 0.0f)
+            {
+                // The gameplaybinary stores the yfov but collada might have specified
+                // an xfov and an aspect ratio. So use those to calculate the yfov.
+                float xfov = (float)perspectiveRef->getXfov()->getValue();
+                float yfov = xfov / aspectRatio;
+                camera->setFieldOfView(yfov);
             }
         }
-        _gamePlayFile.addCamera(camera);
     }
-    CameraInstance* cameraInstance = new CameraInstance();
-    cameraInstance->setCamera(camera);
-    return cameraInstance;
+    _gamePlayFile.addCamera(camera);
+    return camera;
 }
 
-LightInstance* DAESceneEncoder::loadLight(const domLight* lightRef)
+Light* DAESceneEncoder::loadLight(const domLight* lightRef)
 {
-    ///////////////////////////// LIGHT
-
-    // check if light is already added to gamePlayFile
-    const char* id = lightRef->getId();
-    Light* light = _gamePlayFile.getLight(id);
-    if (light == NULL)
-    {
-        light = new Light();
-        light->setId(lightRef->getId());
+    Light* light = new Light();
+    light->setId(lightRef->getId());
 
-        const domLight::domTechnique_commonRef techRef = lightRef->getTechnique_common();
+    const domLight::domTechnique_commonRef techRef = lightRef->getTechnique_common();
 
-        // Ambient light
+    // Ambient light
+    {
+        const domLight::domTechnique_common::domAmbientRef ambientRef = techRef->getAmbient();
+        if (ambientRef.cast())
         {
-            const domLight::domTechnique_common::domAmbientRef ambientRef = techRef->getAmbient();
-            if (ambientRef.cast())
-            {
-                light->setAmbientLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = ambientRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-            }
+            light->setAmbientLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = ambientRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
         }
+    }
 
-        // Directional light
+    // Directional light
+    {
+        const domLight::domTechnique_common::domDirectionalRef direcitonalRef = techRef->getDirectional();
+        if (direcitonalRef.cast())
         {
-            const domLight::domTechnique_common::domDirectionalRef direcitonalRef = techRef->getDirectional();
-            if (direcitonalRef.cast())
-            {
-                light->setDirectionalLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = direcitonalRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-            }
+            light->setDirectionalLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = direcitonalRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
         }
+    }
 
-        // Spot light
+    // Spot light
+    {
+        const domLight::domTechnique_common::domSpotRef spotRef = techRef->getSpot();
+        if (spotRef.cast())
         {
-            const domLight::domTechnique_common::domSpotRef spotRef = techRef->getSpot();
-            if (spotRef.cast())
-            {
-                light->setSpotLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = spotRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
+            light->setSpotLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = spotRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
                 
-                const domTargetableFloatRef& constAtt = spotRef->getConstant_attenuation();
-                if (constAtt.cast())
-                {
-                    light->setConstantAttenuation((float)constAtt->getValue());
-                }
-
-                const domTargetableFloatRef& linearAtt = spotRef->getLinear_attenuation();
-                if (linearAtt.cast())
-                {
-                    light->setLinearAttenuation((float)linearAtt->getValue());
-                }
+            const domTargetableFloatRef& constAtt = spotRef->getConstant_attenuation();
+            if (constAtt.cast())
+            {
+                light->setConstantAttenuation((float)constAtt->getValue());
+            }
 
-                const domTargetableFloatRef& quadAtt = spotRef->getQuadratic_attenuation();
-                if (quadAtt.cast())
-                {
-                    light->setQuadraticAttenuation((float)quadAtt->getValue());
-                }
+            const domTargetableFloatRef& linearAtt = spotRef->getLinear_attenuation();
+            if (linearAtt.cast())
+            {
+                light->setLinearAttenuation((float)linearAtt->getValue());
+            }
 
-                const domTargetableFloatRef& falloffAngle = spotRef->getFalloff_angle();
-                if (falloffAngle.cast())
-                {
-                    light->setFalloffAngle((float)falloffAngle->getValue());
-                }
+            const domTargetableFloatRef& quadAtt = spotRef->getQuadratic_attenuation();
+            if (quadAtt.cast())
+            {
+                light->setQuadraticAttenuation((float)quadAtt->getValue());
+            }
 
-                const domTargetableFloatRef& falloffExp = spotRef->getFalloff_exponent();
-                if (falloffExp.cast())
-                {
-                    light->setFalloffExponent((float)falloffExp->getValue());
-                }
+            const domTargetableFloatRef& falloffAngle = spotRef->getFalloff_angle();
+            if (falloffAngle.cast())
+            {
+                light->setFalloffAngle((float)falloffAngle->getValue());
+            }
 
+            const domTargetableFloatRef& falloffExp = spotRef->getFalloff_exponent();
+            if (falloffExp.cast())
+            {
+                light->setFalloffExponent((float)falloffExp->getValue());
             }
         }
+    }
 
-        // Point light
+    // Point light
+    {
+        const domLight::domTechnique_common::domPointRef pointRef = techRef->getPoint();
+        if (pointRef.cast())
         {
-            const domLight::domTechnique_common::domPointRef pointRef = techRef->getPoint();
-            if (pointRef.cast())
+            light->setPointLight();
+            // color
+            const domTargetableFloat3Ref float3Ref = pointRef->getColor();
+            const domFloat3& color3 = float3Ref->getValue();
+            light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
+
+            const domTargetableFloatRef& constAtt = pointRef->getConstant_attenuation();
+            if (constAtt.cast())
             {
-                light->setPointLight();
-                // color
-                const domTargetableFloat3Ref float3Ref = pointRef->getColor();
-                const domFloat3& color3 = float3Ref->getValue();
-                light->setColor((float)color3.get(0), (float)color3.get(1), (float)color3.get(2));
-
-                const domTargetableFloatRef& constAtt = pointRef->getConstant_attenuation();
-                if (constAtt.cast())
-                {
-                    light->setConstantAttenuation((float)constAtt->getValue());
-                }
+                light->setConstantAttenuation((float)constAtt->getValue());
+            }
 
-                const domTargetableFloatRef& linearAtt = pointRef->getLinear_attenuation();
-                if (linearAtt.cast())
-                {
-                    light->setLinearAttenuation((float)linearAtt->getValue());
-                }
+            const domTargetableFloatRef& linearAtt = pointRef->getLinear_attenuation();
+            if (linearAtt.cast())
+            {
+                light->setLinearAttenuation((float)linearAtt->getValue());
+            }
 
-                const domTargetableFloatRef& quadAtt = pointRef->getQuadratic_attenuation();
-                if (quadAtt.cast())
-                {
-                    light->setQuadraticAttenuation((float)quadAtt->getValue());
-                }
+            const domTargetableFloatRef& quadAtt = pointRef->getQuadratic_attenuation();
+            if (quadAtt.cast())
+            {
+                light->setQuadraticAttenuation((float)quadAtt->getValue());
             }
         }
-
-        _gamePlayFile.addLight(light);
     }
-    LightInstance* lightInstance = new LightInstance();
-    lightInstance->setLight(light);
-    return lightInstance;
+    _gamePlayFile.addLight(light);
+    return light;
 }
 
 void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin)
@@ -1300,7 +1265,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
 
     // 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++)
+    for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
     {
         domInputLocalRef input = jointInputs.get(i);
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1351,7 +1316,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     }
 
     // Process "INV_BIND_MATRIX" next
-    for (unsigned int i = 0; i < jointInputs.getCount(); i++)
+    for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
     {
         domInputLocalRef input = jointInputs.get(i);
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1365,7 +1330,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
             //unsigned int matrixFloatsCount = (unsigned int)source->getFloat_array()->getCount();
             unsigned int jointIndex = 0;
 
-            for (unsigned int j = 0; j < jointCount; j++)
+            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),
@@ -1386,7 +1351,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     unsigned int vertexWeightsCount = (unsigned int)vertexWeights->getCount();
     domListOfFloats jointWeights;
 
-    for (unsigned int i = 0; i < jointInputs.getCount(); i++)
+    for (unsigned int i = 0; i < jointInputs.getCount(); ++i)
     {
         domInputLocalOffsetRef input = vertexWeightsInputs.get(i);
         std::string inputSemantic = std::string(input->getSemantic());
@@ -1432,7 +1397,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
     int weightOffset = 0;
 
     // Go through all the skin vertex influence weights from the indexed data.
-    for (int i = 0; i < skinVertexInfluenceCountTotal; i++)
+    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);
@@ -1441,7 +1406,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         //vertexInfluences.SetCapacity(vertexInfluenceCount);
 
         // Get the index/weight pairs and some the weight totals while at it.
-        for (unsigned int j = 0; j < vertexInfluenceCount; j++)
+        for (unsigned int j = 0; j < vertexInfluenceCount; ++j)
         {
             float weight = (float)jointWeights.get((unsigned int)skinVertexJointWeightPairIndices[vOffset + 1]);
             int index = (int)skinVertexJointWeightPairIndices[vOffset];
@@ -1461,7 +1426,7 @@ Model* DAESceneEncoder::loadSkin(const domSkin* skinElement)
         }
 
         // Get up the the maximum vertex weight influence count.
-         for (unsigned int j = 0; j < maxVertexInfluencesCount; j++)
+         for (unsigned int j = 0; j < maxVertexInfluencesCount; ++j)
         {
             if (j < vertexInfluenceCount)
             {
@@ -1569,7 +1534,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     unsigned int inputCount = (unsigned int)-1;
 
     // Loop through our set of triangle lists (each list of triangles corresponds to a single MeshPart)
-    for (unsigned int i = 0; i < trianglesArrayCount; i++)
+    for (unsigned int i = 0; i < trianglesArrayCount; ++i)
     {
         const domTrianglesRef& triangles = trianglesArray.get(i);
         const domInputLocalOffset_Array& inputArray = triangles->getInput_array();
@@ -1579,7 +1544,8 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
         {
             inputCount = (unsigned int)inputArray.getCount();
 
-            for (unsigned int j = 0; j < inputCount; j++)
+            int texCoordCount = 0;
+            for (unsigned int j = 0; j < inputCount; ++j)
             {
                 const domInputLocalOffsetRef& input = inputArray.get(j);
                 std::string inputSemantic = input->getSemantic();
@@ -1588,7 +1554,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 if (equals(inputSemantic, "VERTEX"))
                 {
                     unsigned int vertexArrayCount = (unsigned int)vertexArray.getCount();
-                    for (unsigned int k = 0; k < vertexArrayCount; k++)
+                    for (unsigned int k = 0; k < vertexArrayCount; ++k)
                     {
                         const domInputLocalRef& vertexInput = vertexArray.get(k);
                         
@@ -1616,6 +1582,14 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                     if (type == -1)
                     {
                         warning(std::string("Semantic (") + semantic + ") is invalid/unsupported for geometry mesh: " + geometryId);
+                        break;
+                    }
+                    if (type == TEXCOORD0)
+                    {
+                        // Some meshes have multiple texture coordinates
+                        assert(texCoordCount <= 7);
+                        type += texCoordCount;
+                        ++texCoordCount;
                     }
 
                     DAEPolygonInput* polygonInput = new DAEPolygonInput();
@@ -1643,7 +1617,7 @@ 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 j = 0; j < polygonInputs.size(); j++)
+                for (size_t j = 0; j < polygonInputs.size(); ++j)
                 {
                     delete polygonInputs[j];
                 }
@@ -1659,7 +1633,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     
     // Now we have validated that all input in all triangles are the same and in the same input layout.
     // Lets start to read them and build our subsets.
-    for (unsigned int i = 0; i < trianglesArrayCount; i++)
+    for (unsigned int i = 0; i < trianglesArrayCount; ++i)
     {
         // Subset to be built.
         MeshPart* subset = new MeshPart();
@@ -1765,6 +1739,11 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                     vertex.texCoord.y = (float)source.get(polyIndex * 2 + 1);
                 }
                 break;
+
+            case TEXCOORD1:
+                // TODO
+                break;
+
             default:
                 break;
             }

+ 2 - 4
gameplay-encoder/src/DAESceneEncoder.h

@@ -5,9 +5,7 @@
 #include "Object.h"
 #include "Node.h"
 #include "Camera.h"
-#include "CameraInstance.h"
 #include "Light.h"
-#include "LightInstance.h"
 #include "Mesh.h"
 #include "MeshPart.h"
 #include "MeshSkin.h"
@@ -116,8 +114,8 @@ private:
      */
     void loadAnimation(const domAnimationRef animationRef);
 
-    CameraInstance* loadCamera(const domCamera* cameraRef);
-    LightInstance* loadLight(const domLight* lightRef);
+    Camera* loadCamera(const domCamera* cameraRef);
+    Light* loadLight(const domLight* lightRef);
     Model* loadSkin(const domSkin* skinElement);
     Model* loadGeometry(const domGeometry* geometry, const domBind_materialRef bindMaterial);
 

+ 60 - 10
gameplay-encoder/src/DAEUtil.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "DAEUtil.h"
+#include "StringUtil.h"
 
 namespace gameplay
 {
@@ -14,6 +15,55 @@ namespace gameplay
  */
 int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node);
 
+void 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 getJointNames(const domSourceRef source, std::vector<std::string>& list)
 {
     // BLENDER used name_array
@@ -22,7 +72,7 @@ void getJointNames(const domSourceRef source, std::vector<std::string>& list)
     {
         domListOfNames& ids = nameArray->getValue();
         size_t jointCount = (size_t)nameArray->getCount();
-        for (size_t j = 0; j < jointCount; j++)
+        for (size_t j = 0; j < jointCount; ++j)
         {
             list.push_back(std::string(ids.get(j)));
         }
@@ -35,7 +85,7 @@ void getJointNames(const domSourceRef source, std::vector<std::string>& list)
         {
             xsIDREFS& ids = idArray->getValue();
             size_t jointCount = (size_t)idArray->getCount();
-            for (size_t j = 0; j < jointCount; j++)
+            for (size_t j = 0; j < jointCount; ++j)
             {
                 list.push_back(std::string(ids.get(j).getID()));
             }
@@ -48,7 +98,7 @@ void getJointNames(const domSkin* skin, std::vector<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++)
+    for (size_t i = 0; i < inputCount; ++i)
     {
         const domInputLocalRef input = inputArray.get(i);
         const char* semantic = input->getSemantic();
@@ -72,7 +122,7 @@ domSource* getInputSource(const domChannelRef& channel)
         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++)
+        for (size_t i = 0; i < inputArrayCount; ++i)
         {
             const domInputLocalRef& input = inputArray.get(i);
             if (strcmp(input->getSemantic(), "INPUT") == 0)
@@ -108,7 +158,7 @@ const domSamplerRef getSampler(const domChannelRef& channel)
         
         const domSampler_Array& samplerArray = animation->getSampler_array();
         size_t count = samplerArray.getCount();
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; ++i)
         {
             const domSamplerRef& sampler = samplerArray.get(i);
             if (id.compare(sampler->getId()) == 0)
@@ -133,7 +183,7 @@ const domSourceRef getSource(const domInputLocalRef& inputLocal, const domAnimat
     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++)
+    for (size_t i = 0; i < count; ++i)
     {
         const domSourceRef source = sourceArray.get(i);
         if (id.compare(source->getId()) == 0)
@@ -154,7 +204,7 @@ const domName_arrayRef getSourceNameArray(const domSourceRef& source)
     daeTArray<daeSmartRef<daeElement> > children;
     source->getChildren(children);
     size_t childCount = children.getCount();
-    for (size_t i = 0; i < childCount; i++)
+    for (size_t i = 0; i < childCount; ++i)
     {
         const daeElementRef element = children.get(i);
         if (element->getElementType() == COLLADA_TYPE::NAME_ARRAY)
@@ -223,7 +273,7 @@ bool equalKeyTimes(const domSource* s1, const domSource* s2)
         const domListOfFloats& list2 = f2->getValue();
 
         size_t count = (size_t)f1->getCount();
-        for (size_t i = 0; i < count; i++)
+        for (size_t i = 0; i < count; ++i)
         {
             if (list1.get(i) != list2.get(i))
             {
@@ -259,7 +309,7 @@ void moveChannelAndSouresToAnimation(domChannelRef& channel, domAnimationRef& an
 
         domInputLocal_Array& inputArray = sampler->getInput_array();
         size_t inputArrayCount = inputArray.getCount();
-        for (size_t i = 0; i < inputArrayCount; i++)
+        for (size_t i = 0; i < inputArrayCount; ++i)
         {
             inputArray = sampler->getInput_array();
             const domInputLocalRef& input = inputArray.get(i);
@@ -289,7 +339,7 @@ int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, con
 {
     const std::string nodeId = node->getId();
     size_t count = skeletonArray.getCount();
-    for (size_t i = 0; i < count; i++)
+    for (size_t i = 0; i < count; ++i)
     {
         const domInstance_controller::domSkeletonRef& skeleton = skeletonArray.get(i);
         daeElementRef element = skeleton->getValue().getElement();

+ 9 - 1
gameplay-encoder/src/DAEUtil.h

@@ -4,6 +4,14 @@
 namespace gameplay
 {
 
+/**
+ * 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);
+
 /**
  * Gets the joint names for the given source and appends them to the given list.
  * 
@@ -39,7 +47,7 @@ domSource* getInputSource(const domChannelRef& channel);
 const domSamplerRef getSampler(const domChannelRef& channel);
 
 /**
- * Returns the source from the given sampler input. 
+ * Returns the source from the given sampler input.
  * Searchs within the given animation.
  * 
  * @param inputLocal The input element within a sampler.

+ 97 - 12
gameplay-encoder/src/EncoderArguments.cpp

@@ -1,4 +1,5 @@
 #include "Base.h"
+
 #include "EncoderArguments.h"
 #include "StringUtil.h"
 
@@ -10,6 +11,8 @@
 namespace gameplay
 {
 
+static EncoderArguments* __instance;
+
 EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
     _fontSize(0),
     _parseError(false),
@@ -17,6 +20,8 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
     _textOutput(false),
     _daeOutput(false)
 {
+    __instance = this;
+
     if (argc > 1)
     {
         size_t filePathIndex = argc - 1;
@@ -27,12 +32,12 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
         
         // read the options
         std::vector<std::string> options;
-        for (size_t i = 1; i < filePathIndex; i++)
+        for (size_t i = 1; i < filePathIndex; ++i)
         {
             options.push_back(argv[i]);
         }
         
-        for (size_t i = 0; i < options.size(); i++)
+        for (size_t i = 0; i < options.size(); ++i)
         {
             if (options[i][0] == '-')
             {
@@ -50,6 +55,11 @@ EncoderArguments::~EncoderArguments(void)
 {
 }
 
+EncoderArguments* EncoderArguments::getInstance()
+{
+    return __instance;
+}
+
 const std::string& EncoderArguments::getFilePath() const
 {
     return _filePath;
@@ -60,6 +70,12 @@ const char* EncoderArguments::getFilePathPointer() const
     return _filePath.c_str();
 }
 
+std::string EncoderArguments::getOutputPath() const
+{
+    int pos = _filePath.find_last_of('/');
+    return (pos == -1 ? _filePath : _filePath.substr(0, pos));
+}
+
 const std::string& EncoderArguments::getDAEOutputPath() const
 {
     return _daeOutputPath;
@@ -75,6 +91,29 @@ const std::vector<std::string>& EncoderArguments::getGroupAnimationAnimationId()
     return _groupAnimationAnimationId;
 }
 
+bool EncoderArguments::containsGroupNodeId(const std::string& nodeId) const
+{
+    return find(_groupAnimationNodeId.begin(), _groupAnimationNodeId.end(), nodeId) != _groupAnimationNodeId.end();
+}
+
+const std::string EncoderArguments::getAnimationId(const std::string& nodeId) const
+{
+    std::vector<std::string>::const_iterator it = find(_groupAnimationNodeId.begin(), _groupAnimationNodeId.end(), nodeId);
+    for (size_t i = 0, size = _groupAnimationNodeId.size(); i < size; ++i)
+    {
+        if (_groupAnimationNodeId[i].compare(nodeId) == 0)
+        {
+            return _groupAnimationAnimationId[i];
+        }
+    }
+    return "";
+}
+
+const std::vector<std::string>& EncoderArguments::getHeightmapNodeIds() const
+{
+    return _heightmapNodeIds;
+}
+
 bool EncoderArguments::parseErrorOccured() const
 {
     return _parseError;
@@ -95,14 +134,28 @@ bool EncoderArguments::fileExists() const
 
 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");
+    fprintf(stderr,"Usage: gameplay-encoder [options] <filepath>\n\n");
+    fprintf(stderr,"Supported file extensions:\n");
+    fprintf(stderr,"  .dae\t(COLLADA)\n");
+    fprintf(stderr,"  .fbx\t(FBX)\n");
+    fprintf(stderr,"  .ttf\t(TrueType Font)\n");
+    fprintf(stderr,"\n");
+    fprintf(stderr,"COLLADA and FBX file options:\n");
+    fprintf(stderr,"  -i<id>\t\tFilter by node ID.\n");
+    fprintf(stderr,"  -t\t\t\tWrite text/xml.\n");
+    fprintf(stderr,"  -groupAnimations <node id> <animation id>\n" \
+        "\t\t\tGroup all animation channels targetting the nodes into a new animation.\n");
+    fprintf(stderr,"  -heightmaps \"<node ids>\"\n" \
+        "\t\t\tList of nodes to generate heightmaps for.\n" \
+        "\t\t\tNode id list should be in quotes with a space between each id.\n" \
+        "\t\t\tHeightmaps will be saved in files named <nodeid>.png.\n");
+    fprintf(stderr,"\n");
+    fprintf(stderr,"COLLADA file options:\n");
+    fprintf(stderr,"  -dae <filepath>\tOutput optimized DAE.\n");
+    fprintf(stderr,"\n");
+    fprintf(stderr,"TTF file options:\n");
+    fprintf(stderr,"  -s <size of font>\tSize of the font.\n");
+    fprintf(stderr,"  -p\t\t\tOutput font preview.\n");
     exit(8);
 }
 
@@ -154,6 +207,10 @@ EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
     {
         return FILEFORMAT_DAE;
     }
+    if (ext.compare("fbx") == 0 || ext.compare("FBX") == 0)
+    {
+        return FILEFORMAT_FBX;
+    }
     if (ext.compare("ttf") == 0 || ext.compare("TTF") == 0)
     {
         return FILEFORMAT_TTF;
@@ -166,7 +223,7 @@ EncoderArguments::FileFormat EncoderArguments::getFileFormat() const
     return FILEFORMAT_UNKNOWN;
 }
 
-void EncoderArguments::readOption(const std::vector<std::string>& options, size_t *index)
+void EncoderArguments::readOption(const std::vector<std::string>& options, size_t* index)
 {
     const std::string& str = options[*index];
     if (str.length() == 0 && str[0] != '-')
@@ -220,6 +277,34 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
             _parseError = true;
             return;
         }
+        break;
+    case 'h':
+        {
+            if (str.compare("-heightmaps") == 0)
+            {
+                (*index)++;
+                if (*index < options.size())
+                {
+                    // Split node id list into tokens
+                    unsigned int length = options[*index].size() + 1;
+                    char* nodeIds = new char[length];
+                    strcpy(nodeIds, options[*index].c_str());
+                    nodeIds[length-1] = 0;
+                    char* id = strtok(nodeIds, " ");
+                    while (id)
+                    {
+                        _heightmapNodeIds.push_back(id);
+                        id = strtok(NULL, " ");
+                    }
+                    delete[] nodeIds;
+                }
+                else
+                {
+                    fprintf(stderr, "Error: missing argument for -heightmaps.\n");
+                }
+            }
+        }
+        break;
     case 'p':
         _fontPreview = true;
         break;
@@ -268,7 +353,7 @@ std::string EncoderArguments::getRealPath(const std::string& filepath)
 
 void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
 {
-    for (; *str != '\0'; str++)
+    for (; *str != '\0'; ++str)
     {
         if (*str == oldChar)
         {

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

@@ -15,6 +15,7 @@ public:
     {
         FILEFORMAT_UNKNOWN,
         FILEFORMAT_DAE,
+        FILEFORMAT_FBX,
         FILEFORMAT_TTF,
         FILEFORMAT_GPB
     };
@@ -29,6 +30,11 @@ public:
      */
     ~EncoderArguments(void);
 
+    /**
+     * Gets the EncoderArguments instance.
+     */
+    static EncoderArguments* getInstance();
+
     /**
      * Gets the file format from the file path based on the extension.
      */
@@ -49,9 +55,19 @@ public:
      */
     const std::string& getDAEOutputPath() const;
 
+    /**
+     * Returns the output path/folder.
+     */
+    std::string getOutputPath() const;
+
     const std::vector<std::string>& getGroupAnimationNodeId() const;
     const std::vector<std::string>& getGroupAnimationAnimationId() const;
 
+    bool containsGroupNodeId(const std::string& nodeId) const;
+    const std::string getAnimationId(const std::string& nodeId) const;
+
+    const std::vector<std::string>& getHeightmapNodeIds() const;
+
     /**
      * Returns true if an error occured while parsing the command line arguments.
      */
@@ -109,6 +125,8 @@ private:
 
     std::vector<std::string> _groupAnimationNodeId;
     std::vector<std::string> _groupAnimationAnimationId;
+    std::vector<std::string> _heightmapNodeIds;
+
 };
 
 }

+ 1336 - 0
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -0,0 +1,1336 @@
+#ifdef USE_FBX
+
+#include <algorithm>
+#include <string>
+
+#include "FBXSceneEncoder.h"
+#include "EncoderArguments.h"
+
+using namespace gameplay;
+
+/**
+ * Returns the aspect ratio from the given camera.
+ * 
+ * @param fbxCamera The FBX camera to get the aspect ratio from.
+ * 
+ * @return The aspect ratio from the camera.
+ */
+float getAspectRatio(KFbxCamera* fbxCamera);
+
+/**
+ * Returns the field of view Y from the given camera.
+ * 
+ * @param fbxCamera The camera to get the fiew of view from.
+ * 
+ * @return The field of view Y.
+ */
+float getFieldOfView(KFbxCamera* fbxCamera);
+
+/**
+ * Loads the texture coordinates from given mesh's polygon part into the vertex.
+ * 
+ * @param fbxMesh The mesh to get the polygon from.
+ * @param polyIndex The index of the polygon.
+ * @param posInPoly The position in the polygon.
+ * @param vertex The vertex to copy the texture coordinates to.
+ */
+void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex);
+
+/**
+ * Loads the normal from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to get the polygon from.
+ * @param vertexIndex The vertex index in the mesh.
+ * @param vertex The vertex to copy to.
+ */
+void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the tangent from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param vertexIndex The index of the vertex within fbxMesh.
+ * @param vertex The vertex to copy to.
+ */
+void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the binormal from the mesh and adds it to the given vertex.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param vertexIndex The index of the vertex within fbxMesh.
+ * @param vertex The vertex to copy to.
+ */
+void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the blend weight and blend indices data into the vertex.
+ * 
+ * @param vertexWeights List of vertex weights. The x member contains the blendIndices. The y member contains the blendWeights.
+ * @param vertex The vertex to copy the blend data to.
+ */
+void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
+
+/**
+ * Loads the blend weights and blend indices from the given mesh.
+ * 
+ * Each element of weights is a list of Vector2s where "x" is the blend index and "y" is the blend weight.
+ * 
+ * @param fbxMesh The mesh to load from.
+ * @param weights List of blend weights and blend indices for each vertex.
+ * 
+ * @return True if this mesh has a mesh skin, false otherwise.
+ */
+bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
+
+/**
+ * Copies from an FBX matrix to a float[16] array.
+ */
+void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix);
+
+/**
+ * Copies from an FBX matrix to a gameplay matrix.
+ */
+void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
+
+/**
+ * Finds the min and max start time and stop time of the given animation curve.
+ * 
+ * startTime is updated if the animation curve contains a start time that is less than startTime.
+ * stopTime is updated if the animation curve contains a stop time that is greater than stopTime.
+ * frameRate is updated if the animation curve contains a frame rate that is greater than frameRate.
+ * 
+ * @param animCurve The animation curve to read from.
+ * @param startTime The min start time. (in/out)
+ * @param stopTime The max stop time. (in/out)
+ * @param frameRate The frame rate. (in/out)
+ */
+void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
+
+/**
+ * Appends a key frame of the given node's transform at the given time.
+ * 
+ * @param fbxNode The node to get the matrix transform from.
+ * @param time The key time to add and the time to get the transform from.
+ * @param keyTimes The list of key times to append to.
+ * @param keyValues The list of key values to append to.
+ */
+void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes, std::vector<float>* keyValues);
+
+/**
+ * Decomposes the given node's matrix transform at the given time and copies to scale, rotation and translation.
+ * 
+ * @param fbxNode The node to get the matrix transform from.
+ * @param time The time to get the matrix transform from.
+ * @param scale The scale to copy to.
+ * @param rotation The rotation to copy to.
+ * @param translation The translation to copy to.
+ */
+void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation);
+
+/**
+ * Creates an animation channel that targets the given node and target attribute using the given key times and key values.
+ * 
+ * @param fbxNode The node to target.
+ * @param targetAttrib The attribute type to target.
+ * @param keyTimes The key times for the animation channel.
+ * @param keyValues The key values for the animation channel.
+ * 
+ * @return The newly created animation channel.
+ */
+AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
+
+void addScaleChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime);
+
+void addTranslateChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime);
+
+
+////////////////////////////////////
+// Member Functions
+////////////////////////////////////
+
+FBXSceneEncoder::FBXSceneEncoder()
+    : _groupAnimation(NULL)
+{
+}
+
+FBXSceneEncoder::~FBXSceneEncoder()
+{
+}
+
+void FBXSceneEncoder::write(const std::string& filepath, const EncoderArguments& arguments)
+{
+    KFbxSdkManager* sdkManager = KFbxSdkManager::Create();
+    KFbxIOSettings *ios = KFbxIOSettings::Create(sdkManager, IOSROOT);
+    sdkManager->SetIOSettings(ios);
+    KFbxImporter* importer = KFbxImporter::Create(sdkManager,"");
+    
+    if (!importer->Initialize(filepath.c_str(), -1, sdkManager->GetIOSettings()))
+    {
+        printf("Call to KFbxImporter::Initialize() failed.\n");
+        printf("Error returned: %s\n\n", importer->GetLastErrorString());
+        exit(-1);
+    }
+    
+    KFbxScene* fbxScene = KFbxScene::Create(sdkManager,"__FBX_SCENE__");
+
+    print("Loading FBX file.");
+    importer->Import(fbxScene);
+    importer->Destroy();
+    print("Loading Scene.");
+    loadScene(fbxScene);
+    print("Loading animations.");
+    loadAnimations(fbxScene, arguments);
+    sdkManager->Destroy();
+
+    print("Optimizing GamePlay Binary.");
+    _gamePlayFile.adjust();
+    
+    std::string filenameOnly = getFilenameFromFilePath(filepath);
+    std::string dstFilename = filepath.substr(0, filepath.find_last_of('/'));
+    dstFilename.append(1, '/');
+    dstFilename.append(getFilenameNoExt(filenameOnly));
+    
+    if (arguments.textOutputEnabled())
+    {
+        std::string outFile = dstFilename + ".xml";
+        fprintf(stderr, "Saving debug file: %s\n", outFile.c_str());
+        _gamePlayFile.saveText(outFile);
+    }
+    else
+    {
+        std::string outFile = dstFilename + ".gpb";
+        fprintf(stderr, "Saving binary file: %s\n", outFile.c_str());
+        _gamePlayFile.saveBinary(outFile);
+    }
+}
+
+void FBXSceneEncoder::loadScene(KFbxScene* fbxScene)
+{
+    Scene* scene = new Scene();
+    scene->setId(fbxScene->GetName());
+    if (scene->getId().length() == 0)
+    {
+        scene->setId("__SCENE__");
+    }
+
+    // Load all of the nodes and their contents.
+    KFbxNode* rootNode = fbxScene->GetRootNode();
+    if (rootNode)
+    {
+        print("Triangulate.");
+        triangulateRecursive(rootNode);
+
+        print("Load nodes.");
+        // Don't include the FBX root node in the GPB.
+        const int childCount = rootNode->GetChildCount();
+        for (int i = 0; i < childCount; ++i)
+        {
+            Node* node = loadNode(rootNode->GetChild(i));
+            if (node)
+            {
+                scene->add(node);
+            }
+        }
+    }
+
+    // Load the MeshSkin information from the scene's poses.
+    loadBindShapes(fbxScene);
+
+    // Find the ambient light of the scene
+    KFbxColor ambientColor = fbxScene->GetGlobalSettings().GetAmbientColor();
+    scene->setAmbientColor((float)ambientColor.mRed, (float)ambientColor.mGreen, (float)ambientColor.mBlue);
+
+    _gamePlayFile.addScene(scene);
+}
+
+void FBXSceneEncoder::loadAnimationChannels(KFbxAnimLayer* animLayer, KFbxNode* fbxNode, Animation* animation)
+{
+    const std::string* targetId = NULL;
+
+    const char* name = fbxNode->GetName();
+    Node* node = _gamePlayFile.getNode(name);
+    if (node)
+    {
+        targetId = &node->getId();
+    }
+    
+    // Determine which properties are animated on this node
+    // Find the transform at each key frame
+    // TODO: Ignore properties that are not animated (scale, rotation, translation)
+    // This should result in only one animation channel per animated node.
+
+    float startTime = FLT_MAX, stopTime = -1.0f, frameRate = FLT_MIN;
+    bool tx = false, ty = false, tz = false, rx = false, ry = false, rz = false, sx = false, sy = false, sz = false;
+    KFbxAnimCurve* animCurve = NULL;
+    animCurve = fbxNode->LclTranslation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_T_X);
+    if (animCurve)
+    {
+        tx = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclTranslation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_T_Y);
+    if (animCurve)
+    {
+        ty = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclTranslation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_T_Z);
+    if (animCurve)
+    {
+        tz = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclRotation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_R_X);
+    if (animCurve)
+    {
+        rx = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclRotation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_R_Y);
+    if (animCurve)
+    {
+        ry = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclRotation.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_R_Z);
+    if (animCurve)
+    {
+        rz = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclScaling.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_S_X);
+    if (animCurve)
+    {
+        sx = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclScaling.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_S_Y);
+    if (animCurve)
+    {
+        sy = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+    animCurve = fbxNode->LclScaling.GetCurve<KFbxAnimCurve>(animLayer, KFCURVENODE_S_Z);
+    if (animCurve)
+    {
+        sz = true;
+        findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate);
+    }
+
+    bool translate = tx | ty | tz;
+    bool scale = sx | sy | sz;
+    bool rotate = rx | ry | rz;
+
+    if (translate || rotate || scale)
+    {
+        assert(startTime != FLT_MAX);
+        assert(stopTime >= 0.0f);
+        AnimationChannel* channel = new AnimationChannel();
+        channel->setTargetId(name);
+        channel->setTargetAttribute(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE);
+        
+        float increment = 1000.0f / frameRate;
+        std::vector<float> keyTimes;
+        std::vector<float> keyValues;
+        for (float time = startTime; time < stopTime; time += increment)
+        {
+            appendKeyFrame(fbxNode, time, &keyTimes, &keyValues);
+        }
+        // Add the last key frame at exactly stopTime
+        appendKeyFrame(fbxNode, stopTime, &keyTimes, &keyValues);
+
+        channel->setKeyTimes(keyTimes);
+        /*
+        std::vector<float> newKeyValues;
+        for (size_t i = 0, size = keyValues.size(); i < size; i += 10)
+        {
+            if (translate)
+            {
+                newKeyValues.push_back(keyValues[i+0]);
+                newKeyValues.push_back(keyValues[i+1]);
+                newKeyValues.push_back(keyValues[i+2]);
+            }
+            if (rotate)
+            {
+                newKeyValues.push_back(keyValues[i+3]);
+                newKeyValues.push_back(keyValues[i+4]);
+                newKeyValues.push_back(keyValues[i+5]);
+                newKeyValues.push_back(keyValues[i+6]);
+            }
+            if (scale)
+            {
+                newKeyValues.push_back(keyValues[i+7]);
+                newKeyValues.push_back(keyValues[i+8]);
+                newKeyValues.push_back(keyValues[i+9]);
+            }
+        }
+        channel->setKeyValues(newKeyValues);
+        */
+        channel->setKeyValues(keyValues);
+        channel->setInterpolation(AnimationChannel::LINEAR);
+        animation->add(channel);
+        /*
+        if (!translate)
+        {
+            addTranslateChannel(animation, fbxNode, startTime, stopTime);
+        }
+        if (!rotate)
+        {
+            printf("rotate?\n"); // TODO
+        }
+        if (!scale)
+        {
+            addScaleChannel(animation, fbxNode, startTime, stopTime);
+        }
+        */
+        if (_groupAnimation != animation)
+        {
+            // TODO explains
+            _gamePlayFile.addAnimation(animation);
+        }
+    }
+}
+
+void FBXSceneEncoder::loadAnimationLayer(KFbxAnimLayer* fbxAnimLayer, KFbxNode* fbxNode, const EncoderArguments& arguments)
+{
+    bool animationGroupId = false;
+    const char* name = fbxNode->GetName();
+    // Check if this node's animations are supposed to be grouped
+    if (name)
+    {
+        std::string str = name;
+        if (arguments.containsGroupNodeId(str))
+        {
+            animationGroupId = true;
+            _groupAnimation = new Animation();
+            _groupAnimation->setId(arguments.getAnimationId(str));
+        }
+    }
+    Animation* animation = _groupAnimation;
+    if (!_groupAnimation)
+    {
+        animation = new Animation();
+        animation->setId(name);
+    }
+    loadAnimationChannels(fbxAnimLayer, fbxNode, animation);
+
+    const int childCount = fbxNode->GetChildCount();
+    for (int modelCount = 0; modelCount < childCount; ++modelCount)
+    {
+        loadAnimationLayer(fbxAnimLayer, fbxNode->GetChild(modelCount), arguments);
+    }
+    if (animationGroupId)
+    {
+        _gamePlayFile.addAnimation(_groupAnimation);
+        _groupAnimation = NULL;
+    }
+}
+
+void FBXSceneEncoder::loadAnimations(KFbxScene* fbxScene, const EncoderArguments& arguments)
+{
+    KFbxAnimEvaluator* evaluator = fbxScene->GetEvaluator();
+    if (!evaluator)
+        return;
+    KFbxAnimStack* animStack = evaluator->GetContext();
+    if (!animStack)
+        return;
+
+    for (int i = 0; i < fbxScene->GetSrcObjectCount(FBX_TYPE(KFbxAnimStack)); ++i)
+    {
+        KFbxAnimStack* animStack = KFbxCast<KFbxAnimStack>(fbxScene->GetSrcObject(FBX_TYPE(KFbxAnimStack), i));
+        int nbAnimLayers = animStack->GetMemberCount(FBX_TYPE(KFbxAnimLayer));
+        for (int l = 0; l < nbAnimLayers; ++l)
+        {
+            KFbxAnimLayer* animLayer = animStack->GetMember(FBX_TYPE(KFbxAnimLayer), l);
+            loadAnimationLayer(animLayer, fbxScene->GetRootNode(), arguments);
+        }
+    }
+}
+
+Node* FBXSceneEncoder::loadNode(KFbxNode* fbxNode)
+{
+    Node* node = NULL;
+
+    // Check if this node has already been loaded
+    const char* id = fbxNode->GetName();
+    if (id && strlen(id) > 0)
+    {
+        node = _gamePlayFile.getNode(fbxNode->GetName());
+        if (node)
+        {
+            return node;
+        }
+    }
+    node = new Node();
+    if (id)
+    {
+        node->setId(id);
+    }
+    _gamePlayFile.addNode(node);
+
+    transformNode(fbxNode, node);
+    
+    loadCamera(fbxNode, node);
+    loadLight(fbxNode, node);
+    loadModel(fbxNode, node);
+
+    if (fbxNode->GetSkeleton())
+    {
+        // Indicate that this is a joint node for the purpose of debugging.
+        // The XML debug output will print that this node is a joint.
+        node->setIsJoint(true);
+    }
+
+    // Load child nodes
+    const int childCount = fbxNode->GetChildCount();
+    for (int i = 0; i < childCount; ++i)
+    {
+        Node* child = loadNode(fbxNode->GetChild(i));
+        if (child)
+        {
+            node->addChild(child);
+        }
+    }
+    return node;
+}
+
+Mesh* FBXSceneEncoder::getMesh(size_t meshId)
+{
+    // Check if this mesh was already loaded.
+    std::map<size_t, Mesh*>::iterator it = _meshes.find(meshId);
+    if (it != _meshes.end())
+    {
+        return it->second;
+    }
+    return NULL;
+}
+
+void FBXSceneEncoder::saveMesh(size_t meshId, Mesh* mesh)
+{
+    assert(mesh);
+    if (!getMesh(meshId))
+    {
+        _meshes[meshId] = mesh;
+    }
+}
+
+void FBXSceneEncoder::print(const char* str)
+{
+    fprintf(stderr,"%s\n", str);
+}
+
+void FBXSceneEncoder::transformNode(KFbxNode* fbxNode, Node* node)
+{
+    KFbxXMatrix matrix;
+    if (fbxNode->GetCamera() || fbxNode->GetLight())
+    {
+        // TODO: Why is this necessary for Camera and Light?
+        matrix.SetTRS(fbxNode->LclTranslation.Get(), fbxNode->LclRotation.Get(), fbxNode->LclScaling.Get());
+    }
+    else
+    {
+        matrix = fbxNode->EvaluateLocalTransform();
+    }
+
+    float m[16];
+    copyMatrix(matrix, m);
+    int i = 0;
+    for (int row = 0; row < 4; ++row)
+    {
+        for (int col = 0; col < 4; ++col)
+        {
+            m[i++] = (float)matrix.Get(row, col);
+        }
+    }
+    node->setTransformMatrix(m);
+}
+
+void FBXSceneEncoder::loadBindShapes(KFbxScene* fbxScene)
+{
+    float m[16];
+    const int poseCount = fbxScene->GetPoseCount();
+    for (int i = 0; i < poseCount; ++i)
+    {
+        KFbxPose* pose = fbxScene->GetPose(i);
+        assert(pose);
+        if (pose->IsBindPose() && pose->GetCount() > 0)
+        {
+            KFbxNode* fbxNode = pose->GetNode(0);
+            if (fbxNode->GetMesh() != NULL)
+            {
+                Node* node = _gamePlayFile.getNode(fbxNode->GetName());
+                assert(node && node->getModel());
+
+                Model* model = node->getModel();
+                if (model && model->getSkin())
+                {
+                    MeshSkin* skin = model->getSkin();
+                    copyMatrix(pose->GetMatrix(0), m);
+                    skin->setBindShape(m);
+                }
+            }
+        }
+    }
+}
+
+void FBXSceneEncoder::loadCamera(KFbxNode* fbxNode, Node* node)
+{
+    KFbxCamera* fbxCamera = fbxNode->GetCamera();
+    if (!fbxCamera)
+    {
+        return;
+    }
+    Camera* camera = new Camera();
+    const char* name = fbxNode->GetName();
+    if (name)
+    {
+        std::string id(name);
+        id.append("_Camera");
+        camera->setId(id);
+    }
+    camera->setAspectRatio(getAspectRatio(fbxCamera));
+    camera->setNearPlane((float)fbxCamera->NearPlane.Get());
+    camera->setFarPlane((float)fbxCamera->FarPlane.Get());
+
+    if (fbxCamera->ProjectionType.Get() == KFbxCamera::eORTHOGONAL)
+    {
+        camera->setOrthographic();
+        camera->setViewportWidth((float)fbxCamera->GetApertureWidth());
+        camera->setViewportWidth((float)fbxCamera->GetApertureHeight());
+        // xmag in FBX can be calculated from: OrthoZoom * 30.0 / 2.0
+        camera->setViewportWidth((float)fbxCamera->OrthoZoom.Get() * 15.0f);
+    }
+    else if (fbxCamera->ProjectionType.Get() == KFbxCamera::ePERSPECTIVE)
+    {
+        camera->setPerspective();
+        camera->setFieldOfView(getFieldOfView(fbxCamera));
+    }
+    else
+    {
+        warning("Unknown camera type in node");
+        return;
+    }
+    _gamePlayFile.addCamera(camera);
+    node->setCamera(camera);
+}
+
+void FBXSceneEncoder::loadLight(KFbxNode* fbxNode, Node* node)
+{
+    KFbxLight* fbxLight = fbxNode->GetLight();
+    if (!fbxLight)
+    {
+        return;
+    }
+    Light* light = new Light();
+    const char* name = fbxNode->GetName();
+    if (name)
+    {
+        std::string id(name);
+        id.append("_Light");
+        light->setId(id);
+    }
+
+    fbxDouble3 color = fbxLight->Color.Get();
+    light->setColor((float)color[0], (float)color[1], (float)color[2]);
+    
+    switch (fbxLight->LightType.Get())
+    {
+    case KFbxLight::ePOINT:
+        light->setPointLight();
+        // TODO: range
+        break;
+    case KFbxLight::eDIRECTIONAL:
+        light->setDirectionalLight();
+        break;
+    case KFbxLight::eSPOT:
+        light->setSpotLight();
+        // TODO: range and angles
+        break;
+    default:
+        warning("Unknown light type in node.");
+        return;
+    }
+
+    _gamePlayFile.addLight(light);
+    node->setLight(light);
+}
+
+void FBXSceneEncoder::loadModel(KFbxNode* fbxNode, Node* node)
+{
+    KFbxMesh* fbxMesh = fbxNode->GetMesh();
+    if (!fbxMesh)
+    {
+        return;
+    }
+    if (fbxMesh->IsTriangleMesh())
+    {
+        Mesh* mesh = loadMesh(fbxMesh);
+        Model* model = new Model();
+        model->setMesh(mesh);
+        node->setModel(model);
+        loadSkin(fbxMesh, model);
+        if (model->getSkin())
+        {
+            // TODO: explain
+            node->resetTransformMatrix();
+        }
+    }
+}
+
+void FBXSceneEncoder::loadSkin(KFbxMesh* fbxMesh, Model* model)
+{
+    const int deformerCount = fbxMesh->GetDeformerCount();
+    for (int i = 0; i < deformerCount; ++i)
+    {
+        KFbxDeformer* deformer = fbxMesh->GetDeformer(i);
+        if (deformer->GetDeformerType() == KFbxDeformer::eSKIN)
+        {
+            KFbxSkin* fbxSkin = static_cast<KFbxSkin*>(deformer);
+
+            MeshSkin* skin = new MeshSkin();
+
+            std::vector<std::string> jointNames;
+            std::vector<Node*> joints;
+            std::vector<Matrix> bindPoses;
+
+            const int clusterCount = fbxSkin->GetClusterCount();
+            for (int j = 0; j < clusterCount; ++j)
+            {
+                KFbxCluster* cluster = fbxSkin->GetCluster(j);
+                assert(cluster);
+                KFbxNode* linkedNode = cluster->GetLink();
+                assert(linkedNode);
+                if (linkedNode->GetSkeleton())
+                {
+                    const char* jointName = linkedNode->GetName();
+                    assert(jointName);
+                    jointNames.push_back(jointName);
+                    Node* joint = loadNode(linkedNode);
+                    assert(joint);
+                    joints.push_back(joint);
+
+                    KFbxXMatrix matrix;
+                    cluster->GetTransformLinkMatrix(matrix);
+                    Matrix m;
+                    copyMatrix(matrix.Inverse(), m);
+                    bindPoses.push_back(m);
+                }
+            }
+            skin->setJointNames(jointNames);
+            skin->setJoints(joints);
+            skin->setBindPoses(bindPoses);
+            model->setSkin(skin);
+            break;
+        }
+    }
+}
+
+Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
+{
+    // Check if this mesh has already been loaded.
+    Mesh* mesh = getMesh(fbxMesh->GetUniqueID());
+    if (mesh)
+    {
+        return mesh;
+    }
+    mesh = new Mesh();
+    // GamePlay requires that a mesh have a unique ID but KFbxMesh doesn't have a string ID.
+    const char* name = fbxMesh->GetNode()->GetName();
+    if (name)
+    {
+        std::string id(name);
+        id.append("_Mesh");
+        mesh->setId(id);
+    }
+
+    // The number of mesh parts is equal to the number of materials that affect this mesh.
+    // There is always at least one mesh part.
+    std::vector<MeshPart*> meshParts;
+    const int materialCount = fbxMesh->GetNode()->GetMaterialCount();
+    int meshPartSize = (materialCount > 0) ? materialCount : 1;
+    for (int i = 0; i < meshPartSize; ++i)
+    {
+        meshParts.push_back(new MeshPart());
+    }
+
+    // Find the blend weights and blend indices if this mesh is skinned.
+    std::vector<std::vector<Vector2> > weights;
+    bool hasSkin = loadBlendWeights(fbxMesh, weights);
+    
+    int vertexIndex = 0;
+    KFbxVector4* controlPoints = fbxMesh->GetControlPoints();
+    const int polygonCount = fbxMesh->GetPolygonCount();
+    for (int polyIndex = 0; polyIndex < polygonCount; ++polyIndex)
+    {
+        const int polygonSize = fbxMesh->GetPolygonSize(polyIndex);
+        for (int posInPoly = 0; posInPoly < polygonSize; ++posInPoly)
+        {
+            int controlPointIndex = fbxMesh->GetPolygonVertex(polyIndex, posInPoly);
+            Vertex vertex;
+
+            KFbxVector4& position = controlPoints[controlPointIndex];
+            vertex.position.x = (float)position[0];
+            vertex.position.y = (float)position[1];
+            vertex.position.z = (float)position[2];
+
+            loadTextureCoords(fbxMesh, polyIndex, posInPoly, &vertex);
+            loadNormal(fbxMesh, vertexIndex, &vertex);
+            loadTangent(fbxMesh, vertexIndex, &vertex);
+            loadBinormal(fbxMesh, vertexIndex, &vertex);
+            // TODO: loadDiffuseColors
+
+            if (hasSkin)
+            {
+                loadBlendData(weights[controlPointIndex], &vertex);
+            }
+
+            // Determine which mesh part this vertex index should be added to based on the material that affects it.
+            int meshPartIndex = 0;
+            const int elementMatrialCount = fbxMesh->GetElementMaterialCount();
+            for (int k = 0; k < elementMatrialCount; ++k)
+            {
+                KFbxGeometryElementMaterial* elementMaterial = fbxMesh->GetElementMaterial(k);
+                meshPartIndex = elementMaterial->GetIndexArray().GetAt(polyIndex);
+            }
+
+            // Add the vertex to the mesh if it hasn't already been added and find the vertex index.
+            unsigned int index;
+            if (mesh->contains(vertex))
+            {
+                index = mesh->getVertexIndex(vertex);
+            }
+            else
+            {
+                index = mesh->addVertex(vertex);
+            }
+            meshParts[meshPartIndex]->addIndex(index);
+            vertexIndex++;
+        }
+    }
+
+    const size_t meshpartsSize = meshParts.size();
+    for (size_t i = 0; i < meshpartsSize; ++i)
+    {
+        mesh->addMeshPart(meshParts[i]);
+    }
+
+    // The order that the vertex elements are add to the list matters.
+    // It should be the same order as how the Vertex data is written.
+
+    // Position
+    mesh->addVetexAttribute(POSITION, 3);
+
+    const Vertex& vertex = mesh->vertices[0];
+    // Normals
+    if (vertex.hasNormal)
+    {
+        mesh->addVetexAttribute(NORMAL, 3);
+    }
+    // Tangents
+    if (vertex.hasTangent)
+    {
+        mesh->addVetexAttribute(TANGENT, 3);
+    }
+    // Binormals
+    if (vertex.hasBinormal)
+    {
+        mesh->addVetexAttribute(BINORMAL, 3);
+    }
+    // Texture Coordinates
+    if (vertex.hasTexCoord)
+    {
+        mesh->addVetexAttribute(TEXCOORD0, 2);
+    }
+    // Diffuse Color
+    if (vertex.hasColor)
+    {
+        mesh->addVetexAttribute(COLOR, 3);
+    }
+    // Skinning BlendWeights BlendIndices
+    if (vertex.hasWeights)
+    {
+        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
+        mesh->addVetexAttribute(BLENDINDICES, 4);
+    }
+
+    _gamePlayFile.addMesh(mesh);
+    saveMesh(fbxMesh->GetUniqueID(), mesh);
+    return mesh;
+}
+
+void FBXSceneEncoder::triangulateRecursive(KFbxNode* fbxNode)
+{
+    // Triangulate all NURBS, patch and mesh under this node recursively.
+    KFbxNodeAttribute* nodeAttribute = fbxNode->GetNodeAttribute();
+
+    if (nodeAttribute)
+    {
+        if (nodeAttribute->GetAttributeType() == KFbxNodeAttribute::eMESH ||
+            nodeAttribute->GetAttributeType() == KFbxNodeAttribute::eNURB ||
+            nodeAttribute->GetAttributeType() == KFbxNodeAttribute::eNURBS_SURFACE ||
+            nodeAttribute->GetAttributeType() == KFbxNodeAttribute::ePATCH)
+        {
+            KFbxGeometryConverter converter(fbxNode->GetFbxSdkManager());
+            converter.TriangulateInPlace(fbxNode);
+        }
+    }
+
+    const int childCount = fbxNode->GetChildCount();
+    for (int childIndex = 0; childIndex < childCount; ++childIndex)
+    {
+        triangulateRecursive(fbxNode->GetChild(childIndex));
+    }
+}
+
+void FBXSceneEncoder::warning(const std::string& message)
+{
+    printf("Warning: %s\n", message.c_str());
+}
+
+void FBXSceneEncoder::warning(const char* message)
+{
+    printf("Warning: %s\n", message);
+}
+
+////////////////////////////////////
+// Functions
+////////////////////////////////////
+
+float getAspectRatio(KFbxCamera* fbxCamera)
+{
+    return (float)fbxCamera->FilmAspectRatio.Get();
+    /*
+    KFbxCamera::ECameraAspectRatioMode camAspectRatioMode = fbxCamera->GetAspectRatioMode();
+    double aspectX = fbxCamera->AspectWidth.Get();
+    double aspectY = fbxCamera->AspectHeight.Get();
+    double aspectRatio = 1.333333;
+    switch ( camAspectRatioMode)
+    {
+    case KFbxCamera::eWINDOW_SIZE:
+        aspectRatio = aspectX / aspectY;
+        break;
+    case KFbxCamera::eFIXED_RATIO:
+        aspectRatio = aspectX;
+        break;
+    case KFbxCamera::eFIXED_RESOLUTION:
+        aspectRatio = aspectX / aspectY * fbxCamera->GetPixelRatio();
+        break;
+    case KFbxCamera::eFIXED_WIDTH:
+        aspectRatio = fbxCamera->GetPixelRatio() / aspectY;
+        break;
+    case KFbxCamera::eFIXED_HEIGHT:
+        aspectRatio = fbxCamera->GetPixelRatio() * aspectX;
+        break;
+    default:
+        break;
+    }
+    return (float)aspectRatio;
+    */
+}
+
+inline double vfov(double hfov, double aspect)
+{
+    static const double MATH_PI_180 = 0.01745329251994329576923690768489;
+    static const double MATH_180_PI = 57.295779513082320876798154814105;
+    return (2.0 * atan((aspect) * tan( (hfov * MATH_PI_180) * 0.5)) * MATH_180_PI);
+}
+
+float getFieldOfView(KFbxCamera* fbxCamera)
+{
+    double fieldOfViewX = 0.0;
+    double fieldOfViewY = 0.0;
+    double filmHeight = fbxCamera->GetApertureHeight();
+    double filmWidth = fbxCamera->GetApertureWidth() * fbxCamera->GetSqueezeRatio();
+    double apertureRatio = filmHeight / filmWidth;
+    if ( fbxCamera->GetApertureMode() == KFbxCamera::eVERTICAL)
+    {
+        fieldOfViewY = fbxCamera->FieldOfView.Get();
+    }
+    else if (fbxCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL)
+    {
+        fieldOfViewX = fbxCamera->FieldOfView.Get();
+        fieldOfViewY = vfov( fieldOfViewX, apertureRatio);
+    }
+    else if (fbxCamera->GetApertureMode() == KFbxCamera::eFOCAL_LENGTH)
+    {
+        fieldOfViewX = fbxCamera->ComputeFieldOfView(fbxCamera->FocalLength.Get());
+        fieldOfViewY = vfov( fieldOfViewX, apertureRatio);
+    }
+    else if (fbxCamera->GetApertureMode() == KFbxCamera::eHORIZONTAL_AND_VERTICAL)
+    {
+        fieldOfViewY = fbxCamera->FieldOfViewY.Get();
+    }
+    else
+    {
+        fieldOfViewY = 45.0;
+    }
+    return (float)fieldOfViewY;
+}
+
+void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex)
+{
+    assert(fbxMesh && polyIndex >=0 && posInPoly >= 0);
+    if (fbxMesh->GetElementUVCount() > 0)
+    {
+        // Get only the first UV coordinates.
+        KFbxGeometryElementUV* leUV = fbxMesh->GetElementUV(0);
+        switch (leUV->GetMappingMode())
+        {
+        case KFbxGeometryElement::eBY_CONTROL_POINT:
+            switch (leUV->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                vertex->hasTexCoord = true;
+                vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(polyIndex)[0];
+                vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(polyIndex)[1];
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leUV->GetIndexArray().GetAt(polyIndex);
+                    vertex->hasTexCoord = true;
+                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(id)[0];
+                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(id)[1];
+                }
+                break;
+            default:
+                break;
+            }
+            break;
+        case KFbxGeometryElement::eBY_POLYGON_VERTEX:
+            {
+                int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
+                switch (leUV->GetReferenceMode())
+                {
+                case KFbxGeometryElement::eDIRECT:
+                case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                    vertex->hasTexCoord = true;
+                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(lTextureUVIndex)[0];
+                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(lTextureUVIndex)[1];
+                    break;
+                default:
+                    break;
+                }
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementNormalCount() > 0)
+    {
+        // Get only the first
+        KFbxGeometryElementNormal* leNormal = fbxMesh->GetElementNormal(0);
+        if (leNormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (leNormal->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(vertexIndex);
+                    vertex->hasNormal = true;
+                    vertex->normal.x = (float)vec4[0];
+                    vertex->normal.y = (float)vec4[1];
+                    vertex->normal.z = (float)vec4[2];
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leNormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(id);
+                    vertex->hasNormal = true;
+                    vertex->normal.x = (float)vec4[0];
+                    vertex->normal.y = (float)vec4[1];
+                    vertex->normal.z = (float)vec4[2];
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementTangentCount() > 0)
+    {
+        // Get only the first tangent
+        KFbxGeometryElementTangent* leTangent = fbxMesh->GetElementTangent(0);
+        if (leTangent->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (leTangent->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(vertexIndex);
+                    vertex->hasTangent = true;
+                    vertex->tangent.x = (float)vec4[0];
+                    vertex->tangent.y = (float)vec4[1];
+                    vertex->tangent.z = (float)vec4[2];
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leTangent->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(id);
+                    vertex->hasTangent = true;
+                    vertex->tangent.x = (float)vec4[0];
+                    vertex->tangent.y = (float)vec4[1];
+                    vertex->tangent.z = (float)vec4[2];
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementBinormalCount() > 0)
+    {
+        // Get only the first binormal.
+        KFbxGeometryElementBinormal* leBinormal = fbxMesh->GetElementBinormal(0);
+        if (leBinormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (leBinormal->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(vertexIndex);
+                    vertex->hasBinormal = true;
+                    vertex->binormal.x = (float)vec4[0];
+                    vertex->binormal.y = (float)vec4[1];
+                    vertex->binormal.z = (float)vec4[2];
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = leBinormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(id);
+                    vertex->hasBinormal = true;
+                    vertex->binormal.x = (float)vec4[0];
+                    vertex->binormal.y = (float)vec4[1];
+                    vertex->binormal.z = (float)vec4[2];
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
+{
+    size_t size = vertexWeights.size();
+
+    if (size >= 1)
+    {
+        vertex->hasWeights= true;
+        vertex->blendIndices.x = vertexWeights[0].x;
+        vertex->blendWeights.x = vertexWeights[0].y;
+    }
+    if (size >= 2)
+    {
+        vertex->blendIndices.y = vertexWeights[1].x;
+        vertex->blendWeights.y = vertexWeights[1].y;
+    }
+    if (size >= 3)
+    {
+        vertex->blendIndices.z = vertexWeights[2].x;
+        vertex->blendWeights.z = vertexWeights[2].y;
+    }
+    if (size >= 4)
+    {
+        vertex->blendIndices.w = vertexWeights[3].x;
+        vertex->blendWeights.w = vertexWeights[3].y;
+    }
+    //vertex->normalizeBlendWeight();
+}
+
+bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights)
+{
+    assert(fbxMesh);
+    const int vertexCount = fbxMesh->GetControlPointsCount();
+
+    KFbxSkin* fbxSkin = NULL;
+    const int deformerCount = fbxMesh->GetDeformerCount();
+    for (int i = 0; i < deformerCount; ++i)
+    {
+        KFbxDeformer* deformer = fbxMesh->GetDeformer(i);
+        if (deformer->GetDeformerType() == KFbxDeformer::eSKIN)
+        {
+            fbxSkin = static_cast<KFbxSkin*>(deformer);
+            weights.resize(vertexCount);
+
+            const int clusterCount = fbxSkin->GetClusterCount();
+            for (int j = 0; j < clusterCount; ++j)
+            {
+                KFbxCluster* cluster = fbxSkin->GetCluster(j);
+                assert(cluster);
+                KFbxNode* linkedNode = cluster->GetLink();
+                assert(linkedNode);
+
+                const int vertexIndexCount = cluster->GetControlPointIndicesCount();
+                for (int k = 0; k < vertexIndexCount; ++k)
+                {
+                    int index = cluster->GetControlPointIndices()[k];
+                    if (index >= vertexCount)
+                    {
+                        continue;
+                    }
+
+                    double weight = cluster->GetControlPointWeights()[k];
+                    if (weight == 0.0)
+                    {
+                        continue;
+                    }
+                    weights[index].push_back(Vector2((float)j, (float)weight));
+                }
+            }
+            // Only the first skin deformer will be loaded.
+            // There probably won't be more than one.
+            break;
+        }
+    }
+    return fbxSkin != NULL;
+}
+
+void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate)
+{
+    KTime start, stop;
+    animCurve->GetTimeInterval(start, stop);
+    *startTime = std::min(*startTime, (float)start.GetMilliSeconds());
+    *stopTime = std::max(*stopTime, (float)stop.GetMilliSeconds());
+    *frameRate = std::max(*frameRate, (float)stop.GetFrameRate(KTime::eDEFAULT_MODE));
+}
+
+void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes, std::vector<float>* keyValues)
+{
+    KFbxXMatrix fbxMatrix;
+    Matrix matrix;
+    KTime kTime;
+    kTime.SetMilliSeconds((kLongLong)time);
+    fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
+    copyMatrix(fbxMatrix, matrix);
+
+    Vector3 scale;
+    Quaternion rotation;
+    Vector3 translation;
+    matrix.decompose(&scale, &rotation, &translation);
+
+    keyTimes->push_back(time);
+    keyValues->push_back(scale.x);
+    keyValues->push_back(scale.y);
+    keyValues->push_back(scale.z);
+    keyValues->push_back(rotation.x);
+    keyValues->push_back(rotation.y);
+    keyValues->push_back(rotation.z);
+    keyValues->push_back(rotation.w);
+    keyValues->push_back(translation.x);
+    keyValues->push_back(translation.y);
+    keyValues->push_back(translation.z);
+}
+
+void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotation, Vector3* translation)
+{
+    KFbxXMatrix fbxMatrix;
+    Matrix matrix;
+    KTime kTime;
+    kTime.SetMilliSeconds((kLongLong)time);
+    fbxMatrix = fbxNode->EvaluateLocalTransform(kTime);
+    copyMatrix(fbxMatrix, matrix);
+    matrix.decompose(scale, rotation, translation);
+}
+
+AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues)
+{
+    AnimationChannel* channel = new AnimationChannel();
+    channel->setTargetId(fbxNode->GetName());
+    channel->setKeyTimes(keyTimes);
+    channel->setKeyValues(keyValues);
+    channel->setInterpolation(AnimationChannel::LINEAR);
+    channel->setTargetAttribute(targetAttrib);
+    return channel;
+}
+
+void addScaleChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime)
+{
+    std::vector<float> keyTimes;
+    std::vector<float> keyValues;
+    Vector3 scale;
+    Quaternion rotation;
+    Vector3 translation;
+
+    decompose(fbxNode, startTime, &scale, &rotation, &translation);
+    keyTimes.push_back(startTime);
+    keyValues.push_back(scale.x);
+    keyValues.push_back(scale.y);
+    keyValues.push_back(scale.z);
+
+    decompose(fbxNode, stopTime, &scale, &rotation, &translation);
+    keyTimes.push_back(stopTime);
+    keyValues.push_back(scale.x);
+    keyValues.push_back(scale.y);
+    keyValues.push_back(scale.z);
+
+    AnimationChannel* channel = createAnimationChannel(fbxNode, Transform::ANIMATE_SCALE, keyTimes, keyValues);
+    animation->add(channel);
+}
+
+void addTranslateChannel(Animation* animation, KFbxNode* fbxNode, float startTime, float stopTime)
+{
+    std::vector<float> keyTimes;
+    std::vector<float> keyValues;
+    Vector3 scale;
+    Quaternion rotation;
+    Vector3 translation;
+
+    decompose(fbxNode, startTime, &scale, &rotation, &translation);
+    keyTimes.push_back(startTime);
+    keyValues.push_back(translation.x);
+    keyValues.push_back(translation.y);
+    keyValues.push_back(translation.z);
+
+    decompose(fbxNode, stopTime, &scale, &rotation, &translation);
+    keyTimes.push_back(stopTime);
+    keyValues.push_back(translation.x);
+    keyValues.push_back(translation.y);
+    keyValues.push_back(translation.z);
+
+    AnimationChannel* channel = createAnimationChannel(fbxNode, Transform::ANIMATE_TRANSLATE, keyTimes, keyValues);
+    animation->add(channel);
+}
+
+void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix)
+{
+    int i = 0;
+    for (int row = 0; row < 4; ++row)
+    {
+        for (int col = 0; col < 4; ++col)
+        {
+            matrix[i++] = (float)fbxMatrix.Get(row, col);
+        }
+    }
+}
+
+void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix)
+{
+    int i = 0;
+    for (int row = 0; row < 4; ++row)
+    {
+        for (int col = 0; col < 4; ++col)
+        {
+            matrix.m[i++] = (float)fbxMatrix.Get(row, col);
+        }
+    }
+}
+
+#endif

+ 222 - 0
gameplay-encoder/src/FBXSceneEncoder.h

@@ -0,0 +1,222 @@
+#ifndef FBXSCENEEENCODER_H_
+#define FBXSCENEEENCODER_H_
+
+#ifdef USE_FBX
+
+#include <iostream>
+#include <list>
+#include <vector>
+#include <ctime>
+#ifdef WIN32
+    #pragma warning( disable : 4100 )
+    #pragma warning( disable : 4512 )
+#endif
+#include <fbxsdk.h>
+
+#include "Base.h"
+#include "StringUtil.h"
+#include "Object.h"
+#include "Node.h"
+#include "Camera.h"
+#include "Light.h"
+#include "Mesh.h"
+#include "MeshPart.h"
+#include "MeshSkin.h"
+#include "Model.h"
+#include "Scene.h"
+#include "Animation.h"
+#include "AnimationChannel.h"
+#include "Vertex.h"
+#include "Matrix.h"
+#include "Transform.h"
+#include "GPBFile.h"
+#include "EncoderArguments.h"
+
+using namespace gameplay;
+
+/**
+ * Class for binary encoding an FBX file.
+ */
+class FBXSceneEncoder
+{
+public:
+
+    static const unsigned int SCENE_SKIN_VERTEXINFLUENCES_MAX = 4;
+    
+    /**
+     * Constructor.
+     */
+    FBXSceneEncoder();
+
+    /**
+     * Destructor.
+     */
+    ~FBXSceneEncoder();
+    
+    /**
+     * Writes out encoded FBX file.
+     */
+    void write(const std::string& filepath, const EncoderArguments& arguments);
+
+private:
+
+    /**
+     * Loads the scene.
+     * 
+     * @param fbxScene The FBX scene to load.
+     */
+    void loadScene(KFbxScene* fbxScene);
+
+    /**
+     * Loads all of the animatiosn from the given FBX scene.
+     * 
+     * @param fbxScene The scene to load animations from.
+     * @param arguments The command line arguments passed to the encoder.
+     */
+    void loadAnimations(KFbxScene* fbxScene, const EncoderArguments& arguments);
+
+    /**
+     * Loads the animations from the given FBX animation layer recursively starting from fbxNode.
+     * 
+     * @param fbxAnimLayer The FBX animation layer to load from.
+     * @param fbxNode The node to start loading animations from.
+     * @param arguments The command line arguments passed to the encoder.
+     */
+    void loadAnimationLayer(KFbxAnimLayer* fbxAnimLayer, KFbxNode* fbxNode, const EncoderArguments& arguments);
+
+    /**
+     * Loads animation channels from the given node and adds the channels to the given animation.
+     * 
+     * @param pAnimLayer The FBX animation layer to load from.
+     * @param fbxNode The node to load animation channels from.
+     * @param animation The animation to add the channels to.
+     */
+    void loadAnimationChannels(KFbxAnimLayer* pAnimLayer, KFbxNode* fbxNode, Animation* animation);
+
+    /**
+     * Loads the bind shape for all mesh skins that have be loaded so far.
+     * 
+     * @param fbxScene The FBX scene to read the bind shapes from.
+     */
+    void loadBindShapes(KFbxScene* fbxScene);
+
+    /**
+     * Loads the camera from the given FBX node and adds to it to the given GamePlay node.
+     * 
+     * @param fbxNode The FBX node to load from.
+     * @param node The GamePlay node to add to.
+     */
+    void loadCamera(KFbxNode* fbxNode, Node* node);
+
+    /**
+     * Loads the light from the given FBX node and adds to it to the given GamePlay node.
+     * 
+     * @param fbxNode The FBX node to load from.
+     * @param node The GamePlay node to add to.
+     */
+    void loadLight(KFbxNode* fbxNode, Node* node);
+    
+    /**
+     * Loads the model from the given FBX node and adds to it to the given GamePlay node.
+     *
+     * @param fbxNode The FBX node to load from.
+     * @param node The GamePlay node to add to.
+     */
+    void loadModel(KFbxNode* fbxNode, Node* node);
+
+    /**
+     * Loads the mesh skin from the given FBX mesh and adds it to the given GamePlay model.
+     *
+     * @param fbxMesh The FBX mesh to load the skin from.
+     * @param model The model to add the skin to.
+     */
+    void loadSkin(KFbxMesh* fbxMesh, Model* model);
+    
+    /**
+     * Loads the FBX Node and creates a GamePlay Node.
+     * 
+     * @param fbxNode The FBX Node to load.
+     * 
+     * @return The newly created Node or NULL if the node could not be loaded.
+     */
+    Node* loadNode(KFbxNode* fbxNode);
+    
+    /**
+     * Loads the FbxMesh and returns a GamePlay mesh.
+     * If the fbxMesh has already been loaded then the same instance of mesh will be returned.
+     * 
+     * @param fbxMesh The FBX Mesh to load.
+     * 
+     * @return The GamePlay mesh that was loaded from the FBX Mesh.
+     */
+    Mesh* loadMesh(KFbxMesh* fbxMesh);
+
+    /**
+     * Gets the Mesh that was saved with the given ID. Returns NULL if a match is not found.
+     * 
+     * @param meshId The ID of the FbxMesh to search for.
+     * 
+     * @return The mesh that was saved with the ID or NULL if none was found.
+     */
+    Mesh* getMesh(size_t meshId);
+
+    /**
+     * Saves the Mesh with the given id.
+     * 
+     * @param meshId The ID of the FbxMesh to use as a key.
+     * @param mesh The mesh to save.
+     */
+    void saveMesh(size_t meshId, Mesh* mesh);
+    
+    /**
+     * Prints a message.
+     *
+     * @param str The string to print.
+     */
+    void print(const char* str);
+
+    /**
+     * Transforms the GamePlay Node using the transform data from the FBX Node.
+     * 
+     * @param fbxNode The FBX node to get the transfrom data from
+     * @param node The GamePlay Node to copy the transform to.
+     */
+    void transformNode(KFbxNode* fbxNode, Node* node);
+
+    /**
+     * Recursively triangules the meshes starting from the given node.
+     * 
+     * @param fbxNode The node to start triangulating from.
+     */
+    static void triangulateRecursive(KFbxNode* fbxNode);
+
+    /**
+     * Prints a warning message.
+     */
+    static void warning(const std::string& message);
+
+    /**
+     * Prints a warning message.
+     */
+    static void warning(const char* message);
+
+private:
+
+    /**
+     * The GamePlay file that is populated while reading the FBX file.
+     */
+    GPBFile _gamePlayFile;
+
+    /**
+     * The collection of meshes for the purpose of making sure that the same model is not loaded twice. (Mesh instancing)
+     */
+    std::map<size_t, Mesh*> _meshes;
+
+    /**
+     * The animation that channels should be added to it the user is using the -groupAnimation command line argument. May be NULL.
+     */
+    Animation* _groupAnimation;
+};
+
+#endif
+#endif

+ 39 - 3
gameplay-encoder/src/FileIO.cpp

@@ -55,7 +55,7 @@ void write(float value, FILE* file)
 }
 void write(const float* values, int length, FILE* file)
 {
-    for (int i = 0; i < length; i++)
+    for (int i = 0; i < length; ++i)
     {
         write(values[i], file);
     }
@@ -77,8 +77,8 @@ void writeZero(FILE* file)
 
 void fprintfElement(FILE* file, const char* elementName, const float values[], int length)
 {
-    fprintf(file, "<%s>", elementName);
-    for (int i = 0; i < length; i++)
+    fprintf(file, "<%s count=\"%d\">", elementName, length);
+    for (int i = 0; i < length; ++i)
     {
         fprintf(file, "%f ", values[i]);
     }
@@ -144,4 +144,40 @@ void skipUint(FILE* file)
     fseek(file, sizeof(unsigned int), SEEK_CUR);
 }
 
+void writeVectorBinary(const Vector2& v, FILE* file)
+{
+    write(v.x, file);
+    write(v.y, file);
+}
+
+void writeVectorText(const Vector2& v, FILE* file)
+{
+    fprintf(file, "%f %f\n", v.x, v.y);
+}
+
+void writeVectorBinary(const Vector3& v, FILE* file)
+{
+    write(v.x, file);
+    write(v.y, file);
+    write(v.z, file);
+}
+
+void writeVectorText(const Vector3& v, FILE* file)
+{
+    fprintf(file, "%f %f %f\n", v.x, v.y, v.z);
+}
+
+void writeVectorBinary(const Vector4& v, FILE* file)
+{
+    write(v.x, file);
+    write(v.y, file);
+    write(v.z, file);
+    write(v.w, file);
+}
+
+void writeVectorText(const Vector4& v, FILE* file)
+{
+    fprintf(file, "%f %f %f %f\n", v.x, v.y, v.z, v.w);
+}
+
 }

+ 30 - 8
gameplay-encoder/src/FileIO.h

@@ -1,11 +1,17 @@
 #ifndef FILEIO_H_
 #define FILEIO_H_
 
+
+#include "Vector2.h"
+#include "Vector3.h"
+#include "Vector4.h"
+
 namespace gameplay
 {
 
 /**
  * Writes an XML element to the specified file stream.
+ * 
  * @param file Pointer to a FILE object that identifies the stream.
  * @param elementName Name of the XML element to write.
  * @param value Value to write.
@@ -20,9 +26,9 @@ void fprintfElement(FILE* file, const char* elementName, const float values[], i
 template <class T>
 void fprintfElement(FILE* file, const char* format, const char* elementName, std::vector<T> list)
 {
-    fprintf(file, "<%s>", elementName);
+    fprintf(file, "<%s count=\"%lu\">", elementName, list.size());
     typename std::vector<T>::const_iterator i;
-    for (i = list.begin(); i != list.end(); i++)
+    for (i = list.begin(); i != list.end(); ++i)
     {
         fprintf(file, format, *i);
     }
@@ -32,9 +38,9 @@ void fprintfElement(FILE* file, const char* format, const char* elementName, std
 template <class T>
 void fprintfElement(FILE* file, const char* format, const char* elementName, std::list<T> list)
 {
-    fprintf(file, "<%s>", elementName);
+    fprintf(file, "<%s count=\"%lu\">", elementName, list.size());
     typename std::list<T>::const_iterator i;
-    for (i = list.begin(); i != list.end(); i++)
+    for (i = list.begin(); i != list.end(); ++i)
     {
         fprintf(file, format, *i);
     }
@@ -45,6 +51,7 @@ void fprintfMatrix4f(FILE* file, const float* m);
 
 /**
  * Writes binary data to the given file stream.
+ * 
  * @param value The value to be written
  * @param file The binary file stream.
  */
@@ -57,6 +64,7 @@ void write(unsigned short value, FILE* file);
 void write(bool value, FILE* file);
 void write(float value, FILE* file);
 void write(const float* values, int length, FILE* file);
+
 /**
  * Writes the length of the string and the string bytes to the binary file stream.
  */
@@ -66,6 +74,7 @@ void writeZero(FILE* file);
 
 /**
  * Writes the length of the list and writes each element value to the binary file stream.
+ * 
  * @param list The list to write.
  * @param file The binary file stream.
  */
@@ -76,7 +85,7 @@ void write(std::list<T> list, FILE* file)
     write(list.size(), file);
     // Then write each element
     typename std::list<T>::const_iterator i;
-    for (i = list.begin(); i != list.end(); i++)
+    for (i = list.begin(); i != list.end(); ++i)
     {
         write(*i, file);
     }
@@ -84,6 +93,7 @@ void write(std::list<T> list, FILE* file)
 
 /**
  * Writes the length of the vector and writes each element value to the binary file stream.
+ * 
  * @param vector The vector to write.
  * @param file The binary file stream.
  */
@@ -94,23 +104,35 @@ void write(std::vector<T> vector, FILE* file)
     write(vector.size(), file);
     // Then write each element
     typename std::vector<T>::const_iterator i;
-    for (i = vector.begin(); i != vector.end(); i++)
+    for (i = vector.begin(); i != vector.end(); ++i)
     {
         write(*i, file);
     }
 }
 
-
 /**
  * Skips over the string at the current file stream offset by moving the file position.
  * Assumes the current position points to the unsigned int length of the string.
  * The string is assumed to be a char array.
- * @param The file stream.
+ * 
+ * @param file The file stream.
  */
 void skipString(FILE* file);
 
 void skipUint(FILE* file);
 
+void writeVectorBinary(const Vector2& v, FILE* file);
+
+void writeVectorText(const Vector2& v, FILE* file);
+
+void writeVectorBinary(const Vector3& v, FILE* file);
+
+void writeVectorText(const Vector3& v, FILE* file);
+
+void writeVectorBinary(const Vector4& v, FILE* file);
+
+void writeVectorText(const Vector4& v, FILE* file);
+
 }
 
 #endif

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

@@ -43,7 +43,7 @@ bool GPBDecoder::validateHeading()
     const char identifier[] = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' };
 
     char heading[HEADING_SIZE];
-    for (size_t i = 0; i < HEADING_SIZE; i++)
+    for (size_t i = 0; i < HEADING_SIZE; ++i)
     {
         if (heading[i] != identifier[i])
         {
@@ -64,7 +64,7 @@ void GPBDecoder::readRefs()
     // read number of refs
     unsigned int refCount;
     assert(read(&refCount));
-    for (size_t i = 0; i < refCount; i++)
+    for (size_t i = 0; i < refCount; ++i)
     {
         readRef();
     }

+ 18 - 10
gameplay-encoder/src/GPBFile.cpp

@@ -30,21 +30,21 @@ void GPBFile::saveBinary(const std::string& filepath)
     fwrite(identifier, 1, sizeof(identifier), _file);
 
     // version
-    fwrite(VERSION, 1, sizeof(VERSION), _file);
+    fwrite(GPB_VERSION, 1, sizeof(GPB_VERSION), _file);
 
     // write refs
     _refTable.writeBinary(_file);
 
     // meshes
     write(_geometry.size(), _file);
-    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)->writeBinary(_file);
     }
 
     // Objects
     write(_objects.size(), _file);
-    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)->writeBinary(_file);
     }
@@ -64,13 +64,13 @@ void GPBFile::saveText(const std::string& filepath)
     _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);
     }
 
     // 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);
     }
@@ -155,8 +155,10 @@ bool GPBFile::idExists(const std::string& id)
 
 Camera* GPBFile::getCamera(const char* id)
 {
+    if (!id)
+        return NULL;
     // 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)
@@ -169,8 +171,10 @@ Camera* GPBFile::getCamera(const char* id)
 
 Light* GPBFile::getLight(const char* id)
 {
+    if (!id)
+        return NULL;
     // 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)
@@ -183,8 +187,10 @@ Light* GPBFile::getLight(const char* id)
 
 Mesh* GPBFile::getMesh(const char* id)
 {
+    if (!id)
+        return NULL;
     // 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)
@@ -197,8 +203,10 @@ Mesh* GPBFile::getMesh(const char* id)
 
 Node* GPBFile::getNode(const char* id)
 {
+    if (!id)
+        return NULL;
     // 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)
@@ -217,7 +225,7 @@ Animations* GPBFile::getAnimations()
 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)

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

@@ -21,7 +21,7 @@ namespace gameplay
  * Increment the version number when making a change that break binary compatibility.
  * [0] is major, [1] is minor.
  */
-const unsigned char VERSION[2] = {1, 1};
+const unsigned char GPB_VERSION[2] = {1, 1};
 
 /**
  * The GamePlay Binary file class handles writing the GamePlay Binary file.

+ 0 - 55
gameplay-encoder/src/LightInstance.cpp

@@ -1,55 +0,0 @@
-#include "Base.h"
-#include "LightInstance.h"
-
-namespace gameplay
-{
-
-LightInstance::LightInstance(void) : _ref(NULL)
-{
-
-}
-
-LightInstance::~LightInstance(void)
-{
-}
-
-unsigned int LightInstance::getTypeId(void) const
-{
-    return LIGHTINSTANCE_ID;
-}
-const char* LightInstance::getElementName(void) const
-{
-    return "LightInstance";
-}
-
-void LightInstance::writeBinary(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeBinary(file);
-    }
-}
-void LightInstance::writeText(FILE* file)
-{
-    if (_ref != NULL)
-    {
-        _ref->writeText(file);
-    }
-}
-
-Light* LightInstance::getLight() const
-{
-    return _ref;
-}
-
-void LightInstance::setLight(Light* light)
-{
-    _ref = light;
-}
-
-bool LightInstance::isAmbient() const
-{
-    return _ref != NULL && _ref->isAmbient();
-}
-
-}

+ 0 - 42
gameplay-encoder/src/LightInstance.h

@@ -1,42 +0,0 @@
-#ifndef LIGHTINSTANCE_H_
-#define LIGHTINSTANCE_H_
-
-#include "Object.h"
-#include "Light.h"
-
-namespace gameplay
-{
-
-class LightInstance : public Object
-{
-public:
-
-    /**
-     * Constructor.
-     */
-    LightInstance(void);
-
-    /**
-     * Destructor.
-     */
-    virtual ~LightInstance(void);
-
-    virtual unsigned int getTypeId(void) const;
-    virtual const char* getElementName(void) const;
-    virtual void writeBinary(FILE* file);
-    virtual void writeText(FILE* file);
-
-    Light* getLight() const;
-    void setLight(Light* light);
-
-    bool isAmbient() const;
-
-private:
-
-    Light* _ref;
-
-};
-
-}
-
-#endif

+ 221 - 10
gameplay-encoder/src/Mesh.cpp

@@ -38,6 +38,218 @@ void Mesh::writeBinary(FILE* file)
     writeBinaryObjects(parts, file);
 }
 
+/////////////////////////////////////////////////////////////
+// 
+// Fast, Minimum Storage Ray-Triangle Intersection
+// 
+// Authors: Tomas Möller, Ben Trumbore
+// http://jgt.akpeters.com/papers/MollerTrumbore97
+//
+// Implementation of algorithm from Real-Time Rendering (vol 1), pg. 305.
+//
+// Adapted slightly for use here.
+// 
+#define EPSILON 0.000001
+#define CROSS(dest,v1,v2) \
+          dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
+          dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
+          dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
+#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
+#define SUB(dest,v1,v2) \
+          dest[0]=v1[0]-v2[0]; \
+          dest[1]=v1[1]-v2[1]; \
+          dest[2]=v1[2]-v2[2]; 
+
+int
+intersect_triangle(const float orig[3], const float dir[3],
+                   const float vert0[3], const float vert1[3], const float vert2[3],
+                   float *t, float *u, float *v)
+{
+   float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+   float det,inv_det;
+
+   /* find vectors for two edges sharing vert0 */
+   SUB(edge1, vert1, vert0);
+   SUB(edge2, vert2, vert0);
+
+   /* begin calculating determinant - also used to calculate U parameter */
+   CROSS(pvec, dir, edge2);
+
+   /* if determinant is near zero, ray lies in plane of triangle */
+   det = DOT(edge1, pvec);
+
+   if (det > -EPSILON && det < EPSILON)
+     return 0;
+   inv_det = 1.0f / det;
+
+   /* calculate distance from vert0 to ray origin */
+   SUB(tvec, orig, vert0);
+
+   /* calculate U parameter and test bounds */
+   *u = DOT(tvec, pvec) * inv_det;
+   if (*u < 0.0 || *u > 1.0)
+     return 0;
+
+   /* prepare to test V parameter */
+   CROSS(qvec, tvec, edge1);
+
+   /* calculate V parameter and test bounds */
+   *v = DOT(dir, qvec) * inv_det;
+   if (*v < 0.0 || *u + *v > 1.0)
+     return 0;
+
+   /* calculate t, ray intersects triangle */
+   *t = DOT(edge2, qvec) * inv_det;
+
+   return 1;
+}
+
+// Performs an intersection test between a ray and the given mesh part
+// and stores the result in "point".
+bool intersect(const Vector3& rayOrigin, const Vector3& rayDirection, const std::vector<Vertex>& vertices, const std::vector<MeshPart*>& parts, Vector3* point)
+{
+    const float* orig = &rayOrigin.x;
+    const float* dir = &rayDirection.x;
+
+    for (unsigned int i = 0, partCount = parts.size(); i < partCount; ++i)
+    {
+        MeshPart* part = parts[i];
+
+        for (unsigned int j = 0, indexCount = part->getIndicesCount(); j < indexCount; j += 3)
+        {
+            const float* v0 = &vertices[part->getIndex( j )].position.x;
+            const float* v1 = &vertices[part->getIndex(j+1)].position.x;
+            const float* v2 = &vertices[part->getIndex(j+2)].position.x;
+
+            float t, u, v;
+            if (intersect_triangle(orig, dir, v0, v1, v2, &t, &u, &v))
+            {
+                // Found an intersection!
+                if (point)
+                {
+                    Vector3 rd(rayDirection);
+                    rd.scale(t);
+                    Vector3::add(rayOrigin, rd, point);
+                }
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+void Mesh::generateHeightmap(const char* filename)
+{
+    // Shoot rays down from a point just above the max Y position of the mesh.
+    // Compute ray-triangle intersection tests against the ray and this mesh to 
+    // generate heightmap data.
+    Vector3 rayOrigin(0, bounds.max.y + 10, 0);
+    Vector3 rayDirection(0, -1, 0);
+    Vector3 intersectionPoint;
+    int minX = (int)ceil(bounds.min.x);
+    int maxX = (int)floor(bounds.max.x);
+    int minZ = (int)ceil(bounds.min.z);
+    int maxZ = (int)floor(bounds.max.z);
+    int width = maxX - minX + 1;
+    int height = maxZ - minZ + 1;
+    float* heights = new float[width * height];
+    int index = 0;
+    float minHeight = FLT_MAX;
+    float maxHeight = FLT_MIN;
+    for (int z = minZ; z <= maxZ; z++)
+    {
+        rayOrigin.z = (float)z;
+        for (int x = minX; x <= maxX; x++)
+        {
+            float h;
+            rayOrigin.x = (float)x;
+            if (intersect(rayOrigin, rayDirection, vertices, parts, &intersectionPoint))
+            {
+                h = intersectionPoint.y;
+            }
+            else
+            {
+                h = 0;
+                fprintf(stderr, "Warning: Heightmap triangle intersection failed for (%d, %d).\n", x, z);
+            }
+            if (h < minHeight)
+                minHeight = h;
+            if (h > maxHeight)
+                maxHeight = h;
+            heights[index++] = h;
+        }
+    }
+    
+    // Normalize the max height value
+    maxHeight = maxHeight - minHeight;
+
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+    png_bytep row = NULL;
+
+    FILE* fp = fopen(filename, "wb");
+    if (fp == NULL)
+    {
+        fprintf(stderr, "Error: Failed to open file for writing: %s\n", filename);
+        goto error;
+    }
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (png_ptr == NULL)
+    {
+        fprintf(stderr, "Error: Write struct creation failed: %s\n", filename);
+        goto error;
+    }
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+    {
+        fprintf(stderr, "Error: Info struct creation failed: %s\n", filename);
+        goto error;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_write_info(png_ptr, info_ptr);
+
+    // Allocate memory for a single row of image data
+    row = (png_bytep)malloc(3 * width * sizeof(png_byte));
+
+    for (int y = 0; y < height; y++)
+    {
+        for (int x = 0; x < width; x++)
+        {
+            // Write height value normalized between 0-255 (between min and max height)
+            float h = heights[y*width + x];
+            float nh = (h - minHeight) / maxHeight;
+            png_byte b = (png_byte)(nh * 255.0f);
+            
+            int pos = x*3;
+            row[pos] = row[pos+1] = row[pos+2] = b;
+        }
+        png_write_row(png_ptr, row);
+    }
+
+    png_write_end(png_ptr, NULL);
+    DEBUGPRINT_VARG("> Saved heightmap: %s\n", filename);
+
+error:
+    if (heights)
+        delete[] heights;
+    if (fp)
+        fclose(fp);
+    if (row)
+        free(row);
+    if (info_ptr)
+        png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+    if (png_ptr)
+        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+
+}
+
 void Mesh::writeBinaryVertices(FILE* file)
 {
     if (vertices.size() > 0)
@@ -48,7 +260,7 @@ void Mesh::writeBinaryVertices(FILE* file)
         write(vertices.size() * vertex.byteSize(), file); // (vertex count) * (vertex size)
 
         // for each vertex
-        for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); i++)
+        for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
         {
             // Write this vertex
             i->writeBinary(file);
@@ -83,7 +295,7 @@ void Mesh::writeText(FILE* file)
 
     // for each Vertex
     fprintf(file, "<vertices count=\"%lu\">\n", vertices.size());
-    for (std::vector<Vertex>::iterator i = vertices.begin(); i != vertices.end(); i++)
+    for (std::vector<Vertex>::iterator i = vertices.begin(); i != vertices.end(); ++i)
     {
         i->writeText(file);
     }
@@ -93,19 +305,19 @@ void Mesh::writeText(FILE* file)
     computeBounds();
     fprintf(file, "<bounds>\n");
     fprintf(file, "<min>\n");
-    bounds.min.writeText(file);
+    writeVectorText(bounds.min, file);
     fprintf(file, "</min>\n");
     fprintf(file, "<max>\n");
-    bounds.max.writeText(file);
+    writeVectorText(bounds.max, file);
     fprintf(file, "</max>\n");
     fprintf(file, "<center>\n");
-    bounds.center.writeText(file);
+    writeVectorText(bounds.center, file);
     fprintf(file, "</center>\n");
     fprintf(file, "<radius>%f</radius>\n", bounds.radius);
     fprintf(file, "</bounds>\n");
 
     // for each MeshPart
-    for (std::vector<MeshPart*>::iterator i = parts.begin(); i != parts.end(); i++)
+    for (std::vector<MeshPart*>::iterator i = parts.begin(); i != parts.end(); ++i)
     {
         (*i)->writeText(file);
     }
@@ -165,7 +377,6 @@ unsigned int Mesh::getVertexIndex(const Vertex& vertex)
 {
     std::map<Vertex,unsigned int>::iterator it;
     it = vertexLookupTable.find(vertex);
-    // TODO: Remove it from the map because we are going to delete it
     return it->second;
 }
 
@@ -185,7 +396,7 @@ void Mesh::computeBounds()
     bounds.center.x = bounds.center.y = bounds.center.z = 0.0f;
     bounds.radius = 0.0f;
 
-    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); i++)
+    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
     {
         // Update min/max for this vertex
         if (i->position.x < bounds.min.x)
@@ -208,9 +419,9 @@ void Mesh::computeBounds()
 
     // Compute radius by looping through all points again and finding the max
     // distance between the center point and each vertex position
-    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); i++)
+    for (std::vector<Vertex>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
     {
-        float d = Vector3::distanceSquared(bounds.center, i->position);
+        float d = bounds.center.distanceSquared(i->position);
         if (d > bounds.radius)
         {
             bounds.radius = d;

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

@@ -60,6 +60,11 @@ public:
 
     unsigned int getVertexIndex(const Vertex& vertex);
 
+    /**
+     * Generates a heightmap with the given filename for this mesh.
+     */
+    void generateHeightmap(const char* filename);
+
     Model* model;
     std::vector<Vertex> vertices;
     std::vector<MeshPart*> parts;

+ 19 - 13
gameplay-encoder/src/MeshPart.cpp

@@ -6,7 +6,7 @@ namespace gameplay
 
 MeshPart::MeshPart(void) :
     _primitiveType(TRIANGLES),
-    _indexFormat(INDEX8)
+    _indexFormat(INDEX16)
 {
 }
 
@@ -18,30 +18,33 @@ unsigned int MeshPart::getTypeId(void) const
 {
     return MESHPART_ID;
 }
+
 const char* MeshPart::getElementName(void) const
 {
     return "MeshPart";
 }
+
 void MeshPart::writeBinary(FILE* file)
 {
     Object::writeBinary(file);
 
     write(_primitiveType, file);
-    write(_indexFormat, file);
+    write((unsigned int)_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);
     }
 }
+
 void MeshPart::writeText(FILE* file)
 {
     fprintElementStart(file);
     fprintfElement(file, "primitiveType", _primitiveType);
-    fprintfElement(file, "indexFormat", _indexFormat);
+    fprintfElement(file, "indexFormat", (unsigned int)_indexFormat);
     fprintfElement(file, "%d ", "indices", _indices);
     fprintElementEnd(file);
 }
@@ -68,14 +71,21 @@ unsigned int MeshPart::indexFormatSize() const
     {
     case INDEX32:
         return 4;
-    case INDEX16:
+    default: // INDEX16
         return 2;
-    case INDEX8:
-    default:
-        return 1;
     }
 }
 
+MeshPart::IndexFormat MeshPart::getIndexFormat() const
+{
+    return _indexFormat;
+}
+
+unsigned int MeshPart::getIndex(unsigned int i) const
+{
+    return _indices[i];
+}
+
 void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
 {
     switch (_indexFormat)
@@ -83,13 +93,9 @@ void MeshPart::writeBinaryIndex(unsigned int index, FILE* file)
     case INDEX32:
         write(index, file);
         break;
-    case INDEX16:
+    default: // INDEX16
         write((unsigned short)index, file);
         break;
-    case INDEX8:
-    default:
-        write((unsigned char)index, file);
-        break;
     }
 }
 

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

@@ -23,12 +23,10 @@ public:
 
     enum IndexFormat
     {
-        INDEX8  = 0x1401, // GL_UNSIGNED_BYTE
         INDEX16 = 0x1403, // GL_UNSIGNED_SHORT
         INDEX32 = 0x1405  // GL_UNSIGNED_INT
     };
 
-
     /**
      * Constructor.
      */
@@ -54,6 +52,16 @@ public:
      */
     size_t getIndicesCount() const;
 
+    /**
+     * Returns the index format.
+     */
+    IndexFormat getIndexFormat() const;
+
+    /**
+     * Gets the value of the index at the specificied location.
+     */
+    unsigned int getIndex(unsigned int i) const;
+
 private:
 
     /**
@@ -78,8 +86,9 @@ private:
     void writeBinaryIndex(unsigned int index, FILE* file);
 
 private:
+
     unsigned int _primitiveType;
-    unsigned int _indexFormat;
+    IndexFormat _indexFormat;
     std::vector<unsigned int> _indices;
 };
 

+ 5 - 4
gameplay-encoder/src/MeshSkin.cpp

@@ -7,6 +7,7 @@
 #include "Animations.h"
 #include "Transform.h"
 #include "../../gameplay/src/Curve.h"
+#include "Matrix.h"
 
 namespace gameplay
 {
@@ -14,7 +15,7 @@ namespace gameplay
 MeshSkin::MeshSkin(void) :
     _vertexInfluenceCount(0)
 {
-    setIdentityMatrix(_bindShape);
+    Matrix::setIdentity(_bindShape);
 }
 
 MeshSkin::~MeshSkin(void)
@@ -87,7 +88,7 @@ void MeshSkin::writeText(FILE* file)
 
 void MeshSkin::setBindShape(const float data[])
 {
-    for (int i = 0; i < 16; i++)
+    for (int i = 0; i < 16; ++i)
     {
         _bindShape[i] = data[i];
     }
@@ -115,7 +116,7 @@ void MeshSkin::setJoints(const std::vector<Node*>& list)
 
 void MeshSkin::setBindPoses(std::vector<Matrix>& list)
 {
-    for (std::vector<Matrix>::iterator i = list.begin(); i != list.end(); i++)
+    for (std::vector<Matrix>::iterator i = list.begin(); i != list.end(); ++i)
     {
         _bindPoses.push_back(*i);
     }
@@ -291,7 +292,7 @@ void MeshSkin::computeBounds()
         {
         case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
             curve = new Curve(keyCount, 10);
-            curve->addQuaternionOffset(3);
+            curve->setQuaternionOffset(3);
             break;
         }
         if (curve == NULL)

+ 14 - 9
gameplay-encoder/src/Model.cpp

@@ -5,7 +5,7 @@ namespace gameplay
 {
 
 Model::Model(void) :
-    _ref(NULL),
+    _mesh(NULL),
     _meshSkin(NULL)
 {
 }
@@ -27,9 +27,9 @@ void Model::writeBinary(FILE* file)
     Object::writeBinary(file);
 
     // xref:Mesh
-    if (_ref != NULL)
+    if (_mesh != NULL)
     {
-        _ref->writeBinaryXref(file);
+        _mesh->writeBinaryXref(file);
     }
     else
     {
@@ -56,9 +56,9 @@ void Model::writeText(FILE* file)
     // Compute mesh bounds before writing
 
     fprintElementStart(file);
-    if (_ref != NULL)
+    if (_mesh != NULL)
     {
-        fprintfElement(file, "ref", _ref->getId());
+        fprintfElement(file, "ref", _mesh->getId());
     }
     if (_meshSkin != NULL)
     {
@@ -72,18 +72,23 @@ MeshSkin* Model::getSkin()
     return _meshSkin;
 }
 
+Mesh* Model::getMesh()
+{
+    return _mesh;
+}
+
 void Model::setMesh(Mesh* mesh)
 {
-    _ref = mesh;
+    _mesh = mesh;
 
     if (mesh)
     {
         mesh->model = this;
     }
 
-    if (_ref && _meshSkin)
+    if (_mesh && _meshSkin)
     {
-        _meshSkin->_mesh = _ref;
+        _meshSkin->_mesh = _mesh;
     }
 }
 
@@ -93,7 +98,7 @@ void Model::setSkin(MeshSkin* skin)
 
     if (_meshSkin)
     {
-        _meshSkin->_mesh = _ref;
+        _meshSkin->_mesh = _mesh;
     }
 }
 

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

@@ -28,13 +28,14 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
 
+    Mesh* getMesh();
     void setMesh(Mesh* mesh);
     MeshSkin* getSkin();
     void setSkin(MeshSkin* skin);
 
 private:
 
-    Mesh* _ref;
+    Mesh* _mesh;
     MeshSkin* _meshSkin;
     std::list<Material*> _materials;
 };

+ 41 - 15
gameplay-encoder/src/Node.cpp

@@ -1,5 +1,7 @@
 #include "Base.h"
 #include "Node.h"
+#include "Matrix.h"
+#include "EncoderArguments.h"
 
 #define NODE 1
 #define JOINT 2
@@ -13,7 +15,6 @@ Node::Node(void) :
     _firstChild(NULL), _lastChild(NULL), _parent(NULL),
     _camera(NULL), _light(NULL), _model(NULL), _joint(false)
 {
-    setIdentityMatrix(_transform.m);
 }
 
 Node::~Node(void)
@@ -73,7 +74,10 @@ void Node::writeBinary(FILE* file)
     {
         writeZero(file);
     }
+
+    generateHeightmap();
 }
+
 void Node::writeText(FILE* file)
 {
     if (isJoint())
@@ -109,6 +113,29 @@ void Node::writeText(FILE* file)
         _model->writeText(file);
     }
     fprintElementEnd(file);
+
+    generateHeightmap();
+}
+
+void Node::generateHeightmap()
+{
+    // Is this node flagged to have a heightmap generated for it?
+    const std::vector<std::string>& heightmapNodes = EncoderArguments::getInstance()->getHeightmapNodeIds();
+    if (std::find(heightmapNodes.begin(), heightmapNodes.end(), getId()) != heightmapNodes.end())
+    {
+        Mesh* mesh = _model ? _model->getMesh() : NULL;
+        if (mesh)
+        {
+            DEBUGPRINT_VARG("> Generating heightmap for node: %s\n", getId().c_str());
+
+            std::string heightmapFilename(EncoderArguments::getInstance()->getOutputPath());
+            heightmapFilename += "/heightmap_";
+            heightmapFilename += getId();
+            heightmapFilename += ".png";
+
+            mesh->generateHeightmap(heightmapFilename.c_str());
+        }
+    }
 }
 
 void Node::addChild(Node* child)
@@ -220,14 +247,16 @@ Node* Node::getParent() const
     return _parent;
 }
 
-void Node::setCameraInstance(CameraInstance* cameraInstance)
+void Node::setCamera(Camera* camera)
 {
-    _camera = cameraInstance;
+    _camera = camera;
 }
-void Node::setLightInstance(LightInstance* lightInstance)
+
+void Node::setLight(Light* light)
 {
-    _light = lightInstance;
+    _light = light;
 }
+
 void Node::setModel(Model* model)
 {
     _model = model;
@@ -257,6 +286,11 @@ const Matrix& Node::getWorldMatrix() const
     return _worldTransform;
 }
 
+void Node::resetTransformMatrix()
+{
+    Matrix::setIdentity(_transform.m);
+}
+
 void Node::setIsJoint(bool value)
 {
     _joint = value;
@@ -269,20 +303,12 @@ bool Node::isJoint()
 
 Camera* Node::getCamera() const
 {
-    if (_camera)
-    {
-        return _camera->getCamera();
-    }
-    return NULL;
+    return _camera;
 }
 
 Light* Node::getLight() const
 {
-    if (_light)
-    {
-        return _light->getLight();
-    }
-    return NULL;
+    return _light;
 }
 
 Model* Node::getModel() const

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

@@ -2,8 +2,8 @@
 #define NODE_H_
 
 #include "Object.h"
-#include "CameraInstance.h"
-#include "LightInstance.h"
+#include "Camera.h"
+#include "Light.h"
 #include "Model.h"
 
 namespace gameplay
@@ -138,8 +138,13 @@ public:
      */
     const Matrix& getWorldMatrix() const;
 
-    void setCameraInstance(CameraInstance* cameraInstance);
-    void setLightInstance(LightInstance* lightInstance);
+    /*
+     * Resets the node's transform matrix to the identity matrix.
+     */
+    void resetTransformMatrix();
+
+    void setCamera(Camera* camera);
+    void setLight(Light* light);
     void setModel(Model* model);
 
     /**
@@ -166,6 +171,12 @@ public:
     
 private:
 
+    /**
+     * Internal method to generate heightmap for a node's mesh data
+     * if the node was flagged as a heightmap via encoder arguments.
+     */
+    void generateHeightmap();
+
     Matrix _transform;
     mutable Matrix _worldTransform;
 
@@ -176,8 +187,8 @@ private:
     Node* _lastChild;
     Node* _parent;
 
-    CameraInstance* _camera;
-    LightInstance* _light;
+    Camera* _camera;
+    Light* _light;
     Model* _model;
 
     bool _joint;

+ 2 - 4
gameplay-encoder/src/Object.h

@@ -22,8 +22,6 @@ public:
         ANIMATION_ID = 4,
         ANIMATIONCHANNEL_ID = 5,
         NODEINSTANCE_ID = 8,
-        CAMERAINSTANCE_ID = 9,
-        LIGHTINSTANCE_ID = 10,
         MODEL_ID = 11,
         MATERIAL_ID = 16,
         EFFECT_ID = 17,
@@ -113,7 +111,7 @@ public:
         write(list.size(), file);
         // Then write each element
         typename std::list<T>::const_iterator i;
-        for (i = list.begin(); i != list.end(); i++)
+        for (i = list.begin(); i != list.end(); ++i)
         {
             (*i)->writeBinary(file);
         }
@@ -129,7 +127,7 @@ public:
         write(vector.size(), file);
         // Then write each element
         typename std::vector<T>::const_iterator i;
-        for (i = vector.begin(); i != vector.end(); i++)
+        for (i = vector.begin(); i != vector.end(); ++i)
         {
             (*i)->writeBinary(file);
         }

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

@@ -31,7 +31,7 @@ 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++ )
+    for ( std::map<std::string, Reference>::iterator i=_table.begin() ; i != _table.end(); ++i)
     {
         i->second.writeBinary(file);
     }
@@ -40,7 +40,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);
     }
@@ -49,7 +49,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);

+ 10 - 3
gameplay-encoder/src/Scene.cpp

@@ -43,7 +43,7 @@ void Scene::writeBinary(FILE* 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);
     }
@@ -67,7 +67,7 @@ void Scene::setActiveCameraNode(Node* 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,7 +81,7 @@ 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);
     }
@@ -91,6 +91,13 @@ void Scene::calcAmbientColor()
     _ambientColor[2] = std::min(values[2], 1.0f);
 }
 
+void Scene::setAmbientColor(float red, float green, float blue)
+{
+    _ambientColor[0] = red;
+    _ambientColor[1] = green;
+    _ambientColor[2] = blue;
+}
+
 void Scene::calcAmbientColor(const Node* node, float* values) const
 {
     if (!node)

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

@@ -50,6 +50,11 @@ public:
      */
     void calcAmbientColor();
 
+    /**
+     * Sets the scene's ambient color.
+     */
+    void setAmbientColor(float red, float green, float blue);
+
 private:
 
     /**

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

@@ -89,7 +89,7 @@ bool equalsIgnoreCase(const std::string& a, const char* b)
     {
         return false;
     }
-    for (size_t i = 0; i < bLength; i++)
+    for (size_t i = 0; i < bLength; ++i)
     {
         if (lowercase(a[i]) != lowercase(b[i]))
         {
@@ -99,4 +99,23 @@ bool equalsIgnoreCase(const std::string& a, const char* b)
     return true;
 }
 
+std::string getFilenameFromFilePath(const std::string& filepath)
+{
+    if (filepath.find_last_of("/") != std::string::npos)
+    {
+        return filepath.substr(filepath.find_last_of("/")+1);
+    }
+    return "";
+}
+
+
+std::string getFilenameNoExt(const std::string& filename)
+{
+    if (filename.find_last_of(".") != std::string::npos)
+    {
+        return filename.substr(0, filename.find_last_of("."));
+    }
+    return filename;
+}
+
 }

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

@@ -17,6 +17,10 @@ bool equals(const std::string& a, const char* b);
  */
 bool equalsIgnoreCase(const std::string& a, const char* b);
 
+std::string getFilenameFromFilePath(const std::string& filepath);
+
+std::string getFilenameNoExt(const std::string& filename);
+
 }
 
 #endif

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

@@ -10,7 +10,7 @@ void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned c
     // offset dst bitmap by x,y.
     dstBitmap +=  (x + (y * dstWidth));
 
-    for (int i = 0; i < srcHeight; i++)
+    for (int i = 0; i < srcHeight; ++i)
     {
         memcpy(dstBitmap, (const void*)srcBitmap, srcWidth);
         srcBitmap += srcWidth;
@@ -91,7 +91,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     int rowSize = 0; // Stores the total number of rows required to all glyphs.
     
     // Find the width of the image.
-    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
+    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
     {
         // Load glyph image into the slot (erase previous one)
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
@@ -136,7 +136,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
 
         // Find out the squared texture size that would fit all the require font glyphs.
         i = 0;
-        for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
+        for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
         {
             // Load glyph image into the slot (erase the previous one).
             error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
@@ -203,7 +203,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     penY = 0;
     row = 0;
     i = 0;
-    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ascii++)
+    for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
     {
         // Load glyph image into the slot (erase the previous one).
         error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
@@ -268,7 +268,7 @@ int writeFont(const char* filename, unsigned int fontSize, const char* id, bool
     // File header and version.
     char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
     fwrite(fileHeader, sizeof(char), 9, gpbFp);
-    fwrite(gameplay::VERSION, sizeof(char), 2, gpbFp);
+    fwrite(gameplay::GPB_VERSION, sizeof(char), 2, gpbFp);
 
     // Write Ref table (for a single font)
     writeUint(gpbFp, 1);                // Ref[] count

+ 20 - 16
gameplay-encoder/src/Transform.h

@@ -14,37 +14,41 @@ public:
          * Scale animation property. Data=sx,sy,sz
          */
         ANIMATE_SCALE = 1,
-        ANIMATE_SCALE_X,
-        ANIMATE_SCALE_Y,
-        ANIMATE_SCALE_Z,
-        ANIMATE_SCALE_XY,
-        ANIMATE_SCALE_XZ,
-        ANIMATE_SCALE_YZ,
+        ANIMATE_SCALE_X = 2,
+        ANIMATE_SCALE_Y = 3,
+        ANIMATE_SCALE_Z = 4,
+        ANIMATE_SCALE_XY = 5,
+        ANIMATE_SCALE_XZ = 6,
+        ANIMATE_SCALE_YZ = 7,
 
         /**
          * Rotation animation property. Data=qx,qy,qz,qw (as quaternion).
          */
-        ANIMATE_ROTATE,
+        ANIMATE_ROTATE = 8,
 
         /**
          * Translation animation property. Data=tx,ty,tz
          */
-        ANIMATE_TRANSLATE,
-        ANIMATE_TRANSLATE_X,
-        ANIMATE_TRANSLATE_Y,
-        ANIMATE_TRANSLATE_Z,
-        ANIMATE_TRANSLATE_XY,
-        ANIMATE_TRANSLATE_XZ,
-        ANIMATE_TRANSLATE_YZ,
+        ANIMATE_TRANSLATE = 9,
+        ANIMATE_TRANSLATE_X = 10,
+        ANIMATE_TRANSLATE_Y = 11,
+        ANIMATE_TRANSLATE_Z = 12,
+        ANIMATE_TRANSLATE_XY = 13,
+        ANIMATE_TRANSLATE_XZ = 14,
+        ANIMATE_TRANSLATE_YZ = 15,
 
         /**
          * Rotation + Translation animation property(Rigid Body). Data=qx,qy,qz,qw,tx,ty,tz
          */
-        ANIMATE_ROTATE_TRANSLATE,
+        ANIMATE_ROTATE_TRANSLATE = 16,
         /**
          * Scale, Rotation + Translation animation property. Data=sx,sy,sz,qx,qy,qz,qw,tx,ty,tz
          */
-        ANIMATE_SCALE_ROTATE_TRANSLATE
+        ANIMATE_SCALE_ROTATE_TRANSLATE = 17,
+
+        ANIMATE_ROTATE_X = 18,
+        ANIMATE_ROTATE_Y = 19,
+        ANIMATE_ROTATE_Z = 20
     };
 };
 

+ 15 - 61
gameplay-encoder/src/Vector2.cpp

@@ -1,6 +1,5 @@
 #include "Base.h"
 #include "Vector2.h"
-#include "FileIO.h"
 
 namespace gameplay
 {
@@ -10,90 +9,76 @@ Vector2::Vector2()
 {
 }
 
-
 Vector2::Vector2(float x, float y)
 {
     set(x, y);
 }
 
-
 Vector2::Vector2(float* array)
 {
     set(array);
 }
 
-
 Vector2::Vector2(const Vector2& p1, const Vector2& p2)
 {
     set(p1, p2);
 }
 
-
 Vector2::Vector2(const Vector2& copy)
 {
     set(copy);
 }
 
-
 Vector2::~Vector2()
 {
 }
 
-
 const Vector2& Vector2::zero()
 {
-    static Vector2* value = new Vector2(0.0f, 0.0f);
-    return *value;
+    static Vector2 value(0.0f, 0.0f);
+    return value;
 }
 
-
 const Vector2& Vector2::one()
 {
-    static Vector2* value = new Vector2(1.0f, 1.0f);
-    return *value;
+    static Vector2 value(1.0f, 1.0f);
+    return value;
 }
 
-
 const Vector2& Vector2::unitX()
 {
-    static Vector2* value = new Vector2(1.0f, 0.0f);
-    return *value;
+    static Vector2 value(1.0f, 0.0f);
+    return value;
 }
 
-
 const Vector2& Vector2::unitY()
 {
-    static Vector2* value = new Vector2(0.0f, 1.0f);
-    return *value;
+    static Vector2 value(0.0f, 1.0f);
+    return value;
 }
 
-
 bool Vector2::isZero() const
 {
     return x == 0.0f && y == 0.0f;
 }
 
-
 bool Vector2::isOne() const
 {
     return x == 1.0f && y == 1.0f;
 }
 
-
 float Vector2::angle(const Vector2& v1, const Vector2& v2)
 {
     float dz = v1.x * v2.y - v1.y * v2.x;
     return atan2f(fabsf(dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 
-
 void Vector2::add(const Vector2& v)
 {
     x += v.x;
     y += v.y;
 }
 
-
 void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
 {
     assert(dst);
@@ -102,7 +87,6 @@ void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst)
     dst->y = v1.y + v2.y;
 }
 
-
 void Vector2::clamp(const Vector2& min, const Vector2& max)
 {
     assert(!( min.x > max.x || min.y > max.y ));
@@ -120,13 +104,12 @@ void Vector2::clamp(const Vector2& min, const Vector2& max)
         y = max.y;
 }
 
-
 void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Vector2* dst)
 {
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y ));
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     if ( dst->x < min.x )
         dst->x = min.x;
@@ -141,8 +124,7 @@ void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Ve
         dst->y = max.y;
 }
 
-
-float Vector2::distance(const Vector2& v)
+float Vector2::distance(const Vector2& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
@@ -150,52 +132,44 @@ float Vector2::distance(const Vector2& v)
     return sqrt(dx * dx + dy * dy);
 }
 
-
-float Vector2::distanceSquared(const Vector2& v)
+float Vector2::distanceSquared(const Vector2& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
     return (dx * dx + dy * dy);
 }
 
-
 float Vector2::dot(const Vector2& v)
 {
     return (x * v.x + y * v.y);
 }
 
-
 float Vector2::dot(const Vector2& v1, const Vector2& v2)
 {
     return (v1.x * v2.x + v1.y * v2.y);
 }
 
-
-float Vector2::length()
+float Vector2::length() const
 {
     return sqrt(x * x + y * y);
 }
 
-
-float Vector2::lengthSquared()
+float Vector2::lengthSquared() const
 {
     return (x * x + y * y);
 }
 
-
 void Vector2::negate()
 {
     x = -x;
     y = -y;
 }
 
-
 void Vector2::normalize()
 {
     normalize(this);
 }
 
-
 void Vector2::normalize(Vector2* dst)
 {
     assert(dst);
@@ -207,12 +181,12 @@ void Vector2::normalize(Vector2* dst)
     }
 
     float n = x * x + y * y;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
         return;
 
@@ -221,21 +195,18 @@ void Vector2::normalize(Vector2* dst)
     dst->y *= n;
 }
 
-
 void Vector2::scale(float scalar)
 {
     x *= scalar;
     y *= scalar;
 }
 
-
 void Vector2::scale(const Vector2& scale)
 {
     x *= scale.x;
     y *= scale.y;
 }
 
-
 void Vector2::rotate(const Vector2& point, float angle)
 {
     float sinAngle = sin(angle);
@@ -257,14 +228,12 @@ void Vector2::rotate(const Vector2& point, float angle)
     }
 }
 
-
 void Vector2::set(float x, float y)
 {
     this->x = x;
     this->y = y;
 }
 
-
 void Vector2::set(float* array)
 {
     assert(array);
@@ -273,28 +242,24 @@ void Vector2::set(float* array)
     y = array[1];
 }
 
-
 void Vector2::set(const Vector2& v)
 {
     this->x = v.x;
     this->y = v.y;
 }
 
-
 void Vector2::set(const Vector2& p1, const Vector2& p2)
 {
      x = p2.x - p1.x;
      y = p2.y - p1.y;
 }
 
-
 void Vector2::subtract(const Vector2& v)
 {
     x -= v.x;
     y -= v.y;
 }
 
-
 void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
 {
     assert(dst);
@@ -303,15 +268,4 @@ void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
     dst->y = v1.y - v2.y;
 }
 
-void Vector2::writeBinary(FILE* file) const
-{
-    write(x, file);
-    write(y, file);
-}
-
-void Vector2::writeText(FILE* file) const
-{
-    fprintf(file, "%f %f\n", x, y);
-}
-
 }

+ 108 - 33
gameplay-encoder/src/Vector2.h

@@ -4,7 +4,6 @@
 namespace gameplay
 {
 
-// Forward declare
 class Matrix;
 
 /**
@@ -65,44 +64,44 @@ public:
     ~Vector2();
 
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      * @return The 2-element vector of 0s.
      */
     static const Vector2& zero();
 
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      * @return The 2-element vector of 1s.
      */
     static const Vector2& one();
 
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      * @return The 2-element unit vector along the x axis.
      */
     static const Vector2& unitX();
 
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      * @return The 2-element unit vector along the y axis.
      */
     static const Vector2& unitY();
 
     /**
-     * Is this vector the all zeros.
+     * Indicates whether this vector contains all zeros.
      *
-     * @return true if all zeros, false if otherwise.
+     * @return true if this vector contains all zeros, false otherwise.
      */
     bool isZero() const;
 
     /**
-     * Is this vector all ones.
+     * Indicates whether this vector contains all ones.
      *
-     * @return true if all ones, false if otherwise.
+     * @return true if this vector contains all ones, false otherwise.
      */
     bool isOne() const;
 
@@ -112,7 +111,7 @@ public:
      * @param v1 The first vector.
      * @param v2 The second vector.
      * 
-     * @return The angle between the two vectors, in radians.
+     * @return The angle between the two vectors (in radians).
      */
     static float angle(const Vector2& v1, const Vector2& v2);
 
@@ -156,9 +155,10 @@ public:
      * @param v The other vector.
      * 
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      */
-    float distance(const Vector2& v);
+    float distance(const Vector2& v) const;
 
     /**
      * Returns the squared distance between this vector and v.
@@ -171,9 +171,10 @@ public:
      * @param v The other vector.
      * 
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      */
-    float distanceSquared(const Vector2& v);
+    float distanceSquared(const Vector2& v) const;
 
     /**
      * Returns the dot product of this vector and the specified vector.
@@ -198,9 +199,10 @@ public:
      * Computes the length of this vector.
      *
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      */
-    float length();
+    float length() const;
 
     /**
      * Returns the squared length of this vector.
@@ -211,9 +213,10 @@ public:
      * instead of length.
      *
      * @return The squared length of the vector.
+     * 
      * @see length
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
     /**
      * Negates this vector.
@@ -238,7 +241,7 @@ public:
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
     void normalize(Vector2* dst);
 
@@ -260,7 +263,7 @@ public:
      * Rotates this vector by angle (specified in radians) around the given point.
      *
      * @param point The point to rotate around.
-     * @param angle The angle to rotate by, in radians.
+     * @param angle The angle to rotate by (in radians).
      */
     void rotate(const Vector2& point, float angle);
 
@@ -288,12 +291,15 @@ public:
 
     /**
      * Sets this vector to the directional vector between the specified points.
+     * 
+     * @param p1 The first point.
+     * @param p2 The second point.
      */
     void set(const Vector2& p1, const Vector2& p2);
 
     /**
      * Subtracts this vector and the specified vector as (this - v)
-     * and stores the result in this.
+     * and stores the result in this vector.
      *
      * @param v The vector to subtract.
      */
@@ -309,30 +315,99 @@ public:
      */
     static void subtract(const Vector2& v1, const Vector2& v2, Vector2* dst);
 
-    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
-    {
-        return x==v.x && y==v.y;
-    }
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector2 operator+(const Vector2& v);
+
+    /**
+     * Adds the given vector to this vector.
+     * 
+     * @param v The vector to add.
+     * @return This vector, after the addition occurs.
+     */
+    inline Vector2& operator+=(const Vector2& v);
 
     /**
-     * Writes this vector to the binary file stream.
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
      */
-    void writeBinary(FILE* file) const;
+    inline Vector2 operator-(const Vector2& v);
 
     /**
-     * Writes this vector to a text file stream.
+     * Subtracts the given vector from this vector.
+     * 
+     * @param v The vector to subtract.
+     * @return This vector, after the subtraction occurs.
      */
-    void writeText(FILE* file) const;
+    inline Vector2& operator-=(const Vector2& v);
+
+    /**
+     * Calculates the negation of this vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @return The negation of this vector.
+     */
+    inline Vector2 operator-();
+
+    /**
+     * Calculates the scalar product of this vector with the given value.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param x The value to scale by.
+     * @return The scaled vector.
+     */
+    inline Vector2 operator*(float x);
+
+    /**
+     * Scales this vector by the given value.
+     * 
+     * @param x The value to scale by.
+     * @return This vector, after the scale occurs.
+     */
+    inline Vector2& operator*=(float x);
+
+    /**
+     * Determines if this vector is less than the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is less than the given vector, false otherwise.
+     */
+    inline bool operator<(const Vector2& v) const;
+
+    /**
+     * Determines if this vector is equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is equal to the given vector, false otherwise.
+     */
+    inline bool operator==(const Vector2& v) const;
 };
 
+/**
+ * Calculates the scalar product of the given vector with the given value.
+ * 
+ * @param x The value to scale by.
+ * @param v The vector to scale.
+ * @return The scaled vector.
+ */
+inline Vector2 operator*(float x, const Vector2& v);
+
 }
 
+#include "Vector2.inl"
+
 #endif

+ 77 - 0
gameplay-encoder/src/Vector2.inl

@@ -0,0 +1,77 @@
+/** 
+ * Vector2.inl
+ */
+
+#include "Vector2.h"
+
+namespace gameplay
+{
+
+inline Vector2 Vector2::operator+(const Vector2& v)
+{
+    Vector2 result(*this);
+    result.add(v);
+    return result;
+}
+
+inline Vector2& Vector2::operator+=(const Vector2& v)
+{
+    add(v);
+    return *this;
+}
+
+inline Vector2 Vector2::operator-(const Vector2& v)
+{
+    Vector2 result(*this);
+    result.subtract(v);
+    return result;
+}
+
+inline Vector2& Vector2::operator-=(const Vector2& v)
+{
+    subtract(v);
+    return *this;
+}
+
+inline Vector2 Vector2::operator-()
+{
+    Vector2 result(*this);
+    result.negate();
+    return result;
+}
+
+inline Vector2 Vector2::operator*(float x)
+{
+    Vector2 result(*this);
+    result.scale(x);
+    return result;
+}
+
+inline Vector2& Vector2::operator*=(float x)
+{
+    scale(x);
+    return *this;
+}
+
+inline bool Vector2::operator<(const Vector2& v) const
+{
+    if (x == v.x)
+    {
+        return y < v.y;
+    }
+    return x < v.x;
+}
+
+inline bool Vector2::operator==(const Vector2& v) const
+{
+    return x==v.x && y==v.y;
+}
+
+inline Vector2 operator*(float x, const Vector2& v)
+{
+    Vector2 result(v);
+    result.scale(x);
+    return result;
+}
+
+}

+ 31 - 72
gameplay-encoder/src/Vector3.cpp

@@ -1,6 +1,5 @@
 #include "Base.h"
 #include "Vector3.h"
-#include "FileIO.h"
 
 namespace gameplay
 {
@@ -10,77 +9,80 @@ Vector3::Vector3()
 {
 }
 
-
 Vector3::Vector3(float x, float y, float z)
 {
     set(x, y, z);
 }
 
-
 Vector3::Vector3(float* array)
 {
     set(array);
 }
 
-
 Vector3::Vector3(const Vector3& p1, const Vector3& p2)
 {
     set(p1, p2);
 }
 
-
 Vector3::Vector3(const Vector3& copy)
 {
     set(copy);
 }
 
+Vector3 Vector3::fromColor(unsigned int color)
+{
+    float components[3];
+    int componentIndex = 0;
+    for (int i = 2; i >= 0; --i)
+    {
+        int component = (color >> i*8) & 0x0000ff;
+
+        components[componentIndex++] = static_cast<float>(component) / 255.0f;
+    }
+
+    Vector3 value(components);
+    return value;
+}
 
 Vector3::~Vector3()
 {
 }
 
-
 const Vector3& Vector3::zero()
 {
-    static Vector3* value = new Vector3(0.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector3 value(0.0f, 0.0f, 0.0f);
+    return value;
 }
 
-
 const Vector3& Vector3::one()
 {
-    static Vector3* value = new Vector3(1.0f, 1.0f, 1.0f);
-    return *value;
+    static Vector3 value(1.0f, 1.0f, 1.0f);
+    return value;
 }
 
-
 const Vector3& Vector3::unitX()
 {
-    static Vector3* value = new Vector3(1.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector3 value(1.0f, 0.0f, 0.0f);
+    return value;
 }
 
-
 const Vector3& Vector3::unitY()
 {
-    static Vector3* value = new Vector3(0.0f, 1.0f, 0.0f);
-    return *value;
+    static Vector3 value(0.0f, 1.0f, 0.0f);
+    return value;
 }
 
-
 const Vector3& Vector3::unitZ()
 {
-    static Vector3* value = new Vector3(0.0f, 0.0f, 1.0f);
-    return *value;
+    static Vector3 value(0.0f, 0.0f, 1.0f);
+    return value;
 }
 
-
 bool Vector3::isZero() const
 {
     return x == 0.0f && y == 0.0f && z == 0.0f;
 }
 
-
 bool Vector3::isOne() const
 {
     return x == 1.0f && y == 1.0f && z == 1.0f;
@@ -95,7 +97,6 @@ float Vector3::angle(const Vector3& v1, const Vector3& v2)
     return atan2f(sqrt(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 
-
 void Vector3::add(const Vector3& v)
 {
     x += v.x;
@@ -103,7 +104,6 @@ void Vector3::add(const Vector3& v)
     z += v.z;
 }
 
-
 void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
     assert(dst);
@@ -113,7 +113,6 @@ void Vector3::add(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = v1.z + v2.z;
 }
 
-
 void Vector3::clamp(const Vector3& min, const Vector3& max)
 {
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z));
@@ -137,13 +136,12 @@ void Vector3::clamp(const Vector3& min, const Vector3& max)
         z = max.z;
 }
 
-
 void Vector3::clamp(const Vector3& v, const Vector3& min, const Vector3& max, Vector3* dst)
 {
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z));
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     if ( dst->x < min.x )
         dst->x = min.x;
@@ -165,7 +163,6 @@ void Vector3::clamp(const Vector3& v, const Vector3& min, const Vector3& max, Ve
         dst->z = max.z;
 }
 
-
 void Vector3::cross(const Vector3& v)
 {
     float tx = (y * v.z) - (z * v.y);
@@ -176,7 +173,6 @@ void Vector3::cross(const Vector3& v)
     z = tz;
 }
 
-
 void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
     assert(dst);
@@ -189,8 +185,7 @@ void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = z;
 }
 
-
-float Vector3::distance(const Vector3& v)
+float Vector3::distance(const Vector3& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
@@ -199,8 +194,7 @@ float Vector3::distance(const Vector3& v)
     return sqrt(dx * dx + dy * dy + dz * dz);
 }
 
-
-float Vector3::distanceSquared(const Vector3& v)
+float Vector3::distanceSquared(const Vector3& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
@@ -209,31 +203,26 @@ float Vector3::distanceSquared(const Vector3& v)
     return (dx * dx + dy * dy + dz * dz);
 }
 
-
 float Vector3::dot(const Vector3& v)
 {
     return (x * v.x + y * v.y + z * v.z);
 }
 
-
 float Vector3::dot(const Vector3& v1, const Vector3& v2)
 {
     return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
 }
 
-
-float Vector3::length()
+float Vector3::length() const
 {
     return sqrt(x * x + y * y + z * z);
 }
 
-
-float Vector3::lengthSquared()
+float Vector3::lengthSquared() const
 {
     return (x * x + y * y + z * z);
 }
 
-
 void Vector3::negate()
 {
     x = -x;
@@ -241,13 +230,11 @@ void Vector3::negate()
     z = -z;
 }
 
-
 void Vector3::normalize()
 {
     normalize(this);
 }
 
-
 void Vector3::normalize(Vector3* dst) const
 {
     assert(dst);
@@ -260,12 +247,12 @@ void Vector3::normalize(Vector3* dst) const
     }
 
     float n = x * x + y * y + z * z;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
         return;
 
@@ -275,7 +262,6 @@ void Vector3::normalize(Vector3* dst) const
     dst->z *= n;
 }
 
-
 void Vector3::scale(float scalar)
 {
     x *= scalar;
@@ -283,7 +269,6 @@ void Vector3::scale(float scalar)
     z *= scalar;
 }
 
-
 void Vector3::set(float x, float y, float z)
 {
     this->x = x;
@@ -291,7 +276,6 @@ void Vector3::set(float x, float y, float z)
     this->z = z;
 }
 
-
 void Vector3::set(float* array)
 {
     assert(array);
@@ -301,7 +285,6 @@ void Vector3::set(float* array)
     z = array[2];
 }
 
-
 void Vector3::set(const Vector3& v)
 {
     this->x = v.x;
@@ -309,7 +292,6 @@ void Vector3::set(const Vector3& v)
     this->z = v.z;
 }
 
-
 void Vector3::set(const Vector3& p1, const Vector3& p2)
 {
     x = p2.x - p1.x;
@@ -317,7 +299,6 @@ void Vector3::set(const Vector3& p1, const Vector3& p2)
     z = p2.z - p1.z;
 }
 
-
 void Vector3::subtract(const Vector3& v)
 {
     x -= v.x;
@@ -325,7 +306,6 @@ void Vector3::subtract(const Vector3& v)
     z -= v.z;
 }
 
-
 void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
     assert(dst);
@@ -335,25 +315,4 @@ void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = v1.z - v2.z;
 }
 
-float Vector3::distanceSquared(const Vector3& v1, const Vector3& v2)
-{
-    float dx = v2.x - v1.x;
-    float dy = v2.y - v1.y;
-    float dz = v2.z - v1.z;
-
-    return (dx * dx + dy * dy + dz * dz);
-}
-
-void Vector3::writeBinary(FILE* file) const
-{
-    write(x, file);
-    write(y, file);
-    write(z, file);
-}
-
-void Vector3::writeText(FILE* file) const
-{
-    fprintf(file, "%f %f %f\n", x, y, z);
-}
-
 }

+ 117 - 39
gameplay-encoder/src/Vector3.h

@@ -4,7 +4,6 @@
 namespace gameplay
 {
 
-// Forward declare
 class Matrix;
 class Quaternion;
 
@@ -14,7 +13,7 @@ class Quaternion;
  * When using a vector to represent a surface normal,
  * the vector should typically be normalized.
  * Other uses of directional vectors may wish to leave
- * the magnitude of the vector in-tact. When used as a point,
+ * the magnitude of the vector intact. When used as a point,
  * the elements of the vector represent a position in 3D space.
  */
 class Vector3
@@ -72,57 +71,67 @@ public:
      */
     Vector3(const Vector3& copy);
 
+    /**
+     * Creates a new vector from an integer interpreted as an RGB value.
+     * E.g. 0xff0000 represents red or the vector (1, 0, 0).
+     *
+     * @param color The integer to interpret as an RGB value.
+     *
+     * @return A vector corresponding to the interpreted RGB color.
+     */
+    static Vector3 fromColor(unsigned int color);
+
     /**
      * Destructor.
      */
     ~Vector3();
 
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      * @return The 3-element vector of 0s.
      */
     static const Vector3& zero();
 
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      * @return The 3-element vector of 1s.
      */
     static const Vector3& one();
 
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      * @return The 3-element unit vector along the x axis.
      */
     static const Vector3& unitX();
 
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      * @return The 3-element unit vector along the y axis.
      */
     static const Vector3& unitY();
 
     /**
-     * The unit z vector.
+     * Returns the unit z vector.
      *
      * @return The 3-element unit vector along the z axis.
      */
     static const Vector3& unitZ();
 
     /**
-     * Is this vector the all zeros.
+     * Indicates whether this vector contains all zeros.
      *
-     * @return true if all zeros, false if otherwise.
+     * @return true if this vector contains all zeros, false otherwise.
      */
     bool isZero() const;
 
     /**
-     * Is this vector all ones.
+     * Indicates whether this vector contains all ones.
      *
-     * @return true if all ones, false if otherwise.
+     * @return true if this vector contains all ones, false otherwise.
      */
     bool isOne() const;
 
@@ -132,7 +141,7 @@ public:
      * @param v1 The first vector.
      * @param v2 The second vector.
      * 
-     * @return The angle between the two vectors, in radians.
+     * @return The angle between the two vectors (in radians).
      */
     static float angle(const Vector3& v1, const Vector3& v2);
 
@@ -174,7 +183,7 @@ public:
     /**
      * Sets this vector to the cross product between itself and the specified vector.
      *
-     * @param v the vector to compute the cross product with.
+     * @param v The vector to compute the cross product with.
      */
     void cross(const Vector3& v);
 
@@ -193,9 +202,10 @@ public:
      * @param v The other vector.
      * 
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      */
-    float distance(const Vector3& v);
+    float distance(const Vector3& v) const;
 
     /**
      * Returns the squared distance between this vector and v.
@@ -208,9 +218,10 @@ public:
      * @param v The other vector.
      * 
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      */
-    float distanceSquared(const Vector3& v);
+    float distanceSquared(const Vector3& v) const;
 
     /**
      * Returns the dot product of this vector and the specified vector.
@@ -235,9 +246,10 @@ public:
      * Computes the length of this vector.
      *
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      */
-    float length();
+    float length() const;
 
     /**
      * Returns the squared length of this vector.
@@ -248,9 +260,10 @@ public:
      * instead of length.
      *
      * @return The squared length of the vector.
+     * 
      * @see length
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
     /**
      * Negates this vector.
@@ -275,7 +288,7 @@ public:
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
     void normalize(Vector3* dst) const;
 
@@ -316,7 +329,7 @@ public:
 
     /**
      * Subtracts this vector and the specified vector as (this - v)
-     * and stores the result in this.
+     * and stores the result in this vector.
      *
      * @param v The vector to subtract.
      */
@@ -332,34 +345,99 @@ public:
      */
     static void subtract(const Vector3& v1, const Vector3& v2, Vector3* dst);
 
-    inline bool operator<(const Vector3& v) const
-    {
-        if (x == v.x)
-        {
-            if (y == v.y)
-            {
-                return z < v.z;
-            }
-            return y < v.y;
-        }
-        return x < v.x;
-    }
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector3 operator+(const Vector3& v);
 
-    inline bool operator==(const Vector3& v) const
-    {
-        return x==v.x && y==v.y && z==v.z;
-    }
+    /**
+     * Adds the given vector to this vector.
+     * 
+     * @param v The vector to add.
+     * @return This vector, after the addition occurs.
+     */
+    inline Vector3& operator+=(const Vector3& v);
 
-    static float distanceSquared(const Vector3& v1, const Vector3& v2);
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector3 operator-(const Vector3& v);
 
     /**
-     * Writes this vector to the binary file stream.
+     * Subtracts the given vector from this vector.
+     * 
+     * @param v The vector to subtract.
+     * @return This vector, after the subtraction occurs.
      */
-    void writeBinary(FILE* file) const;
+    inline Vector3& operator-=(const Vector3& v);
 
-    void writeText(FILE* file) const;
+    /**
+     * Calculates the negation of this vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @return The negation of this vector.
+     */
+    inline Vector3 operator-();
+
+    /**
+     * Calculates the scalar product of this vector with the given value.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param x The value to scale by.
+     * @return The scaled vector.
+     */
+    inline Vector3 operator*(float x);
+
+    /**
+     * Scales this vector by the given value.
+     * 
+     * @param x The value to scale by.
+     * @return This vector, after the scale occurs.
+     */
+    inline Vector3& operator*=(float x);
+
+    /**
+     * Determines if this vector is less than the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is less than the given vector, false otherwise.
+     */
+    inline bool operator<(const Vector3& v) const;
+
+    /**
+     * Determines if this vector is equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is equal to the given vector, false otherwise.
+     */
+    inline bool operator==(const Vector3& v) const;
 };
 
+/**
+ * Calculates the scalar product of the given vector with the given value.
+ * 
+ * @param x The value to scale by.
+ * @param v The vector to scale.
+ * @return The scaled vector.
+ */
+inline Vector3 operator*(float x, const Vector3& v);
+
 }
 
+#include "Vector3.inl"
+
 #endif

+ 82 - 0
gameplay-encoder/src/Vector3.inl

@@ -0,0 +1,82 @@
+/** 
+ * Vector3.inl
+ */
+
+#include "Vector3.h"
+#include "Matrix.h"
+
+namespace gameplay
+{
+
+inline Vector3 Vector3::operator+(const Vector3& v)
+{
+    Vector3 result(*this);
+    result.add(v);
+    return result;
+}
+
+inline Vector3& Vector3::operator+=(const Vector3& v)
+{
+    add(v);
+    return *this;
+}
+
+inline Vector3 Vector3::operator-(const Vector3& v)
+{
+    Vector3 result(*this);
+    result.subtract(v);
+    return result;
+}
+
+inline Vector3& Vector3::operator-=(const Vector3& v)
+{
+    subtract(v);
+    return *this;
+}
+
+inline Vector3 Vector3::operator-()
+{
+    Vector3 result(*this);
+    result.negate();
+    return result;
+}
+
+inline Vector3 Vector3::operator*(float x)
+{
+    Vector3 result(*this);
+    result.scale(x);
+    return result;
+}
+
+inline Vector3& Vector3::operator*=(float x)
+{
+    scale(x);
+    return *this;
+}
+
+inline bool Vector3::operator<(const Vector3& v) const
+{
+    if (x == v.x)
+    {
+        if (y == v.y)
+        {
+            return z < v.z;
+        }
+        return y < v.y;
+    }
+    return x < v.x;
+}
+
+inline bool Vector3::operator==(const Vector3& v) const
+{
+    return x==v.x && y==v.y && z==v.z;
+}
+
+inline Vector3 operator*(float x, const Vector3& v)
+{
+    Vector3 result(v);
+    result.scale(x);
+    return result;
+}
+
+}

+ 33 - 65
gameplay-encoder/src/Vector4.cpp

@@ -1,6 +1,5 @@
 #include "Base.h"
 #include "Vector4.h"
-#include "FileIO.h"
 
 namespace gameplay
 {
@@ -10,90 +9,91 @@ Vector4::Vector4()
 {
 }
 
-
 Vector4::Vector4(float x, float y, float z, float w)
 {
     set(x, y, z, w);
 }
 
-
 Vector4::Vector4(float* src)
 {
     set(src);
 }
 
-
 Vector4::Vector4(const Vector4& p1, const Vector4& p2)
 {
     set(p1, p2);
 }
 
-
 Vector4::Vector4(const Vector4& copy)
 {
     set(copy);
 }
 
+Vector4 Vector4::fromColor(unsigned int color)
+{
+    float components[4];
+    int componentIndex = 0;
+    for (int i = 3; i >= 0; --i)
+    {
+        int component = (color >> i*8) & 0x000000ff;
+
+        components[componentIndex++] = static_cast<float>(component) / 255.0f;
+    }
+
+    Vector4 value(components);
+    return value;
+}
 
 Vector4::~Vector4()
 {
 }
 
-
 const Vector4& Vector4::zero()
 {
-    static Vector4* value = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector4 value(0.0f, 0.0f, 0.0f, 0.0f);
+    return value;
 }
 
-
 const Vector4& Vector4::one()
 {
-    static Vector4* value = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
-    return *value;
+    static Vector4 value(1.0f, 1.0f, 1.0f, 1.0f);
+    return value;
 }
 
-
 const Vector4& Vector4::unitX()
 {
-    static Vector4* value = new Vector4(1.0f, 0.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector4 value(1.0f, 0.0f, 0.0f, 0.0f);
+    return value;
 }
 
-
 const Vector4& Vector4::unitY()
 {
-    static Vector4* value = new Vector4(0.0f, 1.0f, 0.0f, 0.0f);
-    return *value;
+    static Vector4 value(0.0f, 1.0f, 0.0f, 0.0f);
+    return value;
 }
 
-
 const Vector4& Vector4::unitZ()
 {
-    static Vector4* value = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
-    return *value;
+    static Vector4 value(0.0f, 0.0f, 1.0f, 0.0f);
+    return value;
 }
 
-
 const Vector4& Vector4::unitW()
 {
-    static Vector4* value = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);
-    return *value;
+    static Vector4 value(0.0f, 0.0f, 0.0f, 1.0f);
+    return value;
 }
 
-
 bool Vector4::isZero() const
 {
     return x == 0.0f && y == 0.0f && z == 0.0f && w == 0.0f;
 }
 
-
 bool Vector4::isOne() const
 {
     return x == 1.0f && y == 1.0f && z == 1.0f && z == 1.0f;
 }
 
-
 float Vector4::angle(const Vector4& v1, const Vector4& v2)
 {
     float dx = v1.w * v2.x - v1.x * v2.w - v1.y * v2.z + v1.z * v2.y;
@@ -103,7 +103,6 @@ float Vector4::angle(const Vector4& v1, const Vector4& v2)
     return atan2f(sqrt(dx * dx + dy * dy + dz * dz) + MATH_FLOAT_SMALL, dot(v1, v2));
 }
 
-
 void Vector4::add(const Vector4& v)
 {
     x += v.x;
@@ -112,7 +111,6 @@ void Vector4::add(const Vector4& v)
     w += v.w;
 }
 
-
 void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
 {
     assert(dst);
@@ -123,7 +121,6 @@ void Vector4::add(const Vector4& v1, const Vector4& v2, Vector4* dst)
     dst->w = v1.w + v2.w;
 }
 
-
 void Vector4::clamp(const Vector4& min, const Vector4& max)
 {
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z || min.w > max.w));
@@ -153,13 +150,12 @@ void Vector4::clamp(const Vector4& min, const Vector4& max)
         w = max.w;
 }
 
-
 void Vector4::clamp(const Vector4& v, const Vector4& min, const Vector4& max, Vector4* dst)
 {
     assert(dst);
     assert(!( min.x > max.x || min.y > max.y || min.z > max.z || min.w > max.w));
 
-    // Clamp the y value.
+    // Clamp the x value.
     dst->x = v.x;
     if ( dst->x < min.x )
         dst->x = min.x;
@@ -188,8 +184,7 @@ void Vector4::clamp(const Vector4& v, const Vector4& min, const Vector4& max, Ve
         dst->w = max.w;
 }
 
-
-float Vector4::distance(const Vector4& v)
+float Vector4::distance(const Vector4& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
@@ -199,8 +194,7 @@ float Vector4::distance(const Vector4& v)
     return sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
 }
 
-
-float Vector4::distanceSquared(const Vector4& v)
+float Vector4::distanceSquared(const Vector4& v) const
 {
     float dx = v.x - x;
     float dy = v.y - y;
@@ -210,31 +204,27 @@ float Vector4::distanceSquared(const Vector4& v)
     return (dx * dx + dy * dy + dz * dz + dw * dw);
 }
 
-
 float Vector4::dot(const Vector4& v)
 {
     return (x * v.x + y * v.y + z * v.z + w * v.w);
 }
 
-
 float Vector4::dot(const Vector4& v1, const Vector4& v2)
 {
     return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w);
 }
 
-
-float Vector4::length()
+float Vector4::length() const
 {
     return sqrt(x * x + y * y + z * z + w * w);
 }
 
 
-float Vector4::lengthSquared()
+float Vector4::lengthSquared() const
 {
     return (x * x + y * y + z * z + w * w);
 }
 
-
 void Vector4::negate()
 {
     x = -x;
@@ -243,13 +233,11 @@ void Vector4::negate()
     w = -w;
 }
 
-
 void Vector4::normalize()
 {
     normalize(this);
 }
 
-
 void Vector4::normalize(Vector4* dst)
 {
     assert(dst);
@@ -263,12 +251,12 @@ void Vector4::normalize(Vector4* dst)
     }
 
     float n = x * x + y * y + z * z + w * w;
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
         return;
 
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < MATH_TOLERANCE)
         return;
 
@@ -279,7 +267,6 @@ void Vector4::normalize(Vector4* dst)
     dst->w *= n;
 }
 
-
 void Vector4::scale(float scalar)
 {
     x *= scalar;
@@ -288,7 +275,6 @@ void Vector4::scale(float scalar)
     w *= scalar;
 }
 
-
 void Vector4::set(float x, float y, float z, float w)
 {
     this->x = x;
@@ -297,7 +283,6 @@ void Vector4::set(float x, float y, float z, float w)
     this->w = w;
 }
 
-
 void Vector4::set(float* array)
 {
     assert(array);
@@ -308,7 +293,6 @@ void Vector4::set(float* array)
     w = array[3];
 }
 
-
 void Vector4::set(const Vector4& v)
 {
     this->x = v.x;
@@ -317,7 +301,6 @@ void Vector4::set(const Vector4& v)
     this->w = v.w;
 }
 
-
 void Vector4::set(const Vector4& p1, const Vector4& p2)
 {
     x = p2.x - p1.x;
@@ -326,7 +309,6 @@ void Vector4::set(const Vector4& p1, const Vector4& p2)
     w = p2.w - p1.w;
 }
 
-
 void Vector4::subtract(const Vector4& v)
 {
     x -= v.x;
@@ -335,7 +317,6 @@ void Vector4::subtract(const Vector4& v)
     w -= v.w;
 }
 
-
 void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
 {
     assert(dst);
@@ -346,17 +327,4 @@ void Vector4::subtract(const Vector4& v1, const Vector4& v2, Vector4* dst)
     dst->w = v1.w - v2.w;
 }
 
-void Vector4::writeBinary(FILE* file) const
-{
-    write(x, file);
-    write(y, file);
-    write(z, file);
-    write(w, file);
-}
-
-void Vector4::writeText(FILE* file) const
-{
-    fprintf(file, "%f %f %f %f\n", x, y, z, w);
-}
-
 }

+ 118 - 46
gameplay-encoder/src/Vector4.h

@@ -1,12 +1,9 @@
 #ifndef VECTOR4_H_
 #define VECTOR4_H_
 
-#include "FileIO.h"
-
 namespace gameplay
 {
 
-// Forward declare
 class Matrix;
 
 /**
@@ -75,64 +72,74 @@ public:
      */
     Vector4(const Vector4& copy);
 
+    /**
+     * Creates a new vector from an integer interpreted as an RGBA value.
+     * E.g. 0xff0000ff represents opaque red or the vector (1, 0, 0, 1).
+     *
+     * @param color The integer to interpret as an RGBA value.
+     *
+     * @return A vector corresponding to the interpreted RGBA color.
+     */
+    static Vector4 fromColor(unsigned int color);
+
     /**
      * Destructor.
      */
     ~Vector4();
 
     /**
-     * The zero vector
+     * Returns the zero vector.
      *
      * @return The 4-element vector of 0s.
      */
     static const Vector4& zero();
 
     /**
-     * The one vector.
+     * Returns the one vector.
      *
      * @return The 4-element vector of 1s.
      */
     static const Vector4& one();
 
     /**
-     * The unit x vector.
+     * Returns the unit x vector.
      *
      * @return The 4-element unit vector along the x axis.
      */
     static const Vector4& unitX();
 
     /**
-     * The unit y vector.
+     * Returns the unit y vector.
      *
      * @return The 4-element unit vector along the y axis.
      */
     static const Vector4& unitY();
 
     /**
-     * The unit z vector.
+     * Returns the unit z vector.
      *
      * @return The 4-element unit vector along the z axis.
      */
     static const Vector4& unitZ();
 
     /**
-     * The unit w vector.
+     * Returns the unit w vector.
      *
      * @return The 4-element unit vector along the w axis.
      */
     static const Vector4& unitW();
 
     /**
-     * Is this vector the all zeros.
+     * Indicates whether this vector contains all zeros.
      *
-     * @return true if all zeros, false if otherwise.
+     * @return true if this vector contains all zeros, false otherwise.
      */
     bool isZero() const;
 
     /**
-     * Is this vector all ones.
+     * Indicates whether this vector contains all ones.
      *
-     * @return true if all ones, false if otherwise.
+     * @return true if this vector contains all ones, false otherwise.
      */
     bool isOne() const;
 
@@ -142,7 +149,7 @@ public:
      * @param v1 The first vector.
      * @param v2 The second vector.
      * 
-     * @return The angle between the two vectors, in radians.
+     * @return The angle between the two vectors (in radians).
      */
     static float angle(const Vector4& v1, const Vector4& v2);
 
@@ -186,9 +193,10 @@ public:
      * @param v The other vector.
      * 
      * @return The distance between this vector and v.
+     * 
      * @see distanceSquared
      */
-    float distance(const Vector4& v);
+    float distance(const Vector4& v) const;
 
     /**
      * Returns the squared distance between this vector and v.
@@ -201,9 +209,10 @@ public:
      * @param v The other vector.
      * 
      * @return The squared distance between this vector and v.
+     * 
      * @see distance
      */
-    float distanceSquared(const Vector4& v);
+    float distanceSquared(const Vector4& v) const;
 
     /**
      * Returns the dot product of this vector and the specified vector.
@@ -228,9 +237,10 @@ public:
      * Computes the length of this vector.
      *
      * @return The length of the vector.
+     * 
      * @see lengthSquared
      */
-    float length();
+    float length() const;
 
     /**
      * Returns the squared length of this vector.
@@ -241,9 +251,10 @@ public:
      * instead of length.
      *
      * @return The squared length of the vector.
+     * 
      * @see length
      */
-    float lengthSquared();
+    float lengthSquared() const;
 
     /**
      * Negates this vector.
@@ -268,7 +279,7 @@ public:
      * of the vector is zero, this method simply copies the
      * current vector into dst.
      *
-     * @param dst the destination vector
+     * @param dst The destination vector.
      */
     void normalize(Vector4* dst);
 
@@ -305,12 +316,15 @@ public:
 
     /**
      * Sets this vector to the directional vector between the specified points.
+     * 
+     * @param p1 The first point.
+     * @param p2 The second point.
      */
     void set(const Vector4& p1, const Vector4& p2);
 
     /**
      * Subtracts this vector and the specified vector as (this - v)
-     * and stores the result in this.
+     * and stores the result in this vector.
      *
      * @param v The vector to subtract.
      */
@@ -326,41 +340,99 @@ public:
      */
     static void subtract(const Vector4& v1, const Vector4& v2, Vector4* dst);
 
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector4 operator+(const Vector4& v);
+
+    /**
+     * Adds the given vector to this vector.
+     * 
+     * @param v The vector to add.
+     * @return This vector, after the addition occurs.
+     */
+    inline Vector4& operator+=(const Vector4& v);
+
+    /**
+     * Calculates the sum of this vector with the given vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param v The vector to add.
+     * @return The vector sum.
+     */
+    inline Vector4 operator-(const Vector4& v);
+
+    /**
+     * Subtracts the given vector from this vector.
+     * 
+     * @param v The vector to subtract.
+     * @return This vector, after the subtraction occurs.
+     */
+    inline Vector4& operator-=(const Vector4& v);
 
+    /**
+     * Calculates the negation of this vector.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @return The negation of this vector.
+     */
+    inline Vector4 operator-();
 
-    inline bool operator<(const Vector4& v) const
-    {
-        if (x == v.x)
-        {
-            if (y == v.y)
-            {
-                if (z < v.z)
-                {
-                    if (w < v.w)
-                    {
-                        return w < v.w;
-                    }
-                }
-                return z < v.z;
-            }
-            return y < v.y;
-        }
-        return x < v.x;
-    }
+    /**
+     * Calculates the scalar product of this vector with the given value.
+     * 
+     * Note: this does not modify this vector.
+     * 
+     * @param x The value to scale by.
+     * @return The scaled vector.
+     */
+    inline Vector4 operator*(float x);
 
-    inline bool operator==(const Vector4& v) const
-    {
-        return x==v.x && y==v.y && z==v.z && w==v.w;
-    }
+    /**
+     * Scales this vector by the given value.
+     * 
+     * @param x The value to scale by.
+     * @return This vector, after the scale occurs.
+     */
+    inline Vector4& operator*=(float x);
 
     /**
-     * Writes this vector to the binary file stream.
+     * Determines if this vector is less than the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is less than the given vector, false otherwise.
      */
-    void writeBinary(FILE* file) const;
+    inline bool operator<(const Vector4& v) const;
 
-    void writeText(FILE* file) const;
+    /**
+     * Determines if this vector is equal to the given vector.
+     * 
+     * @param v The vector to compare against.
+     * 
+     * @return True if this vector is equal to the given vector, false otherwise.
+     */
+    inline bool operator==(const Vector4& v) const;
 };
 
+/**
+ * Calculates the scalar product of the given vector with the given value.
+ * 
+ * @param x The value to scale by.
+ * @param v The vector to scale.
+ * @return The scaled vector.
+ */
+inline Vector4 operator*(float x, const Vector4& v);
+
 }
 
+#include "Vector4.inl"
+
 #endif

+ 89 - 0
gameplay-encoder/src/Vector4.inl

@@ -0,0 +1,89 @@
+/** 
+ * Vector4.inl
+ */
+
+#include "Matrix.h"
+#include "Vector4.h"
+
+namespace gameplay
+{
+
+inline Vector4 Vector4::operator+(const Vector4& v)
+{
+    Vector4 result(*this);
+    result.add(v);
+    return result;
+}
+
+inline Vector4& Vector4::operator+=(const Vector4& v)
+{
+    add(v);
+    return *this;
+}
+
+inline Vector4 Vector4::operator-(const Vector4& v)
+{
+    Vector4 result(*this);
+    result.subtract(v);
+    return result;
+}
+
+inline Vector4& Vector4::operator-=(const Vector4& v)
+{
+    subtract(v);
+    return *this;
+}
+
+inline Vector4 Vector4::operator-()
+{
+    Vector4 result(*this);
+    result.negate();
+    return result;
+}
+
+inline Vector4 Vector4::operator*(float x)
+{
+    Vector4 result(*this);
+    result.scale(x);
+    return result;
+}
+
+inline Vector4& Vector4::operator*=(float x)
+{
+    scale(x);
+    return *this;
+}
+
+inline bool Vector4::operator<(const Vector4& v) const
+{
+    if (x == v.x)
+    {
+        if (y == v.y)
+        {
+            if (z < v.z)
+            {
+                if (w < v.w)
+                {
+                    return w < v.w;
+                }
+            }
+            return z < v.z;
+        }
+        return y < v.y;
+    }
+    return x < v.x;
+}
+
+inline bool Vector4::operator==(const Vector4& v) const
+{
+    return x==v.x && y==v.y && z==v.z && w==v.w;
+}
+
+inline Vector4 operator*(float x, const Vector4& v)
+{
+    Vector4 result(v);
+    result.scale(x);
+    return result;
+}
+
+}

+ 28 - 26
gameplay-encoder/src/Vertex.cpp

@@ -5,24 +5,14 @@ namespace gameplay
 {
 
 Vertex::Vertex(void)
+    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasColor(false), hasWeights(false)
 {
-    reset();
 }
 
 Vertex::~Vertex(void)
 {
 }
 
-void Vertex::reset()
-{
-    hasNormal = false;
-    hasTangent = false;
-    hasBinormal = false;
-    hasTexCoord = false;
-    hasColor = false;
-    hasWeights = false;
-}
-
 unsigned int Vertex::byteSize() const
 {
     unsigned int count = 3;
@@ -41,66 +31,78 @@ unsigned int Vertex::byteSize() const
 
 void Vertex::writeBinary(FILE* file) const
 {
-    position.writeBinary(file);
+    writeVectorBinary(position, file);
     if (hasNormal)
     {
-        normal.writeBinary(file);
+        writeVectorBinary(normal, file);
     }
     if (hasTangent)
     {
-        tangent.writeBinary(file);
+        writeVectorBinary(tangent, file);
     }
     if (hasBinormal)
     {
-        binormal.writeBinary(file);
+        writeVectorBinary(binormal, file);
     }
     if (hasTexCoord)
     {
-        texCoord.writeBinary(file);
+        writeVectorBinary(texCoord, file);
     }
     // TODO add vertex color?
     //if (hasColor)
     //{
-    //    color.writeBinary(file);
+    //    writeVectorBinary(color, file);
     //}
     if (hasWeights)
     {
-        blendWeights.writeBinary(file);
-        blendIndices.writeBinary(file);
+        writeVectorBinary(blendWeights, file);
+        writeVectorBinary(blendIndices, file);
     }
 }
 
 void Vertex::writeText(FILE* file) const
 {
     write("// position\n", file);
-    position.writeText(file);
+    writeVectorText(position, file);
     if (hasNormal)
     {
         write("// normal\n", file);
-        normal.writeText(file);
+        writeVectorText(normal, file);
     }
     if (hasTangent)
     {
         write("// tanget\n", file);
-        tangent.writeText(file);
+        writeVectorText(tangent, file);
     }
     if (hasBinormal)
     {
         write("// binormal\n", file);
-        binormal.writeText(file);
+        writeVectorText(binormal, file);
     }
     if (hasTexCoord)
     {
         write("// texCoord\n", file);
-        texCoord.writeText(file);
+        writeVectorText(texCoord, file);
     }
     if (hasWeights)
     {
         write("// blendWeights\n", file);
-        blendWeights.writeText(file);
+        writeVectorText(blendWeights, file);
         write("// blendIndices\n", file);
-        blendIndices.writeText(file);
+        writeVectorText(blendIndices, file);
     }
 }
 
+void Vertex::normalizeBlendWeight()
+{
+    float total = blendWeights.x + blendWeights.y + blendWeights.z + blendWeights.w;
+    if (total > 0.0f)
+    {
+        blendWeights.x = blendWeights.x / total;
+        blendWeights.y = blendWeights.y / total;
+        blendWeights.z = blendWeights.z / total;
+        blendWeights.w = blendWeights.w / total;
+    }   
+}
+
 }

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

@@ -21,7 +21,7 @@ public:
     /**
      * Destructor.
      */
-    virtual ~Vertex(void);
+    ~Vertex(void);
 
     Vector3 position;
     Vector3 normal;
@@ -73,8 +73,6 @@ public:
             blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
 
-    void reset();
-
     /**
      * Returns the size of this vertex in bytes.
      */
@@ -89,8 +87,12 @@ public:
      * Writes this vertex to a text file stream.
      */
     void writeText(FILE* file) const;
-};
 
+    /**
+     * Normalizes the blend weights of this vertex so that they add up to 1.0.
+     */
+    void normalizeBlendWeight();
+};
 }
 
 #endif

+ 16 - 3
gameplay-encoder/src/main.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "DAESceneEncoder.h"
+#include "FBXSceneEncoder.h"
 #include "TTFFontEncoder.h"
 #include "GPBDecoder.h"
 #include "EncoderArguments.h"
@@ -54,21 +55,33 @@ int main(int argc, const char** argv)
     {
     case EncoderArguments::FILEFORMAT_DAE:
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             DAESceneEncoder daeEncoder;
             daeEncoder.write(realpath, arguments);
             break;
         }
+    case EncoderArguments::FILEFORMAT_FBX:
+        {
+#ifdef USE_FBX
+            std::string realpath(arguments.getFilePath());
+            FBXSceneEncoder fbxEncoder;
+            fbxEncoder.write(realpath, arguments);
+            break;
+#else
+            fprintf(stderr, "Error: FBX not enabled. Install the FBX SDK and use the preprocessor definition USE_FBX.\n");
+            return -1;
+#endif
+        }
     case EncoderArguments::FILEFORMAT_TTF:
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             std::string id = getFileName(realpath);
             writeFont(realpath.c_str(), arguments.getFontSize(), id.c_str(), arguments.fontPreviewEnabled());
             break;
         }
     case EncoderArguments::FILEFORMAT_GPB:
         {
-            std::string realpath = arguments.getFilePath();
+            std::string realpath(arguments.getFilePath());
             GPBDecoder decoder;
             decoder.readBinary(realpath);
             break;

+ 271 - 0
gameplay-newproject.bat

@@ -0,0 +1,271 @@
+@echo off
+
+REM ********************************************************************
+REM
+REM generate-project.bat
+REM
+REM This windows batch script generates a set of gameplay project files.
+REM The new project will be based of the gameplay-template project and 
+REM it will be generated with the name and location that is specified
+REM as input parameters.
+REM
+REM IMPORTANT: This script must be run from the root of the gameplay
+REM source tree.
+REM
+REM ********************************************************************
+
+echo.
+echo 1. Enter a name for the new project.
+echo.
+echo    This name will be given to the project 
+echo    executable and a folder with this name
+echo    will be created to store all project files.
+echo.
+set /p projName=Project name: 
+if "%projName%" == "" (
+    echo.
+    echo ERROR: No project name specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 2. Enter a game title.
+echo.
+echo    On some platforms, this title is used to
+echo    identify the game during installation and
+echo    on shortcuts/icons.
+echo.
+set /p title=Title: 
+if "%title%" == "" (
+    echo.
+    echo ERROR: No game title specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 3. Enter a short game description.
+echo.
+set /p desc=Description: 
+if "%desc%" == "" (
+    set desc=%title%
+)
+echo.
+
+echo.
+echo 4. Enter a unique identifier for your project.
+echo.
+echo    This should be a human readable package name,
+echo    containing at least two words separated by a
+echo    period (eg. com.surname.gamename).
+echo.
+set /p uuid=Unique ID: 
+if "%uuid%" == "" (
+    echo.
+    echo ERROR: No uuid specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 5. Enter author name.
+echo.
+echo    On BlackBerry targets, this is used for
+echo    signing and must match the developer name
+echo    of your development certificate.
+echo.
+set /p author=Author: 
+if "%author%" == "" (
+    echo.
+    echo ERROR: No author specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 6. Enter your game's main class name.
+echo.
+echo    Your initial game header and source file
+echo    will be given this name and a class with 
+echo    this name will be created in these files.
+echo.
+set /p className=Class name: 
+if "%className%" == "" (
+    echo.
+    echo ERROR: No class name specified.
+    echo.
+    pause
+    goto done
+)
+echo.
+
+echo.
+echo 7. Enter the project path.
+echo.
+echo    This can be a relative path, absolute path,
+echo    or empty for the current folder. Note that
+echo    a project folder named %projName% will also
+echo    be created inside this folder.
+echo.
+set /p location=Path: 
+if "%location%" == "" (
+    set projPath=%projName%
+) else (
+    set projPath=%location%\%projName%
+)
+echo.
+
+call:replacevar projPath "/" "\"
+
+REM Does this path already exist?
+if exist %projPath% (
+    echo.
+    echo ERROR: Path '%projPath%' already exists, aborting.
+    echo.
+    pause
+    goto done
+
+REM Disabling following code which prompts to overwrite existing path,
+REM since this could be potentially damaging if the user specifies
+REM an important path and then types 'y', without thinking.
+REM
+REM    set /p owd=Directory '%projPath%' exists, overwrite [Y,N]? 
+REM    if not "!owd!" == "Y" (
+REM        if not "!owd!" == "y" (
+REM            echo Aborting.
+REM            pause
+REM            goto done
+REM        )
+REM    )
+REM    rmdir /S /Q %projPath%
+)
+
+REM Generate relative path from project folder to GamePlay folder
+set gpPath=%cd%
+call:makerelative gpPath %projPath%\
+call:replacevar gpPath "\" "/"
+
+mkdir %projPath%
+mkdir %projPath%\src
+mkdir %projPath%\res
+
+REM Copy Microsoft Visual Studio project files
+copy gameplay-template\gameplay-template.vcxproj %projPath%\%projName%.vcxproj
+call:replace %projPath%\%projName%.vcxproj TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\%projName%.vcxproj TemplateGame "%className%"
+call:replace %projPath%\%projName%.vcxproj GAMEPLAY_PATH "%gpPath%"
+
+copy gameplay-template\gameplay-template.vcxproj.filters %projPath%\%projName%.vcxproj.filters
+call:replace %projPath%\%projName%.vcxproj.filters TemplateGame "%className%"
+
+copy gameplay-template\gameplay-template.vcxproj.user %projPath%\%projName%.vcxproj.user
+call:replace %projPath%\%projName%.vcxproj.user GAMEPLAY_PATH "%gpPath%"
+
+REM Copy Apple XCode project files
+mkdir %projPath%\%projName%.xcodeproj
+copy gameplay-template\gameplay-template.xcodeproj\project.pbxproj %projPath%\%projName%.xcodeproj\project.pbxproj
+call:replace %projPath%\%projName%.xcodeproj\project.pbxproj GAMEPLAY_PATH "%gpPath%"
+call:replace %projPath%\%projName%.xcodeproj\project.pbxproj TemplateGame "%className%"
+call:replace %projPath%\%projName%.xcodeproj\project.pbxproj TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\gameplay-template-macos.plist %projPath%\%projName%-macos.plist
+call:replace %projPath%\%projName%-macos.plist TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\%projName%-macos.plist TEMPLATE_AUTHOR "%author%"
+
+REM Copy BlackBerry NDK project files
+copy gameplay-template\template.cproject %projPath%\.cproject
+call:replace %projPath%\.cproject TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\.cproject TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\.cproject GAMEPLAY_PATH "%gpPath%"
+
+copy gameplay-template\template.project %projPath%\.project
+call:replace %projPath%\.project TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\template.bar-descriptor.xml %projPath%\bar-descriptor.xml
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_TITLE "%title%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_AUTHOR "%author%"
+call:replace %projPath%\bar-descriptor.xml TEMPLATE_DESCRIPTION "%desc%"
+
+REM Copy source files
+copy gameplay-template\src\TemplateGame.h %projPath%\src\%className%.h
+copy gameplay-template\src\TemplateGame.cpp %projPath%\src\%className%.cpp
+call:replace %projPath%\src\%className%.h TemplateGame "%className%"
+call:replace %projPath%\src\%className%.cpp TemplateGame "%className%"
+
+REM Copy resource files
+copy gameplay-template\res\* %projPath%\res\
+copy gameplay\res\shaders\colored.* %projPath%\res\
+
+REM Copy icon
+copy gameplay-template\icon.png %projPath%\icon.png
+
+REM Open new project folder
+start %projPath%
+
+goto done
+
+:replace
+set rtemp=%1.rtemp
+if exist %rtemp% del /Q %rtemp%
+for /f "tokens=1* eol=€ delims=€]" %%j in ('type "%1" ^| find /V /N ""') do (
+    set line=%%k
+    setlocal EnableDelayedExpansion
+    if "!line!" == "" (
+        echo.>>%rtemp%
+    ) else (
+        set linput=!line!
+        set loutput=!linput:%~2=%~3!
+        echo.!loutput!>>%rtemp%
+    )
+    endlocal
+)
+copy /Y %rtemp% %1
+del /Q %rtemp%
+exit /b
+goto done
+
+:replacevar
+setlocal EnableDelayedExpansion
+echo !%~1!>.replacevar.tmp
+endlocal
+call:replace .replacevar.tmp "%~2" "%~3"
+set /p replaced=<.replacevar.tmp
+set %~1=%replaced%
+del /Q .replacevar.tmp
+exit /b
+goto done
+
+:makerelative
+setlocal EnableDelayedExpansion
+set src=%~1
+if defined %1 set src=!%~1!
+set bas=%~2
+if not defined bas set bas=%cd%
+for /f "tokens=*" %%a in ("%src%") do set src=%%~fa
+for /f "tokens=*" %%a in ("%bas%") do set bas=%%~fa
+set mat=&rem variable to store matching part of the name
+set upp=&rem variable to reference a parent
+for /f "tokens=*" %%a in ('echo.%bas:\=^&echo.%') do (
+    set sub=!sub!%%a\
+    call set tmp=%%src:!sub!=%%
+    if "!tmp!" NEQ "!src!" (set mat=!sub!)ELSE (set upp=!upp!..\)
+)
+set src=%upp%!src:%mat%=!
+( endlocal & REM RETURN VALUES
+    IF defined %1 (SET %~1=%src%) ELSE ECHO.%src%
+)
+exit /b
+goto done
+
+:done

+ 34 - 0
gameplay-template/gameplay-template-macos.plist

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>icon.png</string>
+	<key>CFBundleIdentifier</key>
+	<string>TEMPLATE_UUID</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSApplicationCategoryType</key>
+	<string>public.app-category.games</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2011 TEMPLATE_AUTHOR. All rights reserved.</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>

+ 171 - 0
gameplay-template/gameplay-template.vcxproj

@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="DebugMem|Win32">
+      <Configuration>DebugMem</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>TEMPLATE_PROJECT</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(Configuration)\</OutDir>
+    <ExecutablePath>$(ExecutablePath)</ExecutablePath>
+    <CustomBuildBeforeTargets>
+    </CustomBuildBeforeTargets>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(Configuration)\</OutDir>
+    <ExecutablePath>$(ExecutablePath)</ExecutablePath>
+    <CustomBuildBeforeTargets />
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(Configuration)\</OutDir>
+    <CustomBuildBeforeTargets>
+    </CustomBuildBeforeTargets>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>GAMEPLAY_PATH/external-deps/bullet/include;GAMEPLAY_PATH/gameplay/src;GAMEPLAY_PATH/external-deps/openal/include/AL;GAMEPLAY_PATH/external-deps/oggvorbis/include;GAMEPLAY_PATH/external-deps/libpng/include;GAMEPLAY_PATH/external-deps/zlib/include;GAMEPLAY_PATH/external-deps/glew/include</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/bullet/lib/win32;GAMEPLAY_PATH/external-deps/openal/lib/win32;GAMEPLAY_PATH/external-deps/oggvorbis/lib/win32;GAMEPLAY_PATH/external-deps/glew/lib/win32;GAMEPLAY_PATH/external-deps/libpng/lib/win32;GAMEPLAY_PATH/external-deps/zlib/lib/win32;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+    <CustomBuildStep>
+      <Command>
+      </Command>
+      <Message>
+      </Message>
+      <Outputs>
+      </Outputs>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;GAMEPLAY_MEM_LEAK_DETECTION;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>GAMEPLAY_PATH/external-deps/bullet/include;GAMEPLAY_PATH/gameplay/src;GAMEPLAY_PATH/external-deps/openal/include/AL;GAMEPLAY_PATH/external-deps/oggvorbis/include;GAMEPLAY_PATH/external-deps/libpng/include;GAMEPLAY_PATH/external-deps/zlib/include;GAMEPLAY_PATH/external-deps/glew/include</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>
+      <ShowIncludes>false</ShowIncludes>
+      <PreprocessToFile>false</PreprocessToFile>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/bullet/lib/win32;GAMEPLAY_PATH/external-deps/openal/lib/win32;GAMEPLAY_PATH/external-deps/oggvorbis/lib/win32;GAMEPLAY_PATH/external-deps/glew/lib/win32;GAMEPLAY_PATH/external-deps/libpng/lib/win32;GAMEPLAY_PATH/external-deps/zlib/lib/win32;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+    <CustomBuildStep>
+      <Command>
+      </Command>
+      <Message>
+      </Message>
+      <Outputs>
+      </Outputs>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>GAMEPLAY_PATH/external-deps/bullet/include;GAMEPLAY_PATH/gameplay/src;GAMEPLAY_PATH/external-deps/openal/include/AL;GAMEPLAY_PATH/external-deps/oggvorbis/include;GAMEPLAY_PATH/external-deps/libpng/include;GAMEPLAY_PATH/external-deps/zlib/include;GAMEPLAY_PATH/external-deps/glew/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/bullet/lib/win32;GAMEPLAY_PATH/external-deps/openal/lib/win32;GAMEPLAY_PATH/external-deps/oggvorbis/lib/win32;GAMEPLAY_PATH/external-deps/glew/lib/win32;GAMEPLAY_PATH/external-deps/libpng/lib/win32;GAMEPLAY_PATH/external-deps/zlib/lib/win32;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+    <CustomBuildStep>
+      <Command>
+      </Command>
+      <Message>
+      </Message>
+      <Outputs>
+      </Outputs>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="src\TemplateGame.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="src\TemplateGame.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 17 - 0
gameplay-template/gameplay-template.vcxproj.filters

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="src">
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="src\TemplateGame.h">
+      <Filter>src</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\TemplateGame.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+  </ItemGroup>
+</Project>

+ 15 - 0
gameplay-template/gameplay-template.vcxproj.user

@@ -0,0 +1,15 @@
+<?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'">
+    <LocalDebuggerEnvironment>PATH=%PATH%;GAMEPLAY_PATH/external-deps/zlib/lib/win32;GAMEPLAY_PATH/external-deps/libpng/lib/win32;GAMEPLAY_PATH/external-deps/glew/lib/win32;GAMEPLAY_PATH/external-deps/openal/lib/win32;</LocalDebuggerEnvironment>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+	<LocalDebuggerEnvironment>PATH=%PATH%;GAMEPLAY_PATH/external-deps/zlib/lib/win32;GAMEPLAY_PATH/external-deps/libpng/lib/win32;GAMEPLAY_PATH/external-deps/glew/lib/win32;GAMEPLAY_PATH/external-deps/openal/lib/win32;</LocalDebuggerEnvironment>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <LocalDebuggerEnvironment>PATH=%PATH%;GAMEPLAY_PATH/external-deps/zlib/lib/win32;GAMEPLAY_PATH/external-deps/libpng/lib/win32;GAMEPLAY_PATH/external-deps/glew/lib/win32;GAMEPLAY_PATH/external-deps/openal/lib/win32;</LocalDebuggerEnvironment>
+	<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+  </PropertyGroup>
+</Project>

+ 343 - 0
gameplay-template/gameplay-template.xcodeproj/project.pbxproj

@@ -0,0 +1,343 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		42C932F11491A5160098216A /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
+		42C932EE1491A4CB0098216A /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 42C932ED1491A4CB0098216A /* icon.png */; };
+		42C932F31491A53E0098216A /* res in Resources */ = {isa = PBXBuildFile; fileRef = 42C932F21491A53E0098216A /* res */; };
+		42C932C11491A0DB0098216A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C932C01491A0DB0098216A /* Cocoa.framework */; };
+		42C9331D1491A6750098216A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9331C1491A6750098216A /* QuartzCore.framework */; };
+		42C933171491A5EB0098216A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933161491A5EB0098216A /* OpenGL.framework */; };
+		42C9331F1491A67F0098216A /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9331E1491A67F0098216A /* OpenAL.framework */; };
+		42438B531491AD2000D218B8 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
+		42C933211491A6C70098216A /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933201491A6C70098216A /* libbullet.a */; };
+		42C933261491A6E50098216A /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933221491A6E50098216A /* libogg.a */; };
+		42C933271491A6E50098216A /* libvorbis.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933231491A6E50098216A /* libvorbis.a */; };
+		42C933281491A6E50098216A /* libvorbisenc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933241491A6E50098216A /* libvorbisenc.a */; };
+		42C933291491A6E50098216A /* libvorbisfile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933251491A6E50098216A /* libvorbisfile.a */; };
+		42C9332C1491A7680098216A /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332A1491A7390098216A /* libpng.a */; };
+		42C9332F1491A78D0098216A /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332D1491A7810098216A /* libz.dylib */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		42C9336B1491AA0E0098216A /* TEMPLATE_PROJECT-macos.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-macos.plist"; sourceTree = "<group>"; };
+		42C932ED1491A4CB0098216A /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
+		42C932F21491A53E0098216A /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
+		42C932EF1491A5160098216A /* TemplateGame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateGame.cpp; path = src/TemplateGame.cpp; sourceTree = SOURCE_ROOT; };
+		42C932F01491A5160098216A /* TemplateGame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemplateGame.h; path = src/TemplateGame.h; sourceTree = SOURCE_ROOT; };
+		42C932C01491A0DB0098216A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+		42C9331C1491A6750098216A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		42C933161491A5EB0098216A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		42C9331E1491A67F0098216A /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
+		42438B521491AD2000D218B8 /* libgameplay.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgameplay.a; path = "~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug/libgameplay.a"; sourceTree = "<group>"; };
+		42C933201491A6C70098216A /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "GAMEPLAY_PATH/external-deps/bullet/lib/macos/libbullet.a"; sourceTree = "<group>"; };
+		42C933221491A6E50098216A /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libogg.a"; sourceTree = "<group>"; };
+		42C933231491A6E50098216A /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libvorbis.a"; sourceTree = "<group>"; };
+		42C933241491A6E50098216A /* libvorbisenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisenc.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libvorbisenc.a"; sourceTree = "<group>"; };
+		42C933251491A6E50098216A /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos/libvorbisfile.a"; sourceTree = "<group>"; };
+		42C9332A1491A7390098216A /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "GAMEPLAY_PATH/external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
+		42C9332D1491A7810098216A /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		42C932B91491A0DB0098216A /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				42438B531491AD2000D218B8 /* libgameplay.a in Frameworks */,
+				42C933211491A6C70098216A /* libbullet.a in Frameworks */,
+				42C933261491A6E50098216A /* libogg.a in Frameworks */,
+				42C933271491A6E50098216A /* libvorbis.a in Frameworks */,
+				42C933281491A6E50098216A /* libvorbisenc.a in Frameworks */,
+				42C933291491A6E50098216A /* libvorbisfile.a in Frameworks */,
+				42C9332C1491A7680098216A /* libpng.a in Frameworks */,
+				42C9332F1491A78D0098216A /* libz.dylib in Frameworks */,
+				42C932C11491A0DB0098216A /* Cocoa.framework in Frameworks */,
+				42C9331D1491A6750098216A /* QuartzCore.framework in Frameworks */,
+				42C933171491A5EB0098216A /* OpenGL.framework in Frameworks */,
+				42C9331F1491A67F0098216A /* OpenAL.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		42C932B11491A0DB0098216A = {
+			isa = PBXGroup;
+			children = (
+				42C9336B1491AA0E0098216A /* TEMPLATE_PROJECT-macos.plist */,
+				42C932ED1491A4CB0098216A /* icon.png */,
+				42C932F21491A53E0098216A /* res */,
+				42C932C61491A0DB0098216A /* src */,
+				42C932DD1491A1050098216A /* Libraries */,
+				42C932BF1491A0DB0098216A /* Frameworks */,
+				42C932BD1491A0DB0098216A /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		42C932BD1491A0DB0098216A /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		42C932BF1491A0DB0098216A /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				42C932C01491A0DB0098216A /* Cocoa.framework */,
+				42C9331C1491A6750098216A /* QuartzCore.framework */,
+				42C933161491A5EB0098216A /* OpenGL.framework */,
+				42C9331E1491A67F0098216A /* OpenAL.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		42C932C61491A0DB0098216A /* src */ = {
+			isa = PBXGroup;
+			children = (
+				42C932EF1491A5160098216A /* TemplateGame.cpp */,
+				42C932F01491A5160098216A /* TemplateGame.h */,
+			);
+			name = src;
+			path = "src";
+			sourceTree = "<group>";
+		};
+		42C932DD1491A1050098216A /* Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				42438B521491AD2000D218B8 /* libgameplay.a */,
+				42C933201491A6C70098216A /* libbullet.a */,
+				42C933221491A6E50098216A /* libogg.a */,
+				42C933231491A6E50098216A /* libvorbis.a */,
+				42C933241491A6E50098216A /* libvorbisenc.a */,
+				42C933251491A6E50098216A /* libvorbisfile.a */,
+				42C9332A1491A7390098216A /* libpng.a */,
+				42C9332D1491A7810098216A /* libz.dylib */,
+			);
+			name = Libraries;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT" */;
+			buildPhases = (
+				42C932B81491A0DB0098216A /* Sources */,
+				42C932B91491A0DB0098216A /* Frameworks */,
+				42C933301491A7B50098216A /* ShellScript */,
+				42C932BA1491A0DB0098216A /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "TEMPLATE_PROJECT";
+			productName = "TEMPLATE_PROJECT";
+			productReference = 42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		42C932B31491A0DB0098216A /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0420;
+			};
+			buildConfigurationList = 42C932B61491A0DB0098216A /* Build configuration list for PBXProject "TEMPLATE_PROJECT" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 42C932B11491A0DB0098216A;
+			productRefGroup = 42C932BD1491A0DB0098216A /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		42C932BA1491A0DB0098216A /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				42C932EE1491A4CB0098216A /* icon.png in Resources */,
+				42C932F31491A53E0098216A /* res in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		42C933301491A7B50098216A /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "touch -cm ${SRCROOT}/res";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		42C932B81491A0DB0098216A /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				42C932F11491A5160098216A /* TemplateGame.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		42C932D81491A0DB0098216A /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				COPY_PHASE_STRIP = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				GENERATE_PKGINFO_FILE = YES;
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				ONLY_ACTIVE_ARCH = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		42C932D91491A0DB0098216A /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				GENERATE_PKGINFO_FILE = YES;
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				MACOSX_DEPLOYMENT_TARGET = 10.7;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		42C932DB1491A0DB0098216A /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				GCC_PRECOMPILE_PREFIX_HEADER = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					"GAMEPLAY_PATH/gameplay/src",
+					"GAMEPLAY_PATH/external-deps/libpng/include",
+					"GAMEPLAY_PATH/external-deps/bullet/include",
+					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
+				);
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macos\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/macos\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos\"",
+					"\"~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
+				);
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		42C932DC1491A0DB0098216A /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				GCC_PRECOMPILE_PREFIX_HEADER = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+				GCC_WARN_UNUSED_VARIABLE = NO;
+				HEADER_SEARCH_PATHS = (
+					"GAMEPLAY_PATH/gameplay/src",
+					"GAMEPLAY_PATH/external-deps/libpng/include",
+					"GAMEPLAY_PATH/external-deps/bullet/include",
+					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
+				);
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macos\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/macos\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/macos\"",
+					"\"~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug\"",
+				);
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		42C932B61491A0DB0098216A /* Build configuration list for PBXProject "TEMPLATE_PROJECT" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				42C932D81491A0DB0098216A /* Debug */,
+				42C932D91491A0DB0098216A /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				42C932DB1491A0DB0098216A /* Debug */,
+				42C932DC1491A0DB0098216A /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 42C932B31491A0DB0098216A /* Project object */;
+}

BIN
gameplay-template/icon.png


+ 183 - 0
gameplay-template/res/box.dae

@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+  <asset>
+    <contributor>
+      <author>sgrenier</author>
+      <authoring_tool>OpenCOLLADA2011 x64</authoring_tool>
+      <comments>
+			ColladaMaya export options: 
+			bakeTransforms=1;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0;
+			isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1;
+			exportCameras=1;exportJointsAndSkin=1;exportAnimations=1;exportInvisibleNodes=0;exportDefaultCameras=0;
+			exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0;
+			exportTexTangents=0;exportTangents=0;exportReferencedMaterials=0;exportMaterialsOnly=0;
+			exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0
+		</comments>
+      <source_data>file:///C:/Users/sgrenier/Documents/maya/projects/default/untitled</source_data>
+    </contributor>
+    <created>2011-12-05T20:23:32</created>
+    <modified>2011-12-05T20:23:32</modified>
+    <unit name="centimeter" meter="0.01"/>
+    <up_axis>Y_UP</up_axis>
+  </asset>
+  <library_lights>
+    <light id="directionalLightShape" name="directionalLightShape">
+      <technique_common>
+        <directional>
+          <color>1 1 1</color>
+        </directional>
+      </technique_common>
+      <extra>
+        <technique profile="OpenCOLLADAMaya">
+          <originalMayaNodeId>directionalLightShape</originalMayaNodeId>
+        </technique>
+      </extra>
+    </light>
+  </library_lights>
+  <library_cameras>
+    <camera id="cameraShape" name="cameraShape">
+      <optics>
+        <technique_common>
+          <perspective>
+            <yfov>27.38717</yfov>
+            <aspect_ratio>1.7</aspect_ratio>
+            <znear>0.25</znear>
+            <zfar>100</zfar>
+          </perspective>
+        </technique_common>
+      </optics>
+      <extra>
+        <technique profile="OpenCOLLADAMaya">
+          <film_fit>0</film_fit>
+          <film_fit_offset>0</film_fit_offset>
+          <film_offsetX>0</film_offsetX>
+          <film_offsetY>0</film_offsetY>
+          <horizontal_aperture>4.079992</horizontal_aperture>
+          <lens_squeeze>1</lens_squeeze>
+          <originalMayaNodeId>cameraShape</originalMayaNodeId>
+          <vertical_aperture>2.399995</vertical_aperture>
+        </technique>
+      </extra>
+    </camera>
+  </library_cameras>
+  <library_materials>
+    <material id="lambert1" name="lambert1">
+      <instance_effect url="#lambert1-fx"/>
+    </material>
+  </library_materials>
+  <library_effects>
+    <effect id="lambert1-fx">
+      <profile_COMMON>
+        <technique sid="common">
+          <lambert>
+            <emission>
+              <color>0 0 0 1</color>
+            </emission>
+            <ambient>
+              <color>0 0 0 1</color>
+            </ambient>
+            <diffuse>
+              <color>0.4 0.4 0.4 1</color>
+            </diffuse>
+            <transparent opaque="RGB_ZERO">
+              <color>0 0 0 1</color>
+            </transparent>
+            <transparency>
+              <float>1</float>
+            </transparency>
+          </lambert>
+        </technique>
+      </profile_COMMON>
+    </effect>
+  </library_effects>
+  <library_geometries>
+    <geometry id="boxShape" name="boxShape">
+      <mesh>
+        <source id="boxShape-positions" name="boxShape-positions">
+          <float_array id="boxShape-positions-array" count="24">-0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 0.5 0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 -0.5</float_array>
+          <technique_common>
+            <accessor source="#boxShape-positions-array" count="8" stride="3">
+              <param name="X" type="float"/>
+              <param name="Y" type="float"/>
+              <param name="Z" type="float"/>
+            </accessor>
+          </technique_common>
+        </source>
+        <source id="boxShape-normals" name="boxShape-normals">
+          <float_array id="boxShape-normals-array" count="72">0 0 1 0 0 1 0 0 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 -1 0 0 -1 0 0 -1 0 0 -1 0 1 0 0 1 0 0 1 0 0 1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0</float_array>
+          <technique_common>
+            <accessor source="#boxShape-normals-array" count="24" stride="3">
+              <param name="X" type="float"/>
+              <param name="Y" type="float"/>
+              <param name="Z" type="float"/>
+            </accessor>
+          </technique_common>
+        </source>
+        <source id="boxShape-map1" name="boxShape-map1">
+          <float_array id="boxShape-map1-array" count="28">0.375 0 0.625 0 0.375 0.25 0.625 0.25 0.375 0.5 0.625 0.5 0.375 0.75 0.625 0.75 0.375 1 0.625 1 0.875 0 0.875 0.25 0.125 0 0.125 0.25</float_array>
+          <technique_common>
+            <accessor source="#boxShape-map1-array" count="14" stride="2">
+              <param name="S" type="float"/>
+              <param name="T" type="float"/>
+            </accessor>
+          </technique_common>
+        </source>
+        <vertices id="boxShape-vertices" name="boxShape-vertices">
+          <input semantic="POSITION" source="#boxShape-positions"/>
+        </vertices>
+        <triangles material="initialShadingGroup" count="12">
+          <input semantic="VERTEX" source="#boxShape-vertices" offset="0"/>
+          <input semantic="NORMAL" source="#boxShape-normals" offset="1"/>
+          <input semantic="TEXCOORD" source="#boxShape-map1" offset="2" set="0"/>
+          <p>0 0 0 1 1 1 2 3 2 2 3 2 1 1 1 3 2 3 2 4 2 3 5 3 4 7 4 4 7 4 3 5 3 5 6 5 4 8 4 5 9 5 6 11 6 6 11 6 5 9 5 7 10 7 6 12 6 7 13 7 0 15 8 0 15 8 7 13 7 1 14 9 1 16 1 7 17 10 3 19 3 3 19 3 7 17 10 5 18 11 6 20 12 0 21 0 4 23 13 4 23 13 0 21 0 2 22 2</p>
+        </triangles>
+      </mesh>
+      <extra>
+        <technique profile="OpenCOLLADAMaya">
+          <originalMayaNodeId>boxShape</originalMayaNodeId>
+          <double_sided>1</double_sided>
+        </technique>
+      </extra>
+    </geometry>
+  </library_geometries>
+  <library_visual_scenes>
+    <visual_scene id="VisualSceneNode" name="untitled">
+      <node id="box" name="box" type="NODE">
+        <matrix sid="transform">1 0 0 0 0 1 0 0.5 0 0 1 0 0 0 0 1</matrix>
+        <instance_geometry url="#boxShape">
+          <bind_material>
+            <technique_common>
+              <instance_material symbol="initialShadingGroup" target="#lambert1"/>
+            </technique_common>
+          </bind_material>
+        </instance_geometry>
+        <extra>
+          <technique profile="OpenCOLLADAMaya">
+            <originalMayaNodeId>box</originalMayaNodeId>
+          </technique>
+        </extra>
+      </node>
+      <node id="camera" name="camera" type="NODE">
+        <matrix sid="transform">0.9753993 -0.08127667 0.2049154 1.554299 0.0276844 0.9673549 0.251909 2.301022 -0.2187002 -0.2400389 0.9458073 7.279555 0 0 0 1</matrix>
+        <instance_camera url="#cameraShape"/>
+        <extra>
+          <technique profile="OpenCOLLADAMaya">
+            <originalMayaNodeId>camera</originalMayaNodeId>
+          </technique>
+        </extra>
+      </node>
+      <node id="directionalLight" name="directionalLight" type="NODE">
+        <matrix sid="transform">0.9282893 -0.14183 0.3437488 4.077966 -0.03090286 0.8917856 0.4514016 1.976955 -0.3705726 -0.4296541 0.8234521 6.724438 0 0 0 1</matrix>
+        <instance_light url="#directionalLightShape"/>
+        <extra>
+          <technique profile="OpenCOLLADAMaya">
+            <originalMayaNodeId>directionalLight</originalMayaNodeId>
+          </technique>
+        </extra>
+      </node>
+    </visual_scene>
+  </library_visual_scenes>
+  <scene>
+    <instance_visual_scene url="#VisualSceneNode"/>
+  </scene>
+</COLLADA>

BIN
gameplay-template/res/box.gpb


+ 25 - 0
gameplay-template/res/box.material

@@ -0,0 +1,25 @@
+material box
+{
+    technique
+    {
+        pass
+        {
+            // shaders
+            vertexShader = res/colored.vsh
+            fragmentShader = res/colored.fsh
+            
+            // uniforms
+            u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX
+            u_inverseTransposeWorldViewMatrix = INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX
+            u_ambientColor = 0.2, 0.2, 0.2
+            u_diffuseColor = 1.0, 1.0, 1.0, 1.0
+
+            // render state
+            renderState
+            {
+                cullFace = true
+                depthTest = true
+            }
+        }
+    }
+}

+ 72 - 0
gameplay-template/src/TemplateGame.cpp

@@ -0,0 +1,72 @@
+#include "TemplateGame.h"
+
+// Declare our game instance
+TemplateGame game;
+
+TemplateGame::TemplateGame()
+    : _scene(NULL)
+{
+}
+
+void TemplateGame::initialize()
+{
+    // Load game scene from file
+    Package* pkg = Package::create("res/box.gpb");
+    _scene = pkg->loadScene();
+    SAFE_RELEASE(pkg);
+
+    // Get light node
+    Node* lightNode = _scene->findNode("directionalLight");
+    Light* light = lightNode->getLight();
+
+    // Initialize box model
+    Node* boxNode = _scene->findNode("box");
+    Model* boxModel = boxNode->getModel();
+    Material* boxMaterial = boxModel->setMaterial("res/box.material");
+    boxMaterial->getParameter("u_lightColor")->setValue(light->getColor());
+    boxMaterial->getParameter("u_lightDirection")->setValue(lightNode->getForwardVectorView());
+}
+
+void TemplateGame::finalize()
+{
+    SAFE_RELEASE(_scene);
+}
+
+void TemplateGame::update(long elapsedTime)
+{
+    // Rotate model
+    _scene->findNode("box")->rotateY(MATH_DEG_TO_RAD((float)elapsedTime / 1000.0f * 180.0f));
+}
+
+void TemplateGame::render(long elapsedTime)
+{
+    // Clear the color and depth buffers
+    clear(CLEAR_COLOR_DEPTH, Vector4::zero(), 1.0f, 0);
+
+    // Visit all the nodes in the scene for drawing
+    _scene->visit(this, &TemplateGame::drawScene);
+}
+
+bool TemplateGame::drawScene(Node* node, void* cookie)
+{
+    // If the node visited contains a model, draw it
+    Model* model = node->getModel(); 
+    if (model)
+    {
+        model->draw();
+    }
+    return true;
+}
+
+void TemplateGame::touch(int x, int y, int touchEvent)
+{
+    switch (touchEvent)
+    {
+    case Input::TOUCHEVENT_PRESS:
+        break;
+    case Input::TOUCHEVENT_RELEASE:
+        break;
+    case Input::TOUCHEVENT_MOVE:
+        break;
+    };
+}

+ 57 - 0
gameplay-template/src/TemplateGame.h

@@ -0,0 +1,57 @@
+#ifndef TEMPLATEGAME_H_
+#define TEMPLATEGAME_H_
+
+#include "gameplay.h"
+
+using namespace gameplay;
+
+/**
+ * Main game class.
+ */
+class TemplateGame: public Game
+{
+public:
+
+    /**
+     * Constructror.
+     */
+    TemplateGame();
+
+    /**
+     * Touch event handler.
+     */
+    void touch(int x, int y, int touchEvent);
+
+protected:
+
+    /**
+     * @see Game::initialize
+     */
+    void initialize();
+
+    /**
+     * @see Game::finalize
+     */
+    void finalize();
+
+    /**
+     * @see Game::update
+     */
+    void update(long elapsedTime);
+
+    /**
+     * @see Game::render
+     */
+    void render(long elapsedTime);
+
+private:
+
+    /**
+     * Draws the scene each frame.
+     */
+    bool drawScene(Node* node, void* cookie);
+
+    Scene* _scene;
+};
+
+#endif

+ 110 - 0
gameplay-template/template.bar-descriptor.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<qnx xmlns="http://www.qnx.com/schemas/application/1.0">
+
+<!-- BlackBerry Tablet OS application descriptor file.
+
+    Specifies parameters for identifying, installing, and launching native applications on BlackBerry Tablet OS.
+
+-->
+
+    <!-- A universally unique application identifier. Must be unique across all BlackBerry Tablet OS applications.
+         Using a reverse DNS-style name as the id is recommended. (Eg. com.example.ExampleApplication.) Required. -->
+    <id>TEMPLATE_UUID</id>
+
+    <!-- The name that is displayed in the BlackBerry Tablet OS application installer. 
+         May have multiple values for each language. See samples or xsd schema file. Optional. -->
+    <name>TEMPLATE_TITLE</name>
+
+    <!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade. 
+         Values can also be 1-part or 2-part. It is not necessary to have a 3-part value.
+         An updated version of application must have a versionNumber value higher than the previous version. Required. -->
+    <versionNumber>1.0.0</versionNumber>
+
+    <!-- Fourth digit segment of the package version. First three segments are taken from the 
+         <versionNumber> element.  Must be an integer from 0 to 2^16-1 -->
+    <buildId>1</buildId>
+
+    <!-- A string value (such as "v1", "2.5", or "Alpha 1") that represents the version of the application, as it should be shown to users. Optional. -->
+    <!-- <versionLabel></versionLabel> -->
+
+    <!-- Description, displayed in the BlackBerry Tablet OS application installer.
+         May have multiple values for each language. See samples or xsd schema file. Optional. -->
+    <description>TEMPLATE_DESCRIPTION</description>
+    
+    <!-- Copyright information. Optional. -->
+    <!-- <copyright></copyright> -->
+
+    <!--  Name of author which is used for signing. Must match the developer name of your development certificate. -->
+    <author>TEMPLATE_AUTHOR</author>
+
+    <!--  Unique author ID assigned by signing authority. Required if using debug tokens. -->
+    <!-- <authorId>ABC1234YjsnUk235h</authorId> -->
+
+    <initialWindow>
+        <aspectRatio>landscape</aspectRatio>
+        <autoOrients>false</autoOrients>
+        <systemChrome>none</systemChrome>
+        <transparent>false</transparent>
+    </initialWindow>
+
+    <!--  The category where the application appears. Either core.games or core.media. -->
+    <category>core.games</category>
+
+    <asset path="icon.png">icon.png</asset>
+    <asset path="res">res</asset>
+
+    <configuration id="com.qnx.qcc.configuration.exe.debug.242437683" name="Device-Debug">
+       <platformArchitecture>armle-v7</platformArchitecture>
+       <asset path="Device-Debug/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+    <configuration id="com.qnx.qcc.configuration.exe.release.693953760" name="Device-Release">
+       <platformArchitecture>armle-v7</platformArchitecture>
+       <asset path="Device-Release/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+    <configuration id="com.qnx.qcc.configuration.exe.profile.1278883794" name="Device-Profile">
+       <platformArchitecture>armle-v7</platformArchitecture>
+       <asset path="Device-Profile/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+    <configuration id="com.qnx.qcc.configuration.exe.profile.coverage.357266346" name="Device-Coverage">
+       <platformArchitecture>armle-v7</platformArchitecture>
+       <asset path="Device-Coverage/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+    <configuration id="com.qnx.qcc.configuration.exe.debug.882133523" name="Simulator">
+        <platformArchitecture>x86</platformArchitecture>
+       <asset path="Simulator/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+    <configuration id="com.qnx.qcc.configuration.exe.profile.400335078" name="Simulator-Profile">
+       <platformArchitecture>x86</platformArchitecture> 
+       <asset path="Simulator-Profile/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+    <configuration id="com.qnx.qcc.configuration.exe.profile.coverage.48235134" name="Simulator-Coverage">
+       <platformArchitecture>x86</platformArchitecture>
+       <asset path="Simulator-Coverage/TEMPLATE_PROJECT" entry="true" type="Qnx/Elf">TEMPLATE_PROJECT</asset>
+    </configuration>
+
+    <!--  The icon for the application, which should be 86x86. -->
+    <icon>
+        <image>icon.png</image>
+    </icon>
+
+    <!--  The splash screen that will appear when your application is launching. Should be 1024x600. -->
+    <!-- <splashscreen></splashscreen> -->
+
+    <!-- Request permission to execute native code.  Required for native applications. -->
+    <action system="true">run_native</action>
+
+    <!--  The permissions requested by your application. -->
+    <!--  <action>access_shared</action> -->
+    <!--  <action>record_audio</action> -->
+    <!--  <action>read_geolocation</action> -->
+    <!--  <action>use_camera</action> -->
+    <!--  <action>access_internet</action> -->
+    <!--  <action>play_audio</action> -->
+    <!--  <action>post_notification</action> -->
+    <!--  <action>set_audio_volume</action> -->
+    <!--  <action>read_device_identifying_information</action> -->
+
+    <!-- Ensure that shared libraries in the package are found at run-time. -->
+    <env var="LD_LIBRARY_PATH" value="app/native/lib"/>
+
+</qnx>

+ 600 - 0
gameplay-template/template.cproject

@@ -0,0 +1,600 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+	<storageModule moduleId="org.eclipse.cdt.core.settings">
+		<cconfiguration id="com.qnx.qcc.configuration.exe.debug.242437683">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.debug.242437683" moduleId="org.eclipse.cdt.core.settings" name="Device-Debug">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="" id="com.qnx.qcc.configuration.exe.debug.242437683" name="Device-Debug" parent="com.qnx.qcc.configuration.exe.debug">
+					<folderInfo id="com.qnx.qcc.configuration.exe.debug.242437683." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.debug.1457920850" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<option id="com.qnx.qcc.option.cpu.543140018" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.284407654" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Device-Debug}" id="cdt.managedbuild.target.gnu.builder.base.505389028" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.208366882" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compile.debug.139715017" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.security.1844270687" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.2033387229" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.1368017357" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.220599794" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.553483674" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.debug.1729293963" name="Debug (-g)" superClass="com.qnx.qcc.option.assembler.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.assembler.includePath.554649657" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.1501021992" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.206151014" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.debug.1106710686" name="Debug (-g)" superClass="com.qnx.qcc.option.linker.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.langcpp.1026800223" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.security.971898295" name="Enhanced Security (-Wl,-z,relro -Wl,-z,now)" superClass="com.qnx.qcc.option.linker.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.1429533021" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/arm&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/arm&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.1174766388" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.149610709" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.1629441407" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+		<cconfiguration id="com.qnx.qcc.configuration.exe.release.693953760">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.release.693953760" moduleId="org.eclipse.cdt.core.settings" name="Device-Release">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="" id="com.qnx.qcc.configuration.exe.release.693953760" name="Device-Release" parent="com.qnx.qcc.configuration.exe.release">
+					<folderInfo id="com.qnx.qcc.configuration.exe.release.693953760." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.release.980420031" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<option id="com.qnx.qcc.option.cpu.1761526343" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.505505845" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Device-Release}" id="cdt.managedbuild.target.gnu.builder.base.754548990" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.1859104517" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compiler.optlevel.1503352761" name="Optimization Level" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.2" valueType="enumerated"/>
+								<option id="com.qnx.qcc.option.compiler.security.1558473615" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.679430995" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.1438345058" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.145250449" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.2006281313" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.includePath.502102557" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.568619293" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.2142228322" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.langcpp.626501515" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.security.5968719" name="Enhanced Security (-Wl,-z,relro -Wl,-z,now)" superClass="com.qnx.qcc.option.linker.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.1406850381" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/arm&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/arm&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.380839761" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.1335515313" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.277430725" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+		<cconfiguration id="com.qnx.qcc.configuration.exe.profile.1278883794">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.profile.1278883794" moduleId="org.eclipse.cdt.core.settings" name="Device-Profile">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=com.qnx.buildType.profile,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="Build for Profiling" id="com.qnx.qcc.configuration.exe.profile.1278883794" name="Device-Profile" parent="com.qnx.qcc.configuration.exe.profile">
+					<folderInfo id="com.qnx.qcc.configuration.exe.profile.1278883794." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.profile.1845991974" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<option id="com.qnx.qcc.option.cpu.841582420" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.291641862" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Device-Profile}" id="cdt.managedbuild.target.gnu.builder.base.213445888" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.614386334" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compile.debug.2016842657" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.profile2.654771532" name="Build for Profiling (Function Instrumentation) (-finstrument-functions)" superClass="com.qnx.qcc.option.compiler.profile2" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.security.1750208647" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.426444242" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.2039847498" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.1151876862" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.502016742" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.debug.1770496608" name="Debug (-g)" superClass="com.qnx.qcc.option.assembler.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.assembler.includePath.2105725346" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.892399553" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.870506839" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.debug.159182844" name="Debug (-g)" superClass="com.qnx.qcc.option.linker.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.profile2.2063219966" name="Build for Profiling (Function Instrumentation) (-lprofiling)" superClass="com.qnx.qcc.option.linker.profile2" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.langcpp.1041029842" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.855849190" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/arm&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/arm&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.248496823" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.321831739" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.1255321054" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+		<cconfiguration id="com.qnx.qcc.configuration.exe.profile.coverage.357266346">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.profile.coverage.357266346" moduleId="org.eclipse.cdt.core.settings" name="Device-Coverage">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=com.qnx.buildType.coverage,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="Build for Code Coverage" id="com.qnx.qcc.configuration.exe.profile.coverage.357266346" name="Device-Coverage" parent="com.qnx.qcc.configuration.exe.profile.coverage" prebuildStep="">
+					<folderInfo id="com.qnx.qcc.configuration.exe.profile.coverage.357266346." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.coverage.1058841174" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<option id="com.qnx.qcc.option.cpu.1763443935" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1557345848" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Device-Coverage}" id="cdt.managedbuild.target.gnu.builder.base.990549776" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.2123563242" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compile.debug.1458020405" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.coverage.2144528412" name="Build for Code Coverage (-Wc,-ftest-coverage -Wc,-fprofile-arcs)" superClass="com.qnx.qcc.option.compiler.coverage" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.security.1880137880" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.418753612" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.197126708" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.383272251" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.1630912693" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.debug.1688927362" name="Debug (-g)" superClass="com.qnx.qcc.option.assembler.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.assembler.includePath.1590514238" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.2106145451" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.511201149" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.debug.1991187080" name="Debug (-g)" superClass="com.qnx.qcc.option.linker.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.coverage.1187156961" name="Build for Code Coverage (-ftest-coverage -fprofile-arcs -p)" superClass="com.qnx.qcc.option.linker.coverage" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.langcpp.2094559243" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.security.206602965" name="Enhanced Security (-Wl,-z,relro -Wl,-z,now)" superClass="com.qnx.qcc.option.linker.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.1026501146" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/arm&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/arm&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.955918617" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.1922788653" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.658460952" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+		<cconfiguration id="com.qnx.qcc.configuration.exe.debug.882133523">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.debug.882133523" moduleId="org.eclipse.cdt.core.settings" name="Simulator">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="" id="com.qnx.qcc.configuration.exe.debug.882133523" name="Simulator" parent="com.qnx.qcc.configuration.exe.debug">
+					<folderInfo id="com.qnx.qcc.configuration.exe.debug.882133523." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.debug.263886238" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.826917653" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Simulator}" id="cdt.managedbuild.target.gnu.builder.base.1025219170" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.1408625066" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compile.debug.1248630188" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.security.2051337094" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.1669819974" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.456477750" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.2030100054" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.1374999439" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.debug.1499237946" name="Debug (-g)" superClass="com.qnx.qcc.option.assembler.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.assembler.includePath.1839603063" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.2093972194" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.280868975" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.debug.253431522" name="Debug (-g)" superClass="com.qnx.qcc.option.linker.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.langcpp.297105836" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.security.926891584" name="Enhanced Security (-Wl,-z,relro -Wl,-z,now)" superClass="com.qnx.qcc.option.linker.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.1127080358" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/x86/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/x86/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/x86&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/x86&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.298922406" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.1669353763" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.152598842" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+		<cconfiguration id="com.qnx.qcc.configuration.exe.profile.400335078">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.profile.400335078" moduleId="org.eclipse.cdt.core.settings" name="Simulator-Profile">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=com.qnx.buildType.profile,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="Build for Profiling" id="com.qnx.qcc.configuration.exe.profile.400335078" name="Simulator-Profile" parent="com.qnx.qcc.configuration.exe.profile">
+					<folderInfo id="com.qnx.qcc.configuration.exe.profile.400335078." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.profile.339344565" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.900231101" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Simulator-Profile}" id="cdt.managedbuild.target.gnu.builder.base.134792332" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.1403486104" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compile.debug.505574977" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.profile2.486301444" name="Build for Profiling (Function Instrumentation) (-finstrument-functions)" superClass="com.qnx.qcc.option.compiler.profile2" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.security.1360526671" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.740035068" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.923690234" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.1329574373" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.1843174104" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.debug.28838627" name="Debug (-g)" superClass="com.qnx.qcc.option.assembler.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.assembler.includePath.1935823127" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.429310796" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.412411076" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.debug.1336651609" name="Debug (-g)" superClass="com.qnx.qcc.option.linker.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.profile2.1986678601" name="Build for Profiling (Function Instrumentation) (-lprofiling)" superClass="com.qnx.qcc.option.linker.profile2" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.langcpp.634706544" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.security.1149202874" name="Enhanced Security (-Wl,-z,relro -Wl,-z,now)" superClass="com.qnx.qcc.option.linker.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.836471121" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/arm&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/arm&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.1203875316" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.387004436" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.1976882839" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+		<cconfiguration id="com.qnx.qcc.configuration.exe.profile.coverage.48235134">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.configuration.exe.profile.coverage.48235134" moduleId="org.eclipse.cdt.core.settings" name="Simulator-Coverage">
+				<externalSettings/>
+				<extensions>
+					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="com.qnx.tools.ide.qde.core.QDELinkerErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=com.qnx.buildType.coverage,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" description="Build for Code Coverage" id="com.qnx.qcc.configuration.exe.profile.coverage.48235134" name="Simulator-Coverage" parent="com.qnx.qcc.configuration.exe.profile.coverage">
+					<folderInfo id="com.qnx.qcc.configuration.exe.profile.coverage.48235134." name="/" resourcePath="">
+						<toolChain id="com.qnx.qcc.toolChain.exe.coverage.1175317875" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
+							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1428636360" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
+							<builder buildPath="${workspace_loc:/TEMPLATE_PROJECT/Simulator-Coverage}" id="cdt.managedbuild.target.gnu.builder.base.781926995" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<tool id="com.qnx.qcc.tool.compiler.1261670176" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
+								<option id="com.qnx.qcc.option.compile.debug.62201864" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.coverage.1226618626" name="Build for Code Coverage (-Wc,-ftest-coverage -Wc,-fprofile-arcs)" superClass="com.qnx.qcc.option.compiler.coverage" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.security.1008693238" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.compiler.defines.2042809726" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+								</option>
+								<option id="com.qnx.qcc.option.compiler.includePath.1486948386" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/include&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.compiler.1418704610" superClass="com.qnx.qcc.inputType.compiler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.assembler.785476179" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
+								<option id="com.qnx.qcc.option.assembler.debug.1374788951" name="Debug (-g)" superClass="com.qnx.qcc.option.assembler.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.assembler.includePath.1019783363" name="Include Directories (-I)" superClass="com.qnx.qcc.option.assembler.includePath" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/src&quot;"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.assembler.1637789752" superClass="com.qnx.qcc.inputType.assembler"/>
+							</tool>
+							<tool id="com.qnx.qcc.tool.linker.1825130130" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
+								<option id="com.qnx.qcc.option.linker.debug.773346051" name="Debug (-g)" superClass="com.qnx.qcc.option.linker.debug" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.coverage.1662322557" name="Build for Code Coverage (-ftest-coverage -fprofile-arcs -p)" superClass="com.qnx.qcc.option.linker.coverage" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.langcpp.1437332425" name="C++ (-lang-c++)" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.security.1625644976" name="Enhanced Security (-Wl,-z,relro -Wl,-z,now)" superClass="com.qnx.qcc.option.linker.security" value="true" valueType="boolean"/>
+								<option id="com.qnx.qcc.option.linker.libraryPaths.1870486762" name="Library Paths (-L)" superClass="com.qnx.qcc.option.linker.libraryPaths" valueType="libPaths">
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/lib"/>
+									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/armle-v7/usr/lib"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/gameplay/${ConfigName}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/bullet/lib/qnx/arm&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}}/GAMEPLAY_PATH/external-deps/oggvorbis/lib/qnx/arm&quot;"/>
+								</option>
+								<option id="com.qnx.qcc.option.linker.libraries.2055007034" name="Libraries (-l)" superClass="com.qnx.qcc.option.linker.libraries" valueType="libs">
+									<listOptionValue builtIn="false" value="GLESv2"/>
+									<listOptionValue builtIn="false" value="EGL"/>
+									<listOptionValue builtIn="false" value="screen"/>
+									<listOptionValue builtIn="false" value="m"/>
+									<listOptionValue builtIn="false" value="png14"/>
+									<listOptionValue builtIn="false" value="pps"/>
+									<listOptionValue builtIn="false" value="bps"/>
+									<listOptionValue builtIn="false" value="OpenAL"/>
+									<listOptionValue builtIn="false" value="asound"/>
+									<listOptionValue builtIn="false" value="gameplay"/>
+									<listOptionValue builtIn="false" value="bullet"/>
+									<listOptionValue builtIn="false" value="vorbis"/>
+								</option>
+								<inputType id="com.qnx.qcc.inputType.linker.47190931" superClass="com.qnx.qcc.inputType.linker">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+									<additionalInput kind="additionaldependency" paths="$(LIB_DEPS)"/>
+								</inputType>
+							</tool>
+							<tool id="com.qnx.qcc.tool.archiver.216978419" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="src"/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+		</cconfiguration>
+	</storageModule>
+	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+		<project id="TEMPLATE_UUID" name="TEMPLATE_PROJECT"/>
+	</storageModule>
+	<storageModule moduleId="scannerConfiguration">
+		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.release.693953760">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.profile.400335078">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.profile.coverage.48235134">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.debug.242437683">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.debug.882133523">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.profile.1278883794">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="com.qnx.qcc.configuration.exe.profile.coverage.357266346">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
+		</scannerConfigBuildInfo>
+	</storageModule>
+	<storageModule moduleId="refreshScope" versionNumber="1">
+		<resource resourceType="PROJECT" workspacePath="/TEMPLATE_PROJECT"/>
+	</storageModule>
+	<storageModule moduleId="com.qnx.tools.ide.qde.core.QNXProjectProperties"/>
+</cproject>

+ 87 - 0
gameplay-template/template.project

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>TEMPLATE_PROJECT</name>
+	<comment></comment>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+			<triggers>clean,full,incremental,</triggers>
+			<arguments>
+				<dictionary>
+					<key>?name?</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.append_environment</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildArguments</key>
+					<value></value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildCommand</key>
+					<value>make</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.buildLocation</key>
+					<value>${workspace_loc:/TEMPLATE_PROJECT/Device-Debug}</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+					<value>clean</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.contents</key>
+					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+					<value>false</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+					<value>all</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.stopOnError</key>
+					<value>true</value>
+				</dictionary>
+				<dictionary>
+					<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+					<value>true</value>
+				</dictionary>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+			<triggers>full,incremental,</triggers>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>com.qnx.tools.bbt.xml.core.bbtXMLValidationBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.cdt.core.cnature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+		<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+		<nature>com.qnx.tools.ide.bbt.core.bbtnature</nature>
+		<nature>org.eclipse.cdt.core.ccnature</nature>
+	</natures>
+</projectDescription>

+ 18 - 5
gameplay/gameplay.vcxproj

@@ -29,17 +29,20 @@
     <ClCompile Include="src\Camera.cpp" />
     <ClCompile Include="src\Curve.cpp" />
     <ClCompile Include="src\DebugNew.cpp" />
+    <ClCompile Include="src\DepthStencilTarget.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\FileSystem.cpp" />
     <ClCompile Include="src\Font.cpp" />
+    <ClCompile Include="src\FrameBuffer.cpp" />
     <ClCompile Include="src\Frustum.cpp" />
     <ClCompile Include="src\Game.cpp" />
     <ClCompile Include="src\gameplay-main-qnx.cpp" />
     <ClCompile Include="src\gameplay-main-win32.cpp" />
-    <ClCompile Include="src\Input.cpp" />
+    <ClCompile Include="src\Image.cpp" />
     <ClCompile Include="src\Joint.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\Material.cpp" />
+    <ClCompile Include="src\MeshBatch.cpp" />
     <ClCompile Include="src\Pass.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
     <ClCompile Include="src\Matrix.cpp" />
@@ -68,12 +71,12 @@
     <ClCompile Include="src\Rectangle.cpp" />
     <ClCompile Include="src\Ref.cpp" />
     <ClCompile Include="src\RenderState.cpp" />
+    <ClCompile Include="src\RenderTarget.cpp" />
     <ClCompile Include="src\Scene.cpp" />
     <ClCompile Include="src\SceneLoader.cpp" />
     <ClCompile Include="src\SpriteBatch.cpp" />
     <ClCompile Include="src\Technique.cpp" />
     <ClCompile Include="src\Texture.cpp" />
-    <ClCompile Include="src\Theme.cpp" />
     <ClCompile Include="src\Transform.cpp" />
     <ClCompile Include="src\Vector2.cpp" />
     <ClCompile Include="src\Vector3.cpp" />
@@ -98,16 +101,20 @@
     <ClInclude Include="src\Camera.h" />
     <ClInclude Include="src\Curve.h" />
     <ClInclude Include="src\DebugNew.h" />
+    <ClInclude Include="src\DepthStencilTarget.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\FileSystem.h" />
     <ClInclude Include="src\Font.h" />
+    <ClInclude Include="src\FrameBuffer.h" />
     <ClInclude Include="src\Frustum.h" />
     <ClInclude Include="src\Game.h" />
     <ClInclude Include="src\gameplay.h" />
-    <ClInclude Include="src\Input.h" />
+    <ClInclude Include="src\Image.h" />
     <ClInclude Include="src\Joint.h" />
+    <ClInclude Include="src\Keyboard.h" />
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\Material.h" />
+    <ClInclude Include="src\MeshBatch.h" />
     <ClInclude Include="src\Pass.h" />
     <ClInclude Include="src\MaterialParameter.h" />
     <ClInclude Include="src\Matrix.h" />
@@ -135,12 +142,13 @@
     <ClInclude Include="src\Rectangle.h" />
     <ClInclude Include="src\Ref.h" />
     <ClInclude Include="src\RenderState.h" />
+    <ClInclude Include="src\RenderTarget.h" />
     <ClInclude Include="src\Scene.h" />
     <ClInclude Include="src\SceneLoader.h" />
     <ClInclude Include="src\SpriteBatch.h" />
     <ClInclude Include="src\Technique.h" />
     <ClInclude Include="src\Texture.h" />
-    <ClInclude Include="src\Theme.h" />
+    <ClInclude Include="src\Touch.h" />
     <ClInclude Include="src\Transform.h" />
     <ClInclude Include="src\Vector2.h" />
     <ClInclude Include="src\Vector3.h" />
@@ -170,10 +178,15 @@
     <None Include="res\shaders\solid.vsh" />
     <None Include="res\shaders\textured.fsh" />
     <None Include="res\shaders\textured.vsh" />
+    <None Include="res\textures\particle-default.png" />
     <None Include="src\BoundingBox.inl" />
     <None Include="src\BoundingSphere.inl" />
+    <None Include="src\Curve.inl" />
+    <None Include="src\Game.inl" />
     <None Include="src\gameplay-main-macos.mm" />
+    <None Include="src\Image.inl" />
     <None Include="src\Matrix.inl" />
+    <None Include="src\MeshBatch.inl" />
     <None Include="src\Plane.inl" />
     <None Include="src\PlatformMacOS.mm" />
     <None Include="src\Quaternion.inl" />
@@ -300,4 +313,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>

+ 181 - 519
gameplay/gameplay.vcxproj.filters

@@ -1,527 +1,189 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <Filter Include="src">
-      <UniqueIdentifier>{c4d4da1c-81e2-4944-901c-200e1c4d80e5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="res">
-      <UniqueIdentifier>{4a30ac71-e135-47d3-9f56-baac7cffe64c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="res\shaders">
-      <UniqueIdentifier>{be0b36f1-49ed-4a06-9f1f-57c654a554fe}</UniqueIdentifier>
-    </Filter>
+    <ClCompile Include="src\Animation.cpp" />
+    <ClCompile Include="src\AnimationClip.cpp" />
+    <ClCompile Include="src\AnimationController.cpp" />
+    <ClCompile Include="src\AnimationTarget.cpp" />
+    <ClCompile Include="src\AnimationValue.cpp" />
+    <ClCompile Include="src\AudioBuffer.cpp" />
+    <ClCompile Include="src\AudioController.cpp" />
+    <ClCompile Include="src\AudioListener.cpp" />
+    <ClCompile Include="src\AudioSource.cpp" />
+    <ClCompile Include="src\BoundingBox.cpp" />
+    <ClCompile Include="src\BoundingSphere.cpp" />
+    <ClCompile Include="src\Camera.cpp" />
+    <ClCompile Include="src\Curve.cpp" />
+    <ClCompile Include="src\DebugNew.cpp" />
+    <ClCompile Include="src\DepthStencilTarget.cpp" />
+    <ClCompile Include="src\Effect.cpp" />
+    <ClCompile Include="src\FileSystem.cpp" />
+    <ClCompile Include="src\Font.cpp" />
+    <ClCompile Include="src\FrameBuffer.cpp" />
+    <ClCompile Include="src\Frustum.cpp" />
+    <ClCompile Include="src\Game.cpp" />
+    <ClCompile Include="src\gameplay-main-qnx.cpp" />
+    <ClCompile Include="src\gameplay-main-win32.cpp" />
+    <ClCompile Include="src\Image.cpp" />
+    <ClCompile Include="src\Joint.cpp" />
+    <ClCompile Include="src\Light.cpp" />
+    <ClCompile Include="src\Material.cpp" />
+    <ClCompile Include="src\MeshBatch.cpp" />
+    <ClCompile Include="src\Pass.cpp" />
+    <ClCompile Include="src\MaterialParameter.cpp" />
+    <ClCompile Include="src\Matrix.cpp" />
+    <ClCompile Include="src\Mesh.cpp" />
+    <ClCompile Include="src\MeshPart.cpp" />
+    <ClCompile Include="src\MeshSkin.cpp" />
+    <ClCompile Include="src\Model.cpp" />
+    <ClCompile Include="src\Node.cpp" />
+    <ClCompile Include="src\Package.cpp" />
+    <ClCompile Include="src\ParticleEmitter.cpp" />
+    <ClCompile Include="src\PhysicsConstraint.cpp" />
+    <ClCompile Include="src\PhysicsController.cpp" />
+    <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
+    <ClCompile Include="src\PhysicsGenericConstraint.cpp" />
+    <ClCompile Include="src\PhysicsHingeConstraint.cpp" />
+    <ClCompile Include="src\PhysicsMotionState.cpp" />
+    <ClCompile Include="src\PhysicsRigidBody.cpp" />
+    <ClCompile Include="src\PhysicsSocketConstraint.cpp" />
+    <ClCompile Include="src\PhysicsSpringConstraint.cpp" />
+    <ClCompile Include="src\Plane.cpp" />
+    <ClCompile Include="src\PlatformQNX.cpp" />
+    <ClCompile Include="src\PlatformWin32.cpp" />
+    <ClCompile Include="src\Properties.cpp" />
+    <ClCompile Include="src\Quaternion.cpp" />
+    <ClCompile Include="src\Ray.cpp" />
+    <ClCompile Include="src\Rectangle.cpp" />
+    <ClCompile Include="src\Ref.cpp" />
+    <ClCompile Include="src\RenderState.cpp" />
+    <ClCompile Include="src\RenderTarget.cpp" />
+    <ClCompile Include="src\Scene.cpp" />
+    <ClCompile Include="src\SceneLoader.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" />
+    <ClCompile Include="src\Vector3.cpp" />
+    <ClCompile Include="src\Vector4.cpp" />
+    <ClCompile Include="src\VertexAttributeBinding.cpp" />
+    <ClCompile Include="src\VertexFormat.cpp" />
+    <ClCompile Include="src\Viewport.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="src\Animation.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationClip.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationValue.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\BoundingBox.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\BoundingSphere.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Camera.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Curve.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Effect.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\FileSystem.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Font.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Frustum.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Game.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Input.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Light.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Matrix.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Mesh.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MeshPart.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MeshSkin.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Model.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Node.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Package.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Plane.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PlatformQNX.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PlatformWin32.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Quaternion.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Ray.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Rectangle.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Ref.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Scene.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SpriteBatch.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Texture.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Transform.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector2.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector3.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector4.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\VertexAttributeBinding.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\VertexFormat.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Viewport.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioListener.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioSource.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioBuffer.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationTarget.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MaterialParameter.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Joint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ParticleEmitter.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <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>
-    <ClCompile Include="src\gameplay-main-qnx.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\gameplay-main-win32.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\DebugNew.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsRigidBody.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsHingeConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsFixedConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsGenericConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsSocketConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsSpringConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsMotionState.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-<<<<<<< HEAD
-    <ClCompile Include="src\Gamepad.cpp" />
-    <ClCompile Include="src\Theme.cpp">
-=======
-    <ClCompile Include="src\SceneLoader.cpp">
->>>>>>> 187027bc8c14ffd1c894cee0793284c5a5238090
-      <Filter>src</Filter>
-    </ClCompile>
+    <ClInclude Include="src\Animation.h" />
+    <ClInclude Include="src\AnimationClip.h" />
+    <ClInclude Include="src\AnimationController.h" />
+    <ClInclude Include="src\AnimationTarget.h" />
+    <ClInclude Include="src\AnimationValue.h" />
+    <ClInclude Include="src\AudioBuffer.h" />
+    <ClInclude Include="src\AudioController.h" />
+    <ClInclude Include="src\AudioListener.h" />
+    <ClInclude Include="src\AudioSource.h" />
+    <ClInclude Include="src\Base.h" />
+    <ClInclude Include="src\BoundingBox.h" />
+    <ClInclude Include="src\BoundingSphere.h" />
+    <ClInclude Include="src\Camera.h" />
+    <ClInclude Include="src\Curve.h" />
+    <ClInclude Include="src\DebugNew.h" />
+    <ClInclude Include="src\DepthStencilTarget.h" />
+    <ClInclude Include="src\Effect.h" />
+    <ClInclude Include="src\FileSystem.h" />
+    <ClInclude Include="src\Font.h" />
+    <ClInclude Include="src\FrameBuffer.h" />
+    <ClInclude Include="src\Frustum.h" />
+    <ClInclude Include="src\Game.h" />
+    <ClInclude Include="src\gameplay.h" />
+    <ClInclude Include="src\Image.h" />
+    <ClInclude Include="src\Joint.h" />
+    <ClInclude Include="src\Keyboard.h" />
+    <ClInclude Include="src\Light.h" />
+    <ClInclude Include="src\Material.h" />
+    <ClInclude Include="src\MeshBatch.h" />
+    <ClInclude Include="src\Pass.h" />
+    <ClInclude Include="src\MaterialParameter.h" />
+    <ClInclude Include="src\Matrix.h" />
+    <ClInclude Include="src\Mesh.h" />
+    <ClInclude Include="src\MeshPart.h" />
+    <ClInclude Include="src\MeshSkin.h" />
+    <ClInclude Include="src\Model.h" />
+    <ClInclude Include="src\Node.h" />
+    <ClInclude Include="src\Package.h" />
+    <ClInclude Include="src\ParticleEmitter.h" />
+    <ClInclude Include="src\PhysicsConstraint.h" />
+    <ClInclude Include="src\PhysicsController.h" />
+    <ClInclude Include="src\PhysicsFixedConstraint.h" />
+    <ClInclude Include="src\PhysicsGenericConstraint.h" />
+    <ClInclude Include="src\PhysicsHingeConstraint.h" />
+    <ClInclude Include="src\PhysicsMotionState.h" />
+    <ClInclude Include="src\PhysicsRigidBody.h" />
+    <ClInclude Include="src\PhysicsSocketConstraint.h" />
+    <ClInclude Include="src\PhysicsSpringConstraint.h" />
+    <ClInclude Include="src\Plane.h" />
+    <ClInclude Include="src\Platform.h" />
+    <ClInclude Include="src\Properties.h" />
+    <ClInclude Include="src\Quaternion.h" />
+    <ClInclude Include="src\Ray.h" />
+    <ClInclude Include="src\Rectangle.h" />
+    <ClInclude Include="src\Ref.h" />
+    <ClInclude Include="src\RenderState.h" />
+    <ClInclude Include="src\RenderTarget.h" />
+    <ClInclude Include="src\Scene.h" />
+    <ClInclude Include="src\SceneLoader.h" />
+    <ClInclude Include="src\SpriteBatch.h" />
+    <ClInclude Include="src\Technique.h" />
+    <ClInclude Include="src\Texture.h" />
+    <ClInclude Include="src\Touch.h" />
+    <ClInclude Include="src\Transform.h" />
+    <ClInclude Include="src\Vector2.h" />
+    <ClInclude Include="src\Vector3.h" />
+    <ClInclude Include="src\Vector4.h" />
+    <ClInclude Include="src\VertexAttributeBinding.h" />
+    <ClInclude Include="src\VertexFormat.h" />
+    <ClInclude Include="src\Viewport.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="src\Animation.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationClip.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationTarget.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationValue.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Base.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\BoundingBox.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\BoundingSphere.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Camera.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Curve.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Effect.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\FileSystem.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Font.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Frustum.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Game.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\gameplay.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Input.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Light.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Matrix.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Mesh.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MeshPart.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MeshSkin.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Model.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Node.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Package.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Plane.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Platform.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Quaternion.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Ray.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Rectangle.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Ref.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Scene.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SpriteBatch.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Texture.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Transform.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Vector2.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Vector3.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Vector4.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VertexAttributeBinding.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VertexFormat.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Viewport.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioListener.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioSource.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioBuffer.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MaterialParameter.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Joint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ParticleEmitter.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <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\DebugNew.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsMotionState.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsRigidBody.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsSpringConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsFixedConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsGenericConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsHingeConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsSocketConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-<<<<<<< HEAD
-    <ClInclude Include="src\Gamepad.h" />
-    <ClInclude Include="src\Theme.h">
-=======
-    <ClInclude Include="src\SceneLoader.h">
->>>>>>> 187027bc8c14ffd1c894cee0793284c5a5238090
-      <Filter>src</Filter>
-    </ClInclude>
+    <None Include="res\shaders\bumped-specular.fsh" />
+    <None Include="res\shaders\bumped-specular.vsh" />
+    <None Include="res\shaders\bumped.fsh" />
+    <None Include="res\shaders\bumped.vsh" />
+    <None Include="res\shaders\colored-specular.fsh" />
+    <None Include="res\shaders\colored-specular.vsh" />
+    <None Include="res\shaders\colored.fsh" />
+    <None Include="res\shaders\colored.vsh" />
+    <None Include="res\shaders\diffuse-specular.fsh" />
+    <None Include="res\shaders\diffuse-specular.vsh" />
+    <None Include="res\shaders\diffuse.fsh" />
+    <None Include="res\shaders\diffuse.vsh" />
+    <None Include="res\shaders\parallax-specular.fsh" />
+    <None Include="res\shaders\parallax-specular.vsh" />
+    <None Include="res\shaders\parallax.fsh" />
+    <None Include="res\shaders\parallax.vsh" />
+    <None Include="res\shaders\solid.fsh" />
+    <None Include="res\shaders\solid.vsh" />
+    <None Include="res\shaders\textured.fsh" />
+    <None Include="res\shaders\textured.vsh" />
+    <None Include="res\textures\particle-default.png" />
+    <None Include="src\BoundingBox.inl" />
+    <None Include="src\BoundingSphere.inl" />
+    <None Include="src\Curve.inl" />
+    <None Include="src\Game.inl" />
+    <None Include="src\gameplay-main-macos.mm" />
+    <None Include="src\Image.inl" />
+    <None Include="src\Matrix.inl" />
+    <None Include="src\MeshBatch.inl" />
+    <None Include="src\Plane.inl" />
+    <None Include="src\PlatformMacOS.mm" />
+    <None Include="src\Quaternion.inl" />
+    <None Include="src\Ray.inl" />
+    <None Include="src\Vector2.inl" />
+    <None Include="src\Vector3.inl" />
+    <None Include="src\Vector4.inl" />
+    <None Include="src\PhysicsConstraint.inl" />
+    <None Include="src\PhysicsFixedConstraint.inl" />
+    <None Include="src\PhysicsGenericConstraint.inl" />
+    <None Include="src\PhysicsRigidBody.inl" />
+    <None Include="src\PhysicsSpringConstraint.inl" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="res\shaders\bumped-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\diffuse-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\parallax-specular.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\solid.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\solid.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\textured.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\textured.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped.vsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\bumped-specular.fsh">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="src\gameplay-main-macos.mm">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PlatformMacOS.mm">
-      <Filter>src</Filter>
-    </None>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="src\PhysicsFixedConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\BoundingBox.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsGenericConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\BoundingSphere.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsSpringConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Matrix.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsRigidBody.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Plane.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Quaternion.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Ray.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Vector2.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Vector3.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Vector4.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-  </ItemGroup>
-</Project>
+</Project>

+ 32 - 8
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -7,6 +7,12 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		4201819014A41B18008C3F56 /* MeshBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4201818D14A41B18008C3F56 /* MeshBatch.cpp */; };
+		4201819114A41B18008C3F56 /* MeshBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4201818E14A41B18008C3F56 /* MeshBatch.h */; };
+		4208DEE914A4079F00D3C511 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4208DEE614A4079F00D3C511 /* Image.cpp */; };
+		4208DEEA14A4079F00D3C511 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEE714A4079F00D3C511 /* Image.h */; };
+		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
+		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
 		4220A6E8146B122B00CAEB3A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4220A6E7146B122B00CAEB3A /* QuartzCore.framework */; };
 		4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4234D99D14686C52003031B3 /* Cocoa.framework */; };
 		428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
@@ -67,8 +73,6 @@
 		42CD0E72147D8FF60000361E /* gameplay-main-qnx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */; };
 		42CD0E73147D8FF60000361E /* gameplay-main-win32.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */; };
 		42CD0E74147D8FF60000361E /* gameplay.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE1147D8FF50000361E /* gameplay.h */; };
-		42CD0E75147D8FF60000361E /* Input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE2147D8FF50000361E /* Input.cpp */; };
-		42CD0E76147D8FF60000361E /* Input.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE3147D8FF50000361E /* Input.h */; };
 		42CD0E77147D8FF60000361E /* Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE4147D8FF50000361E /* Joint.cpp */; };
 		42CD0E78147D8FF60000361E /* Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE5147D8FF50000361E /* Joint.h */; };
 		42CD0E79147D8FF60000361E /* Light.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE6147D8FF50000361E /* Light.cpp */; };
@@ -158,6 +162,15 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
+		4201818D14A41B18008C3F56 /* MeshBatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MeshBatch.cpp; path = src/MeshBatch.cpp; sourceTree = SOURCE_ROOT; };
+		4201818E14A41B18008C3F56 /* MeshBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MeshBatch.h; path = src/MeshBatch.h; sourceTree = SOURCE_ROOT; };
+		4201818F14A41B18008C3F56 /* MeshBatch.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = MeshBatch.inl; path = src/MeshBatch.inl; sourceTree = SOURCE_ROOT; };
+		4208DEE514A4078100D3C511 /* Curve.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Curve.inl; path = src/Curve.inl; sourceTree = SOURCE_ROOT; };
+		4208DEE614A4079F00D3C511 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Image.cpp; path = src/Image.cpp; sourceTree = SOURCE_ROOT; };
+		4208DEE714A4079F00D3C511 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Image.h; path = src/Image.h; sourceTree = SOURCE_ROOT; };
+		4208DEE814A4079F00D3C511 /* Image.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Image.inl; path = src/Image.inl; sourceTree = SOURCE_ROOT; };
+		4208DEEB14A407B900D3C511 /* Keyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Keyboard.h; path = src/Keyboard.h; sourceTree = SOURCE_ROOT; };
+		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.h; sourceTree = SOURCE_ROOT; };
 		4220A6E7146B122B00CAEB3A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
 		4234D99A14686C52003031B3 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4234D99D14686C52003031B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
@@ -165,6 +178,7 @@
 		428390981489D6E800E2B2F5 /* SceneLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SceneLoader.h; path = src/SceneLoader.h; sourceTree = SOURCE_ROOT; };
 		4299EFA8146AC94300FF4A73 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenGL.framework; sourceTree = DEVELOPER_DIR; };
 		4299EFAA146AC94B00FF4A73 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		42C932AF14919FD10098216A /* Game.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Game.inl; path = src/Game.inl; sourceTree = SOURCE_ROOT; };
 		42CCD553146EC1DD00353661 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.7.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
 		42CCD555146EC1EB00353661 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
 		42CD0DA6147D8EA80000361E /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/macos/libbullet.a"; sourceTree = "<group>"; };
@@ -221,8 +235,6 @@
 		42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gameplay-main-qnx.cpp"; path = "src/gameplay-main-qnx.cpp"; sourceTree = SOURCE_ROOT; };
 		42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gameplay-main-win32.cpp"; path = "src/gameplay-main-win32.cpp"; sourceTree = SOURCE_ROOT; };
 		42CD0DE1147D8FF50000361E /* gameplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gameplay.h; path = src/gameplay.h; sourceTree = SOURCE_ROOT; };
-		42CD0DE2147D8FF50000361E /* Input.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Input.cpp; path = src/Input.cpp; sourceTree = SOURCE_ROOT; };
-		42CD0DE3147D8FF50000361E /* Input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Input.h; path = src/Input.h; sourceTree = SOURCE_ROOT; };
 		42CD0DE4147D8FF50000361E /* Joint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Joint.cpp; path = src/Joint.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DE5147D8FF50000361E /* Joint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Joint.h; path = src/Joint.h; sourceTree = SOURCE_ROOT; };
 		42CD0DE6147D8FF50000361E /* Light.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Light.cpp; path = src/Light.cpp; sourceTree = SOURCE_ROOT; };
@@ -395,6 +407,7 @@
 				42CD0DCB147D8FF50000361E /* Camera.h */,
 				42CD0DCC147D8FF50000361E /* Curve.cpp */,
 				42CD0DCD147D8FF50000361E /* Curve.h */,
+				4208DEE514A4078100D3C511 /* Curve.inl */,
 				42CD0DCE147D8FF50000361E /* DebugNew.cpp */,
 				42CD0DCF147D8FF50000361E /* DebugNew.h */,
 				42CD0DD0147D8FF50000361E /* DepthStencilTarget.cpp */,
@@ -411,14 +424,17 @@
 				42CD0DDB147D8FF50000361E /* Frustum.h */,
 				42CD0DDC147D8FF50000361E /* Game.cpp */,
 				42CD0DDD147D8FF50000361E /* Game.h */,
+				42C932AF14919FD10098216A /* Game.inl */,
 				42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */,
 				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
 				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
 				42CD0DE1147D8FF50000361E /* gameplay.h */,
-				42CD0DE2147D8FF50000361E /* Input.cpp */,
-				42CD0DE3147D8FF50000361E /* Input.h */,
+				4208DEE614A4079F00D3C511 /* Image.cpp */,
+				4208DEE714A4079F00D3C511 /* Image.h */,
+				4208DEE814A4079F00D3C511 /* Image.inl */,
 				42CD0DE4147D8FF50000361E /* Joint.cpp */,
 				42CD0DE5147D8FF50000361E /* Joint.h */,
+				4208DEEB14A407B900D3C511 /* Keyboard.h */,
 				42CD0DE6147D8FF50000361E /* Light.cpp */,
 				42CD0DE7147D8FF50000361E /* Light.h */,
 				42CD0DE8147D8FF50000361E /* Material.cpp */,
@@ -430,6 +446,9 @@
 				42CD0DEE147D8FF50000361E /* Matrix.inl */,
 				42CD0DEF147D8FF50000361E /* Mesh.cpp */,
 				42CD0DF0147D8FF50000361E /* Mesh.h */,
+				4201818D14A41B18008C3F56 /* MeshBatch.cpp */,
+				4201818E14A41B18008C3F56 /* MeshBatch.h */,
+				4201818F14A41B18008C3F56 /* MeshBatch.inl */,
 				42CD0DF1147D8FF50000361E /* MeshPart.cpp */,
 				42CD0DF2147D8FF50000361E /* MeshPart.h */,
 				42CD0DF3147D8FF50000361E /* MeshSkin.cpp */,
@@ -500,6 +519,7 @@
 				42CD0E32147D8FF50000361E /* Technique.h */,
 				42CD0E33147D8FF50000361E /* Texture.cpp */,
 				42CD0E34147D8FF50000361E /* Texture.h */,
+				4208DEED14A407D500D3C511 /* Touch.h */,
 				42CD0E35147D8FF50000361E /* Transform.cpp */,
 				42CD0E36147D8FF50000361E /* Transform.h */,
 				42CD0E37147D8FF50000361E /* Vector2.cpp */,
@@ -577,7 +597,6 @@
 				42CD0E6E147D8FF60000361E /* Frustum.h in Headers */,
 				42CD0E70147D8FF60000361E /* Game.h in Headers */,
 				42CD0E74147D8FF60000361E /* gameplay.h in Headers */,
-				42CD0E76147D8FF60000361E /* Input.h in Headers */,
 				42CD0E78147D8FF60000361E /* Joint.h in Headers */,
 				42CD0E7A147D8FF60000361E /* Light.h in Headers */,
 				42CD0E7C147D8FF60000361E /* Material.h in Headers */,
@@ -621,6 +640,10 @@
 				42CD0ECA147D8FF60000361E /* VertexFormat.h in Headers */,
 				42CD0ECC147D8FF60000361E /* Viewport.h in Headers */,
 				4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */,
+				4208DEEA14A4079F00D3C511 /* Image.h in Headers */,
+				4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */,
+				4208DEEE14A407D500D3C511 /* Touch.h in Headers */,
+				4201819114A41B18008C3F56 /* MeshBatch.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -698,7 +721,6 @@
 				42CD0E71147D8FF60000361E /* gameplay-main-macos.mm in Sources */,
 				42CD0E72147D8FF60000361E /* gameplay-main-qnx.cpp in Sources */,
 				42CD0E73147D8FF60000361E /* gameplay-main-win32.cpp in Sources */,
-				42CD0E75147D8FF60000361E /* Input.cpp in Sources */,
 				42CD0E77147D8FF60000361E /* Joint.cpp in Sources */,
 				42CD0E79147D8FF60000361E /* Light.cpp in Sources */,
 				42CD0E7B147D8FF60000361E /* Material.cpp in Sources */,
@@ -744,6 +766,8 @@
 				42CD0EC9147D8FF60000361E /* VertexFormat.cpp in Sources */,
 				42CD0ECB147D8FF60000361E /* Viewport.cpp in Sources */,
 				428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */,
+				4208DEE914A4079F00D3C511 /* Image.cpp in Sources */,
+				4201819014A41B18008C3F56 /* MeshBatch.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 2 - 2
gameplay/res/shaders/bumped-specular.vsh

@@ -59,7 +59,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    
@@ -96,7 +96,7 @@ vec3 getTangentSpaceVector(vec3 vector)
     skinTangentSpaceVector(vector, blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinTangentSpaceVector(vector, blendWeight, matrixIndex);
 
     return _skinnedNormal;

+ 2 - 2
gameplay/res/shaders/bumped.vsh

@@ -56,7 +56,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    
@@ -93,7 +93,7 @@ vec3 getTangentSpaceVector(vec3 vector)
     skinTangentSpaceVector(vector, blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinTangentSpaceVector(vector, blendWeight, matrixIndex);
 
     return _skinnedNormal;

+ 2 - 2
gameplay/res/shaders/colored-specular.vsh

@@ -57,7 +57,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    
@@ -94,7 +94,7 @@ vec3 getNormal()
     skinNormal(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinNormal(blendWeight, matrixIndex);
 
     return _skinnedNormal;

+ 2 - 2
gameplay/res/shaders/colored.vsh

@@ -53,7 +53,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    
@@ -90,7 +90,7 @@ vec3 getNormal()
     skinNormal(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinNormal(blendWeight, matrixIndex);
 
     return _skinnedNormal;

+ 2 - 2
gameplay/res/shaders/diffuse-specular.vsh

@@ -58,7 +58,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    
@@ -95,7 +95,7 @@ vec3 getNormal()
     skinNormal(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinNormal(blendWeight, matrixIndex);
 
     return _skinnedNormal;

+ 2 - 2
gameplay/res/shaders/diffuse.vsh

@@ -56,7 +56,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    
@@ -93,7 +93,7 @@ vec3 getNormal()
     skinNormal(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinNormal(blendWeight, matrixIndex);
 
     return _skinnedNormal;

+ 1 - 1
gameplay/res/shaders/textured.vsh

@@ -51,7 +51,7 @@ vec4 getPosition()
     skinPosition(blendWeight, matrixIndex);
 
     blendWeight = a_blendWeights[3];
-    matrixIndex = int(a_blendIndices[2]) * 3;
+    matrixIndex = int(a_blendIndices[3]) * 3;
     skinPosition(blendWeight, matrixIndex);
 
     return _skinnedPosition;    

BIN
gameplay/res/textures/particle-default.png


+ 101 - 112
gameplay/src/Animation.cpp

@@ -7,7 +7,6 @@
 #include "Transform.h"
 #include "Properties.h"
 
-#define ANIMATION_DEFAULT_CLIP_SUFFIX "__default__clip"
 #define ANIMATION_INDEFINITE_STR "INDEFINITE"
 #define ANIMATION_DEFAULT_CLIP 0
 #define ANIMATION_ROTATE_OFFSET 0
@@ -30,7 +29,13 @@ Animation::Animation(const char* id, AnimationTarget* target, int propertyId, un
 
 Animation::~Animation()
 {
-    if (_clips != NULL)
+    if (_defaultClip)
+    {
+        _defaultClip->stop();
+        SAFE_RELEASE(_defaultClip);
+    }
+
+    if (_clips)
     {
         std::vector<AnimationClip*>::iterator clipIter = _clips->begin();
     
@@ -44,18 +49,6 @@ Animation::~Animation()
         _clips->clear();
     }
     SAFE_DELETE(_clips);
-
-    SAFE_DELETE(_defaultClip);
-
-    /*vector<Channel*>::iterator channelIter = _channels.begin();
-    while (channelIter != _channels.end())
-    {
-        Animation::Channel* channel = *channelIter;
-        channel->_target->removeChannel(channel);
-        SAFE_RELEASE(channel);
-        channelIter++;
-    }*/
-    _channels.clear();
 }
 
 Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
@@ -71,9 +64,9 @@ Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int p
 
 Animation::Channel::~Channel()
 {
+    SAFE_DELETE(_curve);
     _animation->removeChannel(this);
     SAFE_RELEASE(_animation);
-    SAFE_DELETE(_curve);
 }
 
 const char* Animation::getId() const
@@ -90,60 +83,24 @@ void Animation::createClips(const char* animationFile)
 {
     assert(animationFile);
 
-    Properties* pAnim = Properties::create(animationFile);
-    assert(pAnim);
+    Properties* properties = Properties::create(animationFile);
+    assert(properties);
 
-    Properties* animation = pAnim->getNextNamespace();
-    int frameCount = animation->getInt("frameCount");
-
-    const Properties* pClip = animation->getNextNamespace();
-    while (pClip != NULL)
-    {
-        int begin = pClip->getInt("begin");
-        int end = pClip->getInt("end");
-
-        AnimationClip* clip = createClip(pClip->getId(), ((float) begin / frameCount) * _duration, ((float) end / frameCount) * _duration);
-
-        const char* repeat = pClip->getString("repeatCount");
-        if (repeat)
-        {
-            if (strcmp(repeat, ANIMATION_INDEFINITE_STR) == 0)
-            {
-                clip->setRepeatCount(AnimationClip::REPEAT_INDEFINITE);
-            }
-            else
-            {
-                float value;
-                sscanf(repeat, "%f", &value);
-                clip->setRepeatCount(value);
-            }
-        }
-
-        const char* speed = pClip->getString("speed");
-        if (speed)
-        {
-            float value;
-            sscanf(speed, "%f", &value);
-            clip->setSpeed(value);
-        }
+    Properties* pAnimation = properties->getNextNamespace();
+    assert(pAnimation);
+    
+    int frameCount = pAnimation->getInt("frameCount");
+    assert(frameCount > 0);
 
-        pClip = animation->getNextNamespace();
-    }
+    createClips(pAnimation, (unsigned int)frameCount);
 
-    SAFE_DELETE(pAnim);
+    SAFE_DELETE(properties);
 }
 
 AnimationClip* Animation::createClip(const char* id, unsigned long start, unsigned long end)
 {
-    if (_clips != NULL && findClip(id) != NULL)
-    {
-        return NULL;
-    }
-    
     AnimationClip* clip = new AnimationClip(id, this, start, end);
-
     addClip(clip);
-
     return clip;
 }
 
@@ -205,6 +162,77 @@ void Animation::stop(const char* id)
     }
 }
 
+void Animation::createDefaultClip()
+{
+    _defaultClip = new AnimationClip("default_clip", this, 0.0f, _duration);
+}
+
+void Animation::createClips(Properties* animationProperties, unsigned int frameCount)
+{   
+    assert(animationProperties);
+    
+    Properties* pClip = animationProperties->getNextNamespace();
+    
+    while (pClip != NULL && std::strcmp(pClip->getNamespace(), "clip") == 0)
+    {
+        int begin = pClip->getInt("begin");
+        int end = pClip->getInt("end");
+
+        AnimationClip* clip = createClip(pClip->getId(), ((float) begin / frameCount) * _duration, ((float) end / frameCount) * _duration);
+
+        const char* repeat = pClip->getString("repeatCount");
+        if (repeat)
+        {
+            if (strcmp(repeat, ANIMATION_INDEFINITE_STR) == 0)
+            {
+                clip->setRepeatCount(AnimationClip::REPEAT_INDEFINITE);
+            }
+            else
+            {
+                float value;
+                sscanf(repeat, "%f", &value);
+                clip->setRepeatCount(value);
+            }
+        }
+
+        const char* speed = pClip->getString("speed");
+        if (speed)
+        {
+            float value;
+            sscanf(speed, "%f", &value);
+            clip->setSpeed(value);
+        }
+
+        pClip = animationProperties->getNextNamespace();
+    }
+}
+
+void Animation::addClip(AnimationClip* clip)
+{
+    if (_clips == NULL)
+        _clips = new std::vector<AnimationClip*>;
+
+    _clips->push_back(clip);
+}
+
+AnimationClip* Animation::findClip(const char* id) const
+{
+    if (_clips)
+    {
+        AnimationClip* clip = NULL;
+        unsigned int clipCount = _clips->size();
+        for (unsigned int i = 0; i < clipCount; i++)
+        {
+            clip = _clips->at(i);
+            if (clip->_id.compare(id) == 0)
+            {
+                return _clips->at(i);
+            }
+        }
+    }
+    return NULL;
+}
+
 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);
@@ -212,18 +240,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
 
     Curve* curve = new Curve(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
-    {
-        switch (propertyId)
-        {
-        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;
-        }
-    }
+        setTransformRotationOffset(curve, propertyId);
 
     unsigned long lowest = keyTimes[0];
     unsigned long duration = keyTimes[keyCount-1] - lowest;
@@ -259,18 +276,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
 
     Curve* curve = new Curve(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
-    {
-        switch (propertyId)
-        {
-        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;
-        }
-    }
+        setTransformRotationOffset(curve, propertyId);
     
     unsigned long lowest = keyTimes[0];
     unsigned long duration = keyTimes[keyCount-1] - lowest;
@@ -328,37 +334,20 @@ void Animation::removeChannel(Channel* channel)
         _controller->destroyAnimation(this);
 }
 
-void Animation::createDefaultClip()
-{
-    std::string clipId = _id + ANIMATION_DEFAULT_CLIP_SUFFIX;
-
-    _defaultClip = new AnimationClip(clipId.c_str(), this, 0.0f, _duration);
-}
-
-void Animation::addClip(AnimationClip* clip)
-{
-    if (_clips == NULL)
-        _clips = new std::vector<AnimationClip*>;
-
-    _clips->push_back(clip);
-}
-
-AnimationClip* Animation::findClip(const char* id) const
+void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId)
 {
-    if (_clips)
+    switch (propertyId)
     {
-        AnimationClip* clip = NULL;
-        unsigned int clipCount = _clips->size();
-        for (unsigned int i = 0; i < clipCount; i++)
-        {
-            clip = _clips->at(i);
-            if (clip->_id.compare(id) == 0)
-            {
-                return _clips->at(i);
-            }
-        }
+    case Transform::ANIMATE_ROTATE:
+    case Transform::ANIMATE_ROTATE_TRANSLATE:
+        curve->setQuaternionOffset(ANIMATION_ROTATE_OFFSET);
+        return;
+    case Transform::ANIMATE_SCALE_ROTATE_TRANSLATE:
+        curve->setQuaternionOffset(ANIMATION_SRT_OFFSET);
+        return;
     }
-    return NULL;
+
+    return;
 }
 
 }

+ 16 - 5
gameplay/src/Animation.h

@@ -2,6 +2,7 @@
 #define ANIMATION_H_
 
 #include "Ref.h"
+#include "Properties.h"
 
 namespace gameplay
 {
@@ -133,6 +134,16 @@ private:
      */
     ~Animation();
 
+    /**
+     * Creates the default clip.
+     */
+    void createDefaultClip();
+
+    /**
+     * Creates AnimationClip's for this Animation from the specified Property object.
+     */
+    void createClips(Properties* animationProperties, unsigned int frameCount);
+
     /**
      * Adds a clip to this Animation.
      */
@@ -143,11 +154,6 @@ private:
      */
     AnimationClip* findClip(const char* id) const;
 
-    /**
-     * Creates the default clip.
-     */
-    void createDefaultClip();
-
     /**
      * Creates a channel within this animation.
      */ 
@@ -167,6 +173,11 @@ private:
      * Removes a channel from the animation.
      */
     void removeChannel(Channel* channel);
+
+    /**
+     * Sets the rotation offset in a Curve representing a Transform's animation data.
+     */
+    void setTransformRotationOffset(Curve* curve, unsigned int propertyId);
     
     AnimationController* _controller;       // The AnimationController that this Animation will run on.
     std::string _id;                        // The Animation's ID.

+ 49 - 87
gameplay/src/AnimationClip.cpp

@@ -11,18 +11,15 @@ namespace gameplay
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
     : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), _repeatCount(1.0f), 
       _activeDuration(_duration * _repeatCount), _speed(1.0f), _isPlaying(false), _timeStarted(0), _elapsedTime(0), _runningTime(0), 
-      _channelPriority(NULL), _crossFadeToClip(NULL), _crossFadeStart(0), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _crossFadeToClip(NULL), _crossFadeStart(0), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
       _isFadingOutStarted(false), _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL)
 {
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     
-    unsigned int channelCount = _animation->_channels.size();
-    _channelPriority = new unsigned int[channelCount];
-    
+    unsigned int channelCount = _animation->_channels.size();    
     for (unsigned int i = 0; i < channelCount; i++)
     {
         _values.push_back(new AnimationValue(_animation->_channels[i]->_curve->getComponentCount()));
-        _channelPriority[i] = 0;
     }
 }
 
@@ -37,7 +34,6 @@ AnimationClip::~AnimationClip()
     _values.clear();
 
     SAFE_RELEASE(_crossFadeToClip);
-    SAFE_DELETE(_channelPriority);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
 }
@@ -315,7 +311,7 @@ bool AnimationClip::update(unsigned long elapsedTime)
             // Evaluate point on Curve.
             channel->_curve->evaluate(percentComplete, value->_interpolatedValue);
 
-            if (channel->_curve->_quaternionOffsetsCount == 0)
+            if (!channel->_curve->_quaternionOffset)
             {
                 if (value->_isFirstActing)
                 {
@@ -342,131 +338,97 @@ bool AnimationClip::update(unsigned long elapsedTime)
             }
             else
             {   //We have Quaternions!!!
-                unsigned int j = 0;
-                unsigned int quaternionOffsetIndex = 0;
-                unsigned int quaternionOffset = 0;
-
+                unsigned int quaternionOffset = *(channel->_curve->_quaternionOffset);
+                
                 if (value->_isFirstActing)
                 {
-                    do {
-                        quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
-                        while (j < quaternionOffset)
-                        {
-                            if (_blendWeight != 1.0f)
-                                value->_interpolatedValue[j] *= _blendWeight;
-
-                            value->_currentValue[j] = value->_interpolatedValue[j];
-                            j++;
-                        }
+                    unsigned int j = 0;
+                    for (; j < quaternionOffset; j++)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
 
-                        // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                        value->_currentValue[j] = value->_interpolatedValue[j];
+                    }
 
-                        Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
-                        Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+                    // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                    Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
+                    Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
 
-                        // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
-                        if (_blendWeight != 1.0f)
-                            Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
+                    // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
+                    if (_blendWeight != 1.0f)
+                        Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
                     
-                        // Add in contribution.
-                        currentQuaternion->set(*interpolatedQuaternion);
+                    // Add in contribution.
+                    currentQuaternion->set(*interpolatedQuaternion);
                     
-                        // Increase by 4.
-                        j += 4;
-                        quaternionOffsetIndex++;
-                    } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
-
                     unsigned int componentCount = value->_componentCount;
-                    // Handle remaining scalar values.
-                    while (j < componentCount)
+                    for (j += 4; j < componentCount; j++)
                     {
                         if (_blendWeight != 1.0f)
                             value->_interpolatedValue[j] *= _blendWeight;
 
                         value->_currentValue[j] = value->_interpolatedValue[j];
-                        j++;
                     }
                 }
                 else
                 {
-                    do {
-                        quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
-                        while (j < quaternionOffset)
-                        {
-                            if (_blendWeight != 1.0f)
-                                value->_interpolatedValue[j] *= _blendWeight;
-
-                            value->_currentValue[j] += value->_interpolatedValue[j];
-                            j++;
-                        }
+                    unsigned int j = 0;
+                    for (; j < quaternionOffset; j++)
+                    {
+                        if (_blendWeight != 1.0f)
+                            value->_interpolatedValue[j] *= _blendWeight;
 
-                        // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                        value->_currentValue[j] += value->_interpolatedValue[j];
+                    }
+                    // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
 
-                        Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
-                        Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+                    Quaternion* interpolatedQuaternion = (Quaternion*) (value->_interpolatedValue + j);
+                    Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
 
-                        // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
-                        if (_blendWeight != 1.0f)
-                            Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
+                    // If we have a blend weight, we apply it by slerping from the identity to our interpolated value at the given weight.
+                    if (_blendWeight != 1.0f)
+                        Quaternion::slerp(Quaternion::identity(), *interpolatedQuaternion, _blendWeight, interpolatedQuaternion);
                     
-                        // Add in contribution.
-                        currentQuaternion->multiply(*interpolatedQuaternion);
+                    // Add in contribution.
+                    currentQuaternion->multiply(*interpolatedQuaternion);
                     
-                        // Increase by 4.
-                        j += 4;
-                        quaternionOffsetIndex++;
-                    } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
-
                     unsigned int componentCount = value->_componentCount;
-                    // Handle remaining scalar values.
-                    while (j < componentCount)
+                    for (j += 4; j < componentCount; j++)
                     {
                         if (_blendWeight != 1.0f)
                             value->_interpolatedValue[j] *= _blendWeight;
 
                         value->_currentValue[j] += value->_interpolatedValue[j];
-                        j++;
                     }
                 }
             }
         }
         else if (value->_isFirstActing)
         {
-            if (channel->_curve->_quaternionOffsetsCount == 0)
+            if (!channel->_curve->_quaternionOffset)
             {
                 memset(value->_currentValue, 0.0f, value->_componentCount);
             }
             else
             {
+                unsigned int quaternionOffset = *(channel->_curve->_quaternionOffset);
                 unsigned int j = 0;
-                unsigned int quaternionOffset = 0;
-                unsigned int quaternionOffsetIndex = 0;
-                
-                do {
-                    quaternionOffset = channel->_curve->_quaternionOffsets[quaternionOffsetIndex];
-                    while (j < quaternionOffset)
-                    {
-                        value->_currentValue[j] = 0.0f;
-                        j++;
-                    }
-
-                    // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
-                    Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
+                for (; j < quaternionOffset; j++)
+                {
+                    value->_currentValue[j] = 0.0f;
+                }
 
-                    // Set it to identity.
-                    currentQuaternion->setIdentity();
-                    
-                    // Increase by 4.
-                    j += 4;
-                    quaternionOffsetIndex++;
-                } while (quaternionOffsetIndex < channel->_curve->_quaternionOffsetsCount);
+                // We are at the index for a quaternion component. Handle the next for components as a whole quaternion.
+                Quaternion* currentQuaternion = (Quaternion*) (value->_currentValue + j);
 
+                // Set it to identity.
+                currentQuaternion->setIdentity();
+                
                 unsigned int componentCount = value->_componentCount;
-                // Handle remaining scalar values.
-                while (j < componentCount)
+                for (j += 4; j < componentCount; j++)
                 {
                     value->_currentValue[j] = 0.0f;
-                    j++;
                 }
             }
         }

+ 0 - 1
gameplay/src/AnimationClip.h

@@ -239,7 +239,6 @@ private:
     unsigned long _timeStarted;               // The game time when this clip was actually started.
     unsigned long _elapsedTime;               // Time elapsed while the clip is running.
     long _runningTime;                        // Keeps track of the Animation's relative time in respect to the active duration.
-    unsigned int* _channelPriority;           // Keeps track of each channel's priority.
     AnimationClip* _crossFadeToClip;          // The clip to cross fade to
     unsigned long _crossFadeStart;            // The time at which the cross fade started.
     unsigned long _crossFadeOutElapsed;       // The amount of time that has elapsed for the crossfade.

+ 160 - 32
gameplay/src/AnimationController.cpp

@@ -19,13 +19,9 @@ AnimationController::~AnimationController()
 Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type)
 {
     assert(type != Curve::BEZIER && type != Curve::HERMITE);
-    assert(id && keyCount >= 2 && keyTimes && keyValues);
-    Animation* animation = getAnimation(id);
+    assert(keyCount >= 2 && keyTimes && keyValues && target);
 
-    if (animation != NULL)
-        return NULL;
-
-    animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, type);
+    Animation* animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, type);
 
     addAnimation(animation);
     
@@ -34,34 +30,24 @@ Animation* AnimationController::createAnimation(const char* id, AnimationTarget*
 
 Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type)
 {
-    assert(id && keyCount >= 2 && keyTimes && keyValues && keyInValue && keyOutValue);
-    Animation* animation = getAnimation(id);
-
-    if (animation != NULL)
-        return NULL;
-    
-    animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
+    assert(target && keyCount >= 2 && keyTimes && keyValues && keyInValue && keyOutValue);
+    Animation* animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
 
     addAnimation(animation);
 
     return animation;
 }
 
-Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, Properties* p)
+Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, const char* animationFile)
 {
-    Animation* animation = getAnimation(id);
-
-    if (animation != NULL)
-        return NULL;
+    assert(target && animationFile);
     
-    // TODO: Implement loading from a properties object here.
-    /*
-    animation = new Animation(id, target, p);
+    Properties* p = Properties::create(animationFile);
+    assert(p);
 
-    addAnimation(animation);
+    Animation* animation = createAnimation(id, target, p->getNextNamespace());
 
-    target->addAnimation(animation);
-    */
+    SAFE_DELETE(p);
 
     return animation;
 }
@@ -125,7 +111,6 @@ void AnimationController::stopAllAnimations()
         AnimationClip* clip = *clipIter;
         clip->_isPlaying = false;
         clip->onEnd();
-        clipIter = _runningClips.erase(clipIter);
         SAFE_RELEASE(clip);
     }
     _runningClips.clear();
@@ -133,6 +118,144 @@ void AnimationController::stopAllAnimations()
     _state = IDLE;
 }
 
+Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, Properties* animationProperties)
+{
+    assert(target && animationProperties);
+    assert(std::strcmp(animationProperties->getNamespace(), "animation") == 0);
+    
+    const char* propertyIdStr = animationProperties->getString("property");
+    assert(propertyIdStr);
+    
+    // Get animation target property id
+    int propertyId = AnimationTarget::getPropertyId(target->_targetType, propertyIdStr);
+    assert(propertyId != -1);
+    
+    unsigned int keyCount = animationProperties->getInt("keyCount");
+    assert(keyCount > 0);
+
+    const char* keyTimesStr = animationProperties->getString("keyTimes");
+    assert(keyTimesStr);
+    
+    const char* keyValuesStr = animationProperties->getString("keyValues");
+    assert(keyValuesStr);
+    
+    const char* curveStr = animationProperties->getString("curve");
+    assert(curveStr);
+    
+    char delimeter = ' ';
+    unsigned int startOffset = 0;
+    unsigned int endOffset = std::string::npos;
+    
+    unsigned long* keyTimes = new unsigned long[keyCount];
+    for (unsigned int i = 0; i < keyCount; i++)
+    {
+        endOffset = static_cast<std::string>(keyTimesStr).find_first_of(delimeter, startOffset);
+        if (endOffset != std::string::npos)
+        {
+            keyTimes[i] = std::strtoul(static_cast<std::string>(keyTimesStr).substr(startOffset, endOffset - startOffset).c_str(), NULL, 0);
+        }
+        else
+        {
+            keyTimes[i] = std::strtoul(static_cast<std::string>(keyTimesStr).substr(startOffset, static_cast<std::string>(keyTimesStr).length()).c_str(), NULL, 0);
+        }
+        startOffset = endOffset + 1;
+    }
+
+    startOffset = 0;
+    endOffset = std::string::npos;
+    
+    int componentCount = target->getAnimationPropertyComponentCount(propertyId);
+    assert(componentCount > 0);
+    
+    unsigned int components = keyCount * componentCount;
+    
+    float* keyValues = new float[components];
+    for (unsigned int i = 0; i < components; i++)
+    {
+        endOffset = static_cast<std::string>(keyValuesStr).find_first_of(delimeter, startOffset);
+        if (endOffset != std::string::npos)
+        {   
+            keyValues[i] = std::atof(static_cast<std::string>(keyValuesStr).substr(startOffset, endOffset - startOffset).c_str());
+        }
+        else
+        {
+            keyValues[i] = std::atof(static_cast<std::string>(keyValuesStr).substr(startOffset, static_cast<std::string>(keyValuesStr).length()).c_str());
+        }
+        startOffset = endOffset + 1;
+    }
+
+    const char* keyInStr = animationProperties->getString("keyIn");
+    float* keyIn = NULL;
+    if (keyInStr)
+    {
+        keyIn = new float[components];
+        startOffset = 0;
+        endOffset = std::string::npos;
+        for (unsigned int i = 0; i < components; i++)
+        {
+            endOffset = static_cast<std::string>(keyInStr).find_first_of(delimeter, startOffset);
+            if (endOffset != std::string::npos)
+            {   
+                keyIn[i] = std::atof(static_cast<std::string>(keyInStr).substr(startOffset, endOffset - startOffset).c_str());
+            }
+            else
+            {
+                keyIn[i] = std::atof(static_cast<std::string>(keyInStr).substr(startOffset, static_cast<std::string>(keyInStr).length()).c_str());
+            }
+            startOffset = endOffset + 1;
+        }
+    }
+    
+    const char* keyOutStr = animationProperties->getString("keyOut");
+    float* keyOut = NULL;
+    if(keyOutStr)
+    {   
+        keyOut = new float[components];
+        startOffset = 0;
+        endOffset = std::string::npos;
+        for (unsigned int i = 0; i < components; i++)
+        {
+            endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
+            if (endOffset != std::string::npos)
+            {   
+                keyOut[i] = std::atof(static_cast<std::string>(keyOutStr).substr(startOffset, endOffset - startOffset).c_str());
+            }
+            else
+            {
+                keyOut[i] = std::atof(static_cast<std::string>(keyOutStr).substr(startOffset, static_cast<std::string>(keyOutStr).length()).c_str());
+            }
+            startOffset = endOffset + 1;
+        }
+    }
+
+    int curve = Curve::getInterpolationType(curveStr);
+
+    Animation* animation = NULL;
+    if (keyIn && keyOut)
+    {
+        animation = createAnimation(id, target, propertyId, keyCount, keyTimes, keyValues, keyIn, keyOut, (Curve::InterpolationType)curve);
+    }
+    else
+    {
+        animation = createAnimation(id, target, propertyId, keyCount, keyTimes, keyValues, (Curve::InterpolationType) curve);
+    }
+
+    SAFE_DELETE(keyOut);
+    SAFE_DELETE(keyIn);
+    SAFE_DELETE(keyValues);
+    SAFE_DELETE(keyTimes);
+
+    Properties* pClip = animationProperties->getNextNamespace();
+    if (pClip && std::strcmp(pClip->getNamespace(), "clip") == 0)
+    {
+        int frameCount = animationProperties->getInt("frameCount");
+        assert(frameCount > 0);
+        animation->createClips(animationProperties, (unsigned int) frameCount);
+    }
+
+    return animation;
+}
+
 AnimationController::State AnimationController::getState() const
 {
     return _state;
@@ -185,10 +308,17 @@ void AnimationController::schedule(AnimationClip* clip)
 
 void AnimationController::unschedule(AnimationClip* clip)
 {
-    if (clip->_isPlaying)
+    std::list<AnimationClip*>::iterator clipItr = _runningClips.begin();
+    while (clipItr != _runningClips.end())
     {
-        _runningClips.remove(clip);
-        SAFE_RELEASE(clip);
+        AnimationClip* rClip = (*clipItr);
+        if (rClip == clip)
+        {
+            _runningClips.erase(clipItr);
+            SAFE_RELEASE(clip);
+            break;
+        }
+        clipItr++;
     }
 
     if (_runningClips.empty())
@@ -201,20 +331,18 @@ void AnimationController::update(long elapsedTime)
         return;
 
     std::list<AnimationClip*>::iterator clipIter = _runningClips.begin();
-    unsigned int clipCount = 0;
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = (*clipIter);
         if (clip->update(elapsedTime))
         {
-            clipIter = _runningClips.erase(clipIter);
             SAFE_RELEASE(clip);
+            clipIter = _runningClips.erase(clipIter);
         }
         else
         {
             clipIter++;
         }
-        clipCount++;
     }
     
     if (_runningClips.empty())
@@ -235,8 +363,8 @@ void AnimationController::destroyAnimation(Animation* animation)
         if (animation == *itr)
         {
             Animation* animation = *itr;
-            SAFE_RELEASE(animation);
             _animations.erase(itr);
+            SAFE_RELEASE(animation);
             return;
         }
         itr++;

+ 20 - 8
gameplay/src/AnimationController.h

@@ -17,6 +17,7 @@ class AnimationController
     friend class Game;
     friend class Animation;
     friend class AnimationClip;
+    friend class SceneLoader;
 
 public:
 
@@ -32,7 +33,7 @@ public:
      * @param keyValues The list of key values for the animation.
      * @param type The curve interpolation type.
      *
-     * @return The newly created animation, or NULL if an animation with the given ID already exists.
+     * @return The newly created animation.
      */
     Animation* createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type);
 
@@ -49,7 +50,7 @@ public:
      * @param keyOutValue The list of key out values for the animation.
      * @param type The curve interpolation type.
      *
-     * @return The newly created animation, or NULL if an animation with the given ID already exists.
+     * @return The newly created animation.
      */
     Animation* createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type);
 
@@ -58,11 +59,11 @@ public:
      * 
      * @param id The ID of the animation.
      * @param target The animation target.
-     * @param properties The properties object defining the animation data.
+     * @param animationFile The animation file defining the animation data.
      *
-     * @return The newly created animation, or NULL if an animation with the given ID already exists.
+     * @return The newly created animation.
      */
-    Animation* createAnimation(const char* id, AnimationTarget* target, Properties* p);
+    Animation* createAnimation(const char* id, AnimationTarget* target, const char* animationFile);
 
     /**
      * Creates a simple two keyframe from-to animation.
@@ -76,7 +77,7 @@ public:
      * @param type The curve interpolation type.
      * @param duration The duration of the animation (in milliseconds).
      *
-     * @return The newly created animation, or NULL if an animation with the given ID already exists.
+     * @return The newly created animation.
      */
     Animation* createAnimationFromTo(const char* id, AnimationTarget* target, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration);
 
@@ -92,7 +93,7 @@ public:
      * @param type The curve interpolation type.
      * @param duration The duration of the animation (in milliseconds).
      *
-     * @return The newly created animation, or NULL if an animation with the given ID already exists.
+     * @return The newly created animation.
      */
     Animation* createAnimationFromBy(const char* id, AnimationTarget* target, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration);
 
@@ -134,6 +135,17 @@ private:
      */
     ~AnimationController();
     
+    /**
+     * Creates an animation on this target using the data from the given properties object. 
+     * 
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param properties The properties object defining the animation data.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, AnimationTarget* target, Properties* animationProperties);
+
     /**
      * Gets the controller's state.
      *
@@ -175,7 +187,7 @@ private:
      * Callback for when the controller receives a frame update event.
      */
     void update(long elapsedTime);
-    
+
     /**
      * Adds an animation on this AnimationTarget.
      */ 

+ 63 - 1
gameplay/src/AnimationTarget.cpp

@@ -19,9 +19,11 @@ AnimationTarget::~AnimationTarget()
         std::vector<Animation::Channel*>::iterator itr = _animationChannels->begin();
         while (itr != _animationChannels->end())
         {
-            SAFE_DELETE((*itr));
+            Animation::Channel* channel = (*itr);
+            SAFE_DELETE(channel);
             itr++;
         }
+        _animationChannels->clear();
         SAFE_DELETE(_animationChannels);
     }
 }
@@ -34,6 +36,66 @@ void AnimationTarget::addChannel(Animation::Channel* channel)
     _animationChannels->push_back(channel);
 }
 
+int AnimationTarget::getPropertyId(TargetType type, const char* propertyIdStr)
+{
+    if (type == AnimationTarget::TRANSFORM)
+    {
+        if (strcmp(propertyIdStr, "ANIMATE_SCALE") == 0)
+        {
+            return Transform::ANIMATE_SCALE;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_SCALE_X") == 0)
+        {
+            return Transform::ANIMATE_SCALE_X;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_SCALE_Y") == 0)
+        {
+            return Transform::ANIMATE_SCALE_Y;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_SCALE_Z") == 0)
+        {
+            return Transform::ANIMATE_SCALE_Z;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_ROTATE") == 0)
+        {
+            return Transform::ANIMATE_ROTATE;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_TRANSLATE") == 0)
+        {
+            return Transform::ANIMATE_TRANSLATE;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_TRANSLATE_X") == 0)
+        {
+            return Transform::ANIMATE_TRANSLATE_X;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_TRANSLATE_Y") == 0)
+        {
+            return Transform::ANIMATE_TRANSLATE_Y;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_TRANSLATE_Z") == 0)
+        {
+            return Transform::ANIMATE_TRANSLATE_Z;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_ROTATE_TRANSLATE") == 0)
+        {
+            return Transform::ANIMATE_ROTATE_TRANSLATE;
+        }
+        else if (strcmp(propertyIdStr, "ANIMATE_SCALE_ROTATE_TRANSLATE") == 0)
+        {
+            return Transform::ANIMATE_SCALE_ROTATE_TRANSLATE;
+        }
+    }
+    else
+    {
+        if (strcmp(propertyIdStr, "ANIMATE_UNIFORM") == 0)
+        {
+            return MaterialParameter::ANIMATE_UNIFORM;
+        }
+    }
+
+    return -1;
+}
+
 }
 
 

+ 10 - 0
gameplay/src/AnimationTarget.h

@@ -76,6 +76,16 @@ private:
      */
     AnimationTarget(const AnimationTarget& copy);
 
+    /**
+     * Gets the TargetType's property ID value for the specified property ID string.
+     * 
+     * @param type The TargetType of the AnimationTarget.
+     * @param propertyIdStr The property ID string.
+     * @return The property ID value for teh property ID string; -1 if the propertyIdStr does not exist
+     *    for the TargetType.
+     */
+    static int getPropertyId(TargetType type, const char* propertyIdStr);
+
     Animation::Channel* _highestPriority;
     std::vector<Animation::Channel*>* _animationChannels;   // Collection of all animation channels that target the AnimationTarget
 

+ 59 - 2
gameplay/src/AudioSource.cpp

@@ -31,6 +31,22 @@ AudioSource* AudioSource::create(const char* path)
 {
     assert(path);
 
+    // Load from a .audio file.
+    std::string pathStr = path;
+    if (pathStr.find(".audio") != pathStr.npos)
+    {
+        Properties* properties = Properties::create(path);
+        assert(properties);
+        if (properties == NULL)
+        {
+            return NULL;
+        }
+
+        AudioSource* audioSource = create(properties->getNextNamespace());
+        SAFE_DELETE(properties);
+        return audioSource;
+    }
+
     // Create an audio buffer from this path.
     AudioBuffer* buffer = AudioBuffer::create(path);
     if (buffer == NULL)
@@ -51,8 +67,49 @@ AudioSource* AudioSource::create(const char* path)
 
 AudioSource* AudioSource::create(Properties* properties)
 {
-    // TODO: Implement this!
-    return NULL;
+    // Check if the properties is valid and has a valid namespace.
+    assert(properties);
+    if (!properties || !(strcmp(properties->getNamespace(), "audio") == 0))
+    {
+        WARN("Failed to load audio source from properties object: must be non-null object and have namespace equal to \'audio\'.");
+        return NULL;
+    }
+
+    const char* path = properties->getString("path");
+    if (path == NULL)
+    {
+        WARN("Audio file failed to load; the file path was not specified.");
+        return NULL;
+    }
+
+    // Create the audio source.
+    AudioSource* audio = AudioSource::create(path);
+    if (audio == NULL)
+    {
+        WARN_VARG("Audio file '%s' failed to load properly.", path);
+        return NULL;
+    }
+
+    // Set any properties that the user specified in the .audio file.
+    if (properties->getString("looped") != NULL)
+    {
+        audio->setLooped(properties->getBool("looped"));
+    }
+    if (properties->getString("gain") != NULL)
+    {
+        audio->setGain(properties->getFloat("gain"));
+    }
+    if (properties->getString("pitch") != NULL)
+    {
+        audio->setPitch(properties->getFloat("pitch"));
+    }
+    Vector3 v;
+    if (properties->getVector3("velocity", &v))
+    {
+        audio->setVelocity(v);
+    }
+
+    return audio;
 }
 
 AudioSource::State AudioSource::getState() const

+ 3 - 3
gameplay/src/AudioSource.h

@@ -33,11 +33,11 @@ public:
     };
 
     /**
-     * Create an audio source. This is used to instantiate an Audio Source. Currently only wav, au and raw files are supported.
+     * Create an audio source. This is used to instantiate an Audio Source. Currently only wav, au, raw and .audio files are supported.
      *
-     * @param path The relative location on disk of the sound file.
+     * @param path The relative location on disk of the sound file or .audio file.
      * 
-     * @return The newly created audio source, or NULL if an audio source with the given ID already exists.
+     * @return The newly created audio source, or NULL if an audio source cannot be created.
      */
     static AudioSource* create(const char* path);
 

+ 12 - 55
gameplay/src/Base.h

@@ -35,6 +35,9 @@ using std::isdigit;
 using std::toupper;
 using std::tolower;
 using std::size_t;
+using std::min;
+using std::max;
+using std::modf;
 
 // Common
 #ifndef NULL
@@ -69,41 +72,8 @@ extern void printError(const char* format, ...);
 // Bullet Physics
 #include <btBulletDynamicsCommon.h>
 
-// Since Bullet overrides new, we have to allocate objects manually using its
-// aligned allocation function when we turn on memory leak detection in GamePlay.
-#ifdef GAMEPLAY_MEM_LEAK_DETECTION
-#define BULLET_NEW(type, name) \
-    type* name = (type*)btAlignedAlloc(sizeof(type), 16); \
-    type __##name##_tmp; \
-    memcpy(name, &__##name##_tmp, sizeof(type))
-
-#define BULLET_NEW_VARG(type, name, ...) \
-    type* name = (type*)btAlignedAlloc(sizeof(type), 16); \
-    type __##name##_tmp (__VA_ARGS__); \
-    memcpy(name, &__##name##_tmp, sizeof(type))
-
-#define BULLET_DELETE(name) \
-    if (name) \
-    { \
-        btAlignedFree(name); \
-        name = NULL; \
-    }
-
-#else
-#define BULLET_NEW(type, name) \
-    type* name = new type()
-
-#define BULLET_NEW_VARG(type, name, ...) \
-    type* name = new type(__VA_ARGS__)
-
-#define BULLET_DELETE(name) SAFE_DELETE(name)
-#endif
-
-
 // Debug new for memory leak detection
-#ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #include "DebugNew.h"
-#endif
 
 // Object deletion macro
 #define SAFE_DELETE(x) \
@@ -148,6 +118,11 @@ extern void printError(const char* format, ...);
 #define M_1_PI                      0.31830988618379067154
 #endif
 
+// NOMINMAX makes sure that windef.h doesn't add macros min and max
+#ifdef WIN32
+    #define NOMINMAX
+#endif
+
 // Audio (OpenAL)
 #ifdef __QNX__
 #include <AL/al.h>
@@ -184,7 +159,6 @@ extern void printError(const char* format, ...);
 #elif WIN32
     #define WIN32_LEAN_AND_MEAN
     #include <GL/glew.h>
-    #include <GL/wglew.h>
 #elif __APPLE__
 #include <OpenGL/gl.h>
 #include <OpenGL/glext.h>
@@ -208,8 +182,8 @@ extern void printError(const char* format, ...);
 namespace gameplay
 {
 typedef GLint VertexAttribute;
-typedef GLuint VertexBuffer;
-typedef GLuint IndexBuffer;
+typedef GLuint VertexBufferHandle;
+typedef GLuint IndexBufferHandle;
 typedef GLuint TextureHandle;
 typedef GLuint FrameBufferHandle;
 typedef GLuint RenderBufferHandle;
@@ -267,25 +241,7 @@ extern GLenum __gl_error_code;
 #define GL_LAST_ERROR() __gl_error_code
 
 
-#if defined(WIN32) || defined(__APPLE__)
-
-    inline float fminf(float a, float b)
-    {
-      return a < b ? a : b;
-    }
-    inline float fmin(float a, float b)
-    {
-      return a < b ? a : b;
-    }
-    inline float fmaxf(float a, float b)
-    {
-      return a > b ? a : b;
-    }
-    inline float fmax(float a, float b)
-    {
-      return a > b ? a : b;
-    }
-        
+#if defined(WIN32)
     #pragma warning( disable : 4172 )
     #pragma warning( disable : 4244 )
     #pragma warning( disable : 4311 )
@@ -294,4 +250,5 @@ extern GLenum __gl_error_code;
     #pragma warning( disable : 4996 )
 #endif
 
+
 #endif

+ 12 - 12
gameplay/src/BoundingBox.cpp

@@ -206,14 +206,14 @@ bool BoundingBox::isEmpty() const
 void BoundingBox::merge(const BoundingBox& box)
 {
     // Calculate the new minimum point.
-    min.x = fminf(min.x, box.min.x);
-    min.y = fminf(min.y, box.min.y);
-    min.z = fminf(min.z, box.min.z);
+    min.x = std::min(min.x, box.min.x);
+    min.y = std::min(min.y, box.min.y);
+    min.z = std::min(min.z, box.min.z);
 
     // Calculate the new maximum point.
-    max.x = fmaxf(max.x, box.max.x);
-    max.y = fmaxf(max.y, box.max.y);
-    max.z = fmaxf(max.z, box.max.z);
+    max.x = std::max(max.x, box.max.x);
+    max.y = std::max(max.y, box.max.y);
+    max.z = std::max(max.z, box.max.z);
 }
 
 void BoundingBox::merge(const BoundingSphere& sphere)
@@ -222,14 +222,14 @@ void BoundingBox::merge(const BoundingSphere& sphere)
     float radius = sphere.radius;
 
     // Calculate the new minimum point for the merged bounding box.
-    min.x = fminf(min.x, center.x - radius);
-    min.y = fminf(min.y, center.y - radius);
-    min.z = fminf(min.z, center.z - radius);
+    min.x = std::min(min.x, center.x - radius);
+    min.y = std::min(min.y, center.y - radius);
+    min.z = std::min(min.z, center.z - radius);
 
     // Calculate the new maximum point for the merged bounding box.
-    max.x = fmaxf(max.x, center.x + radius);
-    max.y = fmaxf(max.y, center.y + radius);
-    max.z = fmaxf(max.z, center.z + radius);
+    max.x = std::max(max.x, center.x + radius);
+    max.y = std::max(max.y, center.y + radius);
+    max.z = std::max(max.z, center.z + radius);
 }
 
 void BoundingBox::set(const Vector3& min, const Vector3& max)

+ 8 - 9
gameplay/src/BoundingSphere.cpp

@@ -283,15 +283,14 @@ void BoundingSphere::set(const BoundingBox& box)
 void BoundingSphere::transform(const Matrix& matrix)
 {
     // Translate the center point.
-    Vector3 translate;
-    matrix.transformPoint(center, &translate);
-    center = translate;
-
-    // Calculate the sphere's new radius from the radii in each direction (take the largest).
-    matrix.decompose(&translate, NULL, NULL);
-    float r = radius * translate.x;
-    r = fmaxf(radius, radius * translate.y);
-    r = fmaxf(radius, radius * translate.z);
+    matrix.transformPoint(center, &center);
+
+    // Scale the sphere's radius by the scale fo the matrix
+    Vector3 scale;
+    matrix.decompose(&scale, NULL, NULL);
+    float r = radius * scale.x;
+    r = max(r, radius * scale.y);
+    r = max(r, radius * scale.z);
     radius = r;
 }
 

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff