Răsfoiți Sursa

Merge pull request #88 from blackberry/next

gameplay version 1.2.0
Sean Paul Taylor 13 ani în urmă
părinte
comite
e59a383131
100 a modificat fișierele cu 5923 adăugiri și 1349 ștergeri
  1. 155 38
      .gitignore
  2. 18 13
      README.md
  3. 5 0
      gameplay-api/gameplay.html
  4. BIN
      gameplay-api/gameplay.png
  5. 9 10
      gameplay-encoder/README.md
  6. 11 11
      gameplay-encoder/gameplay-bundle.txt
  7. 3 2
      gameplay-encoder/gameplay-encoder.vcxproj
  8. 9 6
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  9. 37 33
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  10. 3 1
      gameplay-encoder/gameplay-encoder.xcodeproj/xcshareddata/xcschemes/gameplay-encoder.xcscheme
  11. 10 0
      gameplay-encoder/src/Animation.cpp
  12. 17 1
      gameplay-encoder/src/Animation.h
  13. 19 14
      gameplay-encoder/src/AnimationChannel.cpp
  14. 12 1
      gameplay-encoder/src/AnimationChannel.h
  15. 8 0
      gameplay-encoder/src/Base.h
  16. 1 0
      gameplay-encoder/src/Camera.h
  17. 1346 0
      gameplay-encoder/src/Curve.cpp
  18. 484 0
      gameplay-encoder/src/Curve.h
  19. 36 0
      gameplay-encoder/src/Curve.inl
  20. 1 0
      gameplay-encoder/src/DAEChannelTarget.h
  21. 72 38
      gameplay-encoder/src/DAESceneEncoder.cpp
  22. 3 1
      gameplay-encoder/src/DAESceneEncoder.h
  23. 1 0
      gameplay-encoder/src/Effect.h
  24. 159 58
      gameplay-encoder/src/FBXSceneEncoder.cpp
  25. 3 0
      gameplay-encoder/src/FileIO.h
  26. 144 0
      gameplay-encoder/src/GPBFile.cpp
  27. 15 0
      gameplay-encoder/src/GPBFile.h
  28. 2 4
      gameplay-encoder/src/Mesh.cpp
  29. 2 4
      gameplay-encoder/src/Mesh.h
  30. 17 15
      gameplay-encoder/src/MeshSkin.cpp
  31. 2 2
      gameplay-encoder/src/Node.cpp
  32. 1 1
      gameplay-encoder/src/Node.h
  33. 2 2
      gameplay-encoder/src/Reference.h
  34. 89 0
      gameplay-encoder/src/Transform.cpp
  35. 11 0
      gameplay-encoder/src/Transform.h
  36. 18 12
      gameplay-encoder/src/Vertex.cpp
  37. 21 7
      gameplay-encoder/src/Vertex.h
  38. 34 3
      gameplay-newproject.bat
  39. 256 0
      gameplay-newproject.sh
  40. 32 0
      gameplay-template/TEMPLATE_PROJECT-ios.plist
  41. 0 0
      gameplay-template/TEMPLATE_PROJECT-macosx.plist
  42. 1 0
      gameplay-template/android/jni/Application.mk
  43. 62 0
      gameplay-template/android/jni/template.Android.mk
  44. 4 0
      gameplay-template/android/res/values/template.strings.xml
  45. 32 0
      gameplay-template/android/template.AndroidManifest.xml
  46. 92 0
      gameplay-template/android/template.build.xml
  47. 266 47
      gameplay-template/gameplay-template.xcodeproj/project.pbxproj
  48. BIN
      gameplay-template/icon.png
  49. 2 2
      gameplay-template/res/box.material
  50. 3 1
      gameplay-template/template.bar-descriptor.xml
  51. 86 74
      gameplay.doxyfile
  52. 22 11
      gameplay.sln
  53. 3 0
      gameplay.xcworkspace/contents.xcworkspacedata
  54. 1 3
      gameplay/.cproject
  55. 0 12
      gameplay/.project
  56. 14 0
      gameplay/android/AndroidManifest.xml
  57. 85 0
      gameplay/android/build.xml
  58. 25 0
      gameplay/android/jni/Android.mk
  59. 2 0
      gameplay/android/jni/Application.mk
  60. 52 7
      gameplay/gameplay.vcxproj
  61. 152 20
      gameplay/gameplay.vcxproj.filters
  62. 401 172
      gameplay/gameplay.xcodeproj/project.pbxproj
  63. 0 57
      gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-MacOSX.xcscheme
  64. 0 57
      gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-iOS.xcscheme
  65. BIN
      gameplay/res/icon.png
  66. BIN
      gameplay/res/icon_128.ico
  67. BIN
      gameplay/res/icon_16.ico
  68. BIN
      gameplay/res/icon_32.ico
  69. BIN
      gameplay/res/icon_64.ico
  70. 27 0
      gameplay/res/logo.ai
  71. BIN
      gameplay/res/logo_black.png
  72. BIN
      gameplay/res/logo_powered_black.png
  73. BIN
      gameplay/res/logo_powered_white.png
  74. BIN
      gameplay/res/logo_white.png
  75. 7 0
      gameplay/res/shaders/bumped-specular.fsh
  76. 7 0
      gameplay/res/shaders/bumped.fsh
  77. 23 6
      gameplay/res/shaders/colored-specular.fsh
  78. 11 2
      gameplay/res/shaders/colored-specular.vsh
  79. 9 1
      gameplay/res/shaders/colored.fsh
  80. 11 3
      gameplay/res/shaders/diffuse-specular.fsh
  81. 9 11
      gameplay/res/shaders/diffuse-specular.vsh
  82. 9 1
      gameplay/res/shaders/diffuse.fsh
  83. 7 0
      gameplay/res/shaders/parallax-specular.fsh
  84. 7 0
      gameplay/res/shaders/parallax.fsh
  85. 7 0
      gameplay/res/shaders/solid.fsh
  86. 7 0
      gameplay/res/shaders/textured.fsh
  87. BIN
      gameplay/res/textures/particle-default.png
  88. 58 0
      gameplay/src/AbsoluteLayout.cpp
  89. 66 0
      gameplay/src/AbsoluteLayout.h
  90. 96 25
      gameplay/src/Animation.cpp
  91. 52 11
      gameplay/src/Animation.h
  92. 248 83
      gameplay/src/AnimationClip.cpp
  93. 108 30
      gameplay/src/AnimationClip.h
  94. 19 284
      gameplay/src/AnimationController.cpp
  95. 5 114
      gameplay/src/AnimationController.h
  96. 322 5
      gameplay/src/AnimationTarget.cpp
  97. 139 3
      gameplay/src/AnimationTarget.h
  98. 136 24
      gameplay/src/AudioBuffer.cpp
  99. 16 2
      gameplay/src/AudioBuffer.h
  100. 144 4
      gameplay/src/AudioController.cpp

+ 155 - 38
.gitignore

@@ -1,42 +1,159 @@
-# Compiled source #
-###################
-*.com
-*.class
-*.dll
-*.exe
-*.o
-*.so
-
-# Packages #
-############
-# it's better to unpack these files and commit the raw source
-# git has its own built in compression methods
-*.7z
-*.dmg
-*.gz
-*.iso
-*.jar
-*.rar
-*.tar
-*.zip
-*.fsh
-*.vsh
-
-# Logs and databases #
-######################
-*.log
-*.sql
-*.sqlite
-
-# OS generated files #
-######################
+*.suo
+*.sdf
+*.opensdf
 .DS_Store*
 ehthumbs.db
 Icon?
-Thumbs.db
+Thumbs.db
+/.metadata
+/169.254.0.1
+/ipch
+/Debug
+/Release
+/Simulator
+/Simulator-Coverage
+/Simulator-Profile
+/Device-Debug
+/Device-Coverage
+/Device-Profile
+/Device-Release
+/gameplay.xcworkspace/xcuserdata
+/gameplay/Debug
+/gameplay/DebugMem
+/gameplay/Release
+/gameplay/Simulator
+/gameplay/Simulator-Coverage
+/gameplay/Simulator-Profile
+/gameplay/Device-Debug
+/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
+/gameplay-samples/sample00-mesh/Release
+/gameplay-samples/sample00-mesh/Simulator
+/gameplay-samples/sample00-mesh/Simulator-Coverage
+/gameplay-samples/sample00-mesh/Simulator-Profile
+/gameplay-samples/sample00-mesh/Device-Debug
+/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/res/logo_powered_white.png
+/gameplay-samples/sample00-mesh/sample00-mesh.xcodeproj/xcuserdata
+/gameplay-samples/sample01-longboard/Debug
+/gameplay-samples/sample01-longboard/DebugMem
+/gameplay-samples/sample01-longboard/Release
+/gameplay-samples/sample01-longboard/Simulator
+/gameplay-samples/sample01-longboard/Simulator-Coverage
+/gameplay-samples/sample01-longboard/Simulator-Profile
+/gameplay-samples/sample01-longboard/Device-Debug
+/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/res/logo_powered_white.png
+/gameplay-samples/sample01-longboard/sample01-longboard.xcodeproj/xcuserdata
+/gameplay-samples/sample02-spaceship/Debug
+/gameplay-samples/sample02-spaceship/DebugMem
+/gameplay-samples/sample02-spaceship/Release
+/gameplay-samples/sample02-spaceship/Simulator
+/gameplay-samples/sample02-spaceship/Simulator-Coverage
+/gameplay-samples/sample02-spaceship/Simulator-Profile
+/gameplay-samples/sample02-spaceship/Device-Debug
+/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/res/logo_powered_white.png
+/gameplay-samples/sample02-spaceship/sample02-spaceship.xcodeproj/xcuserdata
+/gameplay-samples/sample03-character/Debug
+/gameplay-samples/sample03-character/DebugMem
+/gameplay-samples/sample03-character/Release
+/gameplay-samples/sample03-character/Simulator
+/gameplay-samples/sample03-character/Simulator-Coverage
+/gameplay-samples/sample03-character/Simulator-Profile
+/gameplay-samples/sample03-character/Device-Debug
+/gameplay-samples/sample03-character/Device-Coverage
+/gameplay-samples/sample03-character/Device-Profile
+/gameplay-samples/sample03-character/Device-Release
+/gameplay-samples/sample03-character/res/shaders
+/gameplay-samples/sample03-character/res/logo_powered_white.png
+/gameplay-samples/sample03-character/sample03-character.xcodeproj/xcuserdata
+/gameplay-samples/sample04-particles/Debug
+/gameplay-samples/sample04-particles/DebugMem
+/gameplay-samples/sample04-particles/Release
+/gameplay-samples/sample04-particles/Simulator
+/gameplay-samples/sample04-particles/Simulator-Coverage
+/gameplay-samples/sample04-particles/Simulator-Profile
+/gameplay-samples/sample04-particles/Device-Debug
+/gameplay-samples/sample04-particles/Device-Coverage
+/gameplay-samples/sample04-particles/Device-Profile
+/gameplay-samples/sample04-particles/Device-Release
+/gameplay-samples/sample04-particles/res/shaders
+/gameplay-samples/sample04-particles/res/logo_powered_white.png
+/gameplay-samples/sample04-particles/sample04-particles.xcodeproj/xcuserdata
+
+/gameplay-android/obj
+/gameplay-android/NUL
+/gameplay/android/NUL
+/gameplay/android/proguard.cfg
+/gameplay/android/local.properties
+/gameplay/android/project.properties
+/gameplay/android/obj
+/gameplay-samples/sample00-mesh/android/src
+/gameplay-samples/sample00-mesh/android/assets
+/gameplay-samples/sample00-mesh/android/bin
+/gameplay-samples/sample00-mesh/android/gen
+/gameplay-samples/sample00-mesh/android/libs
+/gameplay-samples/sample00-mesh/android/obj
+/gameplay-android/local.properties
+/gameplay-android/proguard.cfg
+/gameplay-android/project.properties
+/gameplay-samples/sample00-mesh/android/NUL
+/gameplay-samples/sample00-mesh/android/local.properties
+/gameplay-samples/sample00-mesh/android/proguard.cfg
+/gameplay-samples/sample00-mesh/android/project.properties
+/gameplay-samples/sample01-longboard/android/NUL
+/gameplay-samples/sample01-longboard/android/src
+/gameplay-samples/sample01-longboard/android/assets
+/gameplay-samples/sample01-longboard/android/bin
+/gameplay-samples/sample01-longboard/android/gen
+/gameplay-samples/sample01-longboard/android/libs
+/gameplay-samples/sample01-longboard/android/obj
+/gameplay-samples/sample01-longboard/android/project.properties
+/gameplay-samples/sample01-longboard/android/local.properties
+/gameplay-samples/sample02-spaceship/android/project.properties
+/gameplay-samples/sample02-spaceship/android/assets
+/gameplay-samples/sample02-spaceship/android/bin
+/gameplay-samples/sample02-spaceship/android/gen
+/gameplay-samples/sample02-spaceship/android/libs
+/gameplay-samples/sample02-spaceship/android/obj
+/gameplay-samples/sample02-spaceship/android/src
+/gameplay-samples/sample02-spaceship/android/proguard.cfg
+/gameplay-samples/sample02-spaceship/android/local.properties
+/gameplay-samples/sample03-character/android/project.properties
+/gameplay-samples/sample03-character/android/proguard.cfg
+/gameplay-samples/sample03-character/android/local.properties
+/gameplay-samples/sample01-longboard/android/proguard.cfg
+/gameplay-samples/sample02-spaceship/android/NUL
+/gameplay-samples/sample01-longboard/android/proguard.cfg
+/gameplay-samples/sample03-character/android/src
+/gameplay-samples/sample03-character/android/assets
+/gameplay-samples/sample03-character/android/bin
+/gameplay-samples/sample03-character/android/gen
+/gameplay-samples/sample03-character/android/libs
+/gameplay-samples/sample03-character/android/obj
+/gameplay-samples/sample03-character/android/NUL
+/gameplay-samples/sample01-longboard/NUL
 
-# PLAYBOOK Build Folders #
-##########################
-Simulator/
-Device-Debug/
-xcuserdata/
+
+/gameplay-samples/sample04-particles/Device-Debug
+/gameplay-samples/sample04-particles/Debug
+/gameplay-samples/sample04-particles/DebugMem
+/gameplay-samples/sample03-character/res/gamepad.xcf

+ 18 - 13
README.md

@@ -1,18 +1,24 @@
-## GamePlay v1.1.0
-GamePlay is a open-source, cross-platform 3D native gaming framework making it easy to learn and write mobile and desktop games. 
+## gameplay v1.2.0
+An open-source, cross-platform 3D native C++ game framework making it easy to learn and write mobile and desktop games. 
 
-## Supported Platforms
-- BlackBerry PlayBook 1.0/2.0 (using BlackBerry Native SDK 1.0/2.0)
-- Apple MacOS X (using Apple XCode 4.0)
-- Microsoft Windows 7 (using Microsoft Visual Studio 2010 Pro/Express)
-	* Requires OpenAL 1.1 (http://connect.creativelabs.com/openal/Downloads/Forms/AllItems.aspx)
+## Supported Mobile Platforms
+- BlackBerry PlayBook 2 (using BlackBerry Native SDK 2)
+- Google Android 2.3 (using Google Android NDK 7)
+- Apple iOS 5.1 (using Apple XCode 4.3.2)
+
+## Supported Desktop Platforms
+- Microsoft Windows 7 (using Microsoft Visual Studio 2010)
+- Apple MacOS X (using Apple XCode 4.3.2)
 
 ## Roadmap for 'next' branch
-- UI Forms with Themed Overlays.
-- Improvements to Lighting.
-- Developer Guide.
-- More Samples and Tutorials.
-- Apple iOS 5 Support.
+- Shadows
+- Lua Script Bindings
+- Terrain
+- Editor
+- Performance/Optimizations
+
+## Licence
+The project is open sourced under the Apache 2.0 license.
 
 ## Bug Reporting and Feature Requests
 If you find a bug in a Sample, or have an enhancement request, simply file an 
@@ -27,4 +33,3 @@ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIG
 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.
-

+ 5 - 0
gameplay-api/gameplay.html

@@ -0,0 +1,5 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Refresh" CONTENT="0; URL=html/index.html">
+</HEAD>
+</HTML>

BIN
gameplay-api/gameplay.png


+ 9 - 10
gameplay-encoder/README.md

@@ -1,6 +1,6 @@
-## 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. 
+## gameplay-encoder
+Command-line tool for encoding games assets like true-type fonts and 3D scene files
+into a simple binary-based bundle file format for the gameplay 3D game framework runtime. 
 
 ## TrueType Font Support
 TrueType Fonts conversion is enabled/built-in by default into gameplay-encoder via freetype 2 library.
@@ -27,10 +27,10 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
 - 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)"
+  * 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
+### Building FBX Support on Mac OS X using XCode 4.3.2+
 - 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)
@@ -41,12 +41,11 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
   * 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.
+## Bundle File Format
+The gameplay bundle file format is well defined in the gameplay-encoder/gameplay-bundle.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.
+## Bundle File Loading
+Bundle files can easily be loaded using the gameplay/Bundle.h which is part of the gameplay runtime framework.
 
 ## Disclaimer
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 

+ 11 - 11
gameplay-encoder/gameplay-binary.txt → gameplay-encoder/gameplay-bundle.txt

@@ -1,16 +1,16 @@
-gameplay Binary file format
+gameplay Bundle File Format (.gpb)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 File Description
 ================
-A sample binary file format supporting definition of primitve and builtin objects.
+A simple binary bundle file format supporting definition of primitve and builtin objects.
 
 File Extension and Mime Type
 ============================
-File extension is '.bbb' and the mime type is 'application/bbb'
+File extension is '.gpb' and the mime type is 'application/gpb'
 
 File Structure
-===============
+==============
 
 Section      Name            Type
 ------------------------------------------------------------------------------------------------------
@@ -22,31 +22,31 @@ Data
              Objects         Object[]
 
 Objects
-===========
+=======
 Supported object types are defined in the table below. Object with unique ids are included
 in the Reference table (see below).
 
 References
-===========
+==========
 A Reference is an Object that has a unique id. The Reference contains the unique id of the
 object, a uint for the TypeID a uint for the offset into the package for the object definition.
 
 ID's
-===========
+====
 Object ID's are represented as a string which is guaranteed to be unique per file.
 Any object which host an object id should be added to the header Reference table so that it can
 be consumed by reference internally and externally.
 
 Xrefs
-===========
+=====
 Xrefs are string with a specific format used for referencing objects internal and external to
 a package. An xref with the format "#id" references an object within the current package with
 the given ID. Xrefs can also have the format "file#id", where "file" is the name of package file
 (relative to the locaiton of the current package) and "id" is the unique identifier of an object
-in that package.
+in that bundle.
 
 Primitives
-===========
+==========
 
 Name            Description
 ------------------------------------------------------------------------------------------------------
@@ -198,9 +198,9 @@ Reference
 34->Mesh
                 vertexFormat            VertexElement[] { enum VertexUsage usage, unint size }
                 vertices                byte[]
-                parts                   MeshPart[]
                 boundingBox             BoundingBox { float[3] min, float[3] max }
                 boundingSphere          BoundingSphere { float[3] center, float radius }
+                parts                   MeshPart[]
 ------------------------------------------------------------------------------------------------------
 35->MeshPart
                 primitiveType           enum PrimitiveType

+ 3 - 2
gameplay-encoder/gameplay-encoder.vcxproj

@@ -11,12 +11,12 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\gameplay\src\Curve.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\AnimationChannel.cpp" />
     <ClCompile Include="src\Base.cpp" />
     <ClCompile Include="src\BoundingVolume.cpp" />
     <ClCompile Include="src\Camera.cpp" />
+    <ClCompile Include="src\Curve.cpp" />
     <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\DAEChannelTarget.cpp" />
     <ClCompile Include="src\DAEOptimizer.cpp" />
@@ -55,12 +55,12 @@
     <ClCompile Include="src\VertexElement.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\gameplay\src\Curve.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\AnimationChannel.h" />
     <ClInclude Include="src\Base.h" />
     <ClInclude Include="src\BoundingVolume.h" />
     <ClInclude Include="src\Camera.h" />
+    <ClInclude Include="src\Curve.h" />
     <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\DAEChannelTarget.h" />
     <ClInclude Include="src\DAEOptimizer.h" />
@@ -98,6 +98,7 @@
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="src\Curve.inl" />
     <None Include="src\Quaternion.inl" />
     <None Include="src\Vector2.inl" />
     <None Include="src\Vector3.inl" />

+ 9 - 6
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -19,9 +19,6 @@
     <ClCompile Include="src\Camera.cpp">
       <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="..\gameplay\src\Curve.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
     <ClCompile Include="src\DAEChannelTarget.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -127,6 +124,9 @@
     <ClCompile Include="src\VertexElement.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\Curve.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\VertexElement.h">
@@ -150,9 +150,6 @@
     <ClInclude Include="src\Camera.h">
       <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="..\gameplay\src\Curve.h">
-      <Filter>src</Filter>
-    </ClInclude>
     <ClInclude Include="src\DAEChannelTarget.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -252,6 +249,9 @@
     <ClInclude Include="src\Vertex.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Curve.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\Vector2.inl">
@@ -266,6 +266,9 @@
     <None Include="src\Quaternion.inl">
       <Filter>src</Filter>
     </None>
+    <None Include="src\Curve.inl">
+      <Filter>src</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Filter Include="src">

+ 37 - 33
gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj

@@ -8,9 +8,9 @@
 
 /* Begin PBXBuildFile section */
 		42475D7C14720ECE00610A6A /* libdom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42475D7B14720ECE00610A6A /* libdom.a */; };
+		4251B12C152D044B002F6199 /* Curve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4251B128152D044B002F6199 /* Curve.cpp */; };
 		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 */; };
 		42C8EE0B14724CD700E43619 /* AnimationChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB914724CD700E43619 /* AnimationChannel.cpp */; };
 		42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBB14724CD700E43619 /* Animations.cpp */; };
@@ -57,6 +57,7 @@
 		42C8EE3B1472DAAE00E43619 /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C8EE3A1472DAAE00E43619 /* libbz2.dylib */; };
 		42D277591472EFA700D867A4 /* libpcre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42D277571472EFA700D867A4 /* libpcre.a */; };
 		42D2775A1472EFA700D867A4 /* libpcrecpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42D277581472EFA700D867A4 /* libpcrecpp.a */; };
+		5BCD0643152CFC3C0071FAB5 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BCD0642152CFC3C0071FAB5 /* libpng.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -73,7 +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>"; };
+		42475D7B14720ECE00610A6A /* libdom.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdom.a; path = "../external-deps/collada-dom/lib/macosx/libdom.a"; sourceTree = "<group>"; };
+		4251B128152D044B002F6199 /* Curve.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Curve.cpp; path = src/Curve.cpp; sourceTree = SOURCE_ROOT; };
+		4251B129152D044B002F6199 /* Curve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Curve.h; path = src/Curve.h; sourceTree = SOURCE_ROOT; };
+		4251B12A152D044B002F6199 /* Curve.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Curve.inl; path = src/Curve.inl; sourceTree = SOURCE_ROOT; };
+		4251B12B152D044B002F6199 /* Quaternion.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Quaternion.inl; path = src/Quaternion.inl; sourceTree = SOURCE_ROOT; };
 		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; };
@@ -81,8 +86,6 @@
 		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>"; };
-		4283906214896F1600E2B2F5 /* Curve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Curve.h; path = ../gameplay/src/Curve.h; sourceTree = "<group>"; };
 		42C8EDB714724CD700E43619 /* Animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Animation.cpp; path = src/Animation.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EDB814724CD700E43619 /* Animation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Animation.h; path = src/Animation.h; sourceTree = SOURCE_ROOT; };
 		42C8EDB914724CD700E43619 /* AnimationChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnimationChannel.cpp; path = src/AnimationChannel.cpp; sourceTree = SOURCE_ROOT; };
@@ -162,12 +165,13 @@
 		42C8EE0714724CD700E43619 /* Vertex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vertex.h; path = src/Vertex.h; sourceTree = SOURCE_ROOT; };
 		42C8EE0814724CD700E43619 /* VertexElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VertexElement.cpp; path = src/VertexElement.cpp; sourceTree = SOURCE_ROOT; };
 		42C8EE0914724CD700E43619 /* VertexElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexElement.h; path = src/VertexElement.h; sourceTree = SOURCE_ROOT; };
-		42C8EE341472B60100E43619 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = "../external-deps/freetype2/lib/macos/libfreetype.a"; sourceTree = "<group>"; };
+		42C8EE341472B60100E43619 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = "../external-deps/freetype2/lib/macosx/libfreetype.a"; sourceTree = "<group>"; };
 		42C8EE361472D7E700E43619 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
 		42C8EE381472DAA300E43619 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
 		42C8EE3A1472DAAE00E43619 /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; };
-		42D277571472EFA700D867A4 /* libpcre.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcre.a; path = "../external-deps/pcre/lib/macos/libpcre.a"; sourceTree = "<group>"; };
-		42D277581472EFA700D867A4 /* libpcrecpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcrecpp.a; path = "../external-deps/pcre/lib/macos/libpcrecpp.a"; sourceTree = "<group>"; };
+		42D277571472EFA700D867A4 /* libpcre.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcre.a; path = "../external-deps/pcre/lib/macosx/libpcre.a"; sourceTree = "<group>"; };
+		42D277581472EFA700D867A4 /* libpcrecpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpcrecpp.a; path = "../external-deps/pcre/lib/macosx/libpcrecpp.a"; sourceTree = "<group>"; };
+		5BCD0642152CFC3C0071FAB5 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macosx/libpng.a"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -182,6 +186,7 @@
 				42C8EE3B1472DAAE00E43619 /* libbz2.dylib in Frameworks */,
 				42C8EE391472DAA300E43619 /* libz.dylib in Frameworks */,
 				42C8EE371472D7E700E43619 /* libxml2.dylib in Frameworks */,
+				5BCD0643152CFC3C0071FAB5 /* libpng.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -191,7 +196,6 @@
 		42475CDB147208A000610A6A = {
 			isa = PBXGroup;
 			children = (
-				4283906414896F3000E2B2F5 /* gameplay */,
 				42475CE9147208A000610A6A /* src */,
 				427D4F44147DC9080076760E /* Libraries */,
 				42475CE7147208A000610A6A /* Products */,
@@ -221,6 +225,9 @@
 				4283905814896E6C00E2B2F5 /* BoundingVolume.h */,
 				42C8EDBF14724CD700E43619 /* Camera.cpp */,
 				42C8EDC014724CD700E43619 /* Camera.h */,
+				4251B128152D044B002F6199 /* Curve.cpp */,
+				4251B129152D044B002F6199 /* Curve.h */,
+				4251B12A152D044B002F6199 /* Curve.inl */,
 				42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */,
 				42C8EDC414724CD700E43619 /* DAEChannelTarget.h */,
 				42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */,
@@ -270,6 +277,7 @@
 				42C8EDF114724CD700E43619 /* Object.h */,
 				42C8EDF214724CD700E43619 /* Quaternion.cpp */,
 				42C8EDF314724CD700E43619 /* Quaternion.h */,
+				4251B12B152D044B002F6199 /* Quaternion.inl */,
 				42C8EDF414724CD700E43619 /* Reference.cpp */,
 				42C8EDF514724CD700E43619 /* Reference.h */,
 				42C8EDF614724CD700E43619 /* ReferenceTable.cpp */,
@@ -303,6 +311,7 @@
 		427D4F44147DC9080076760E /* Libraries */ = {
 			isa = PBXGroup;
 			children = (
+				5BCD0642152CFC3C0071FAB5 /* libpng.a */,
 				42D277571472EFA700D867A4 /* libpcre.a */,
 				42D277581472EFA700D867A4 /* libpcrecpp.a */,
 				42C8EE3A1472DAAE00E43619 /* libbz2.dylib */,
@@ -314,15 +323,6 @@
 			name = Libraries;
 			sourceTree = "<group>";
 		};
-		4283906414896F3000E2B2F5 /* gameplay */ = {
-			isa = PBXGroup;
-			children = (
-				4283906114896F1600E2B2F5 /* Curve.cpp */,
-				4283906214896F1600E2B2F5 /* Curve.h */,
-			);
-			name = gameplay;
-			sourceTree = "<group>";
-		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -349,7 +349,7 @@
 		42475CDD147208A000610A6A /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0420;
+				LastUpgradeCheck = 0430;
 			};
 			buildConfigurationList = 42475CE0147208A000610A6A /* Build configuration list for PBXProject "gameplay-encoder" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -414,8 +414,8 @@
 				42C8EE3214724CD700E43619 /* Vertex.cpp in Sources */,
 				42C8EE3314724CD700E43619 /* VertexElement.cpp in Sources */,
 				4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */,
-				4283906314896F1600E2B2F5 /* Curve.cpp in Sources */,
 				42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */,
+				4251B12C152D044B002F6199 /* Curve.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -448,6 +448,7 @@
 					"../external-deps/freetype/include",
 					"../external-deps/collada-dom/include",
 					"../external-deps/collada-dom/include/1.4",
+					"../external-deps/libpng/include",
 				);
 				INFOPLIST_PREPROCESSOR_DEFINITIONS = "";
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
@@ -455,7 +456,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";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 ./external-deps/libpng/include";
 				WARNING_CFLAGS = "";
 			};
 			name = Debug;
@@ -483,13 +484,14 @@
 					"../external-deps/freetype/include",
 					"../external-deps/collada-dom/include",
 					"../external-deps/collada-dom/include/1.4",
+					"../external-deps/libpng/include",
 				);
 				INFOPLIST_PREPROCESSOR_DEFINITIONS = "";
 				MACOSX_DEPLOYMENT_TARGET = 10.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";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 ./external-deps/libpng/include";
 				WARNING_CFLAGS = "";
 			};
 			name = Release;
@@ -510,18 +512,19 @@
 					"../external-deps/freetype2/include",
 					"../external-deps/collada-dom/include",
 					"../external-deps/collada-dom/include/1.4",
+					"../external-deps/libpng/include",
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
-					"\"$(SRCROOT)/../external-deps/freetype2/lib/macos\"",
-					"\"$(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\"",
+					"\"$(SRCROOT)/../external-deps/freetype2/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/pcre/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/libpng/lib/macosx\"",
+					"\"$(SRCROOT)\"",
 				);
 				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";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype2/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 ../external-deps/libpng/include";
 			};
 			name = Debug;
 		};
@@ -541,18 +544,19 @@
 					"../external-deps/freetype2/include",
 					"../external-deps/collada-dom/include",
 					"../external-deps/collada-dom/include/1.4",
+					"../external-deps/libpng/include",
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
-					"\"$(SRCROOT)/../external-deps/freetype2/lib/macos\"",
-					"\"$(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\"",
+					"\"$(SRCROOT)/../external-deps/freetype2/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/collada-dom/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/pcre/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/libpng/lib/macosx\"",
+					"\"$(SRCROOT)\"",
 				);
 				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";
+				USER_HEADER_SEARCH_PATHS = "../external-deps/freetype2/include ../external-deps/collada-dom/include ../external-deps/collada-dom/include/1.4 ../external-deps/libpng/include";
 			};
 			name = Release;
 		};

+ 3 - 1
gameplay-encoder/gameplay-encoder.xcodeproj/xcshareddata/xcschemes/gameplay-encoder.xcscheme

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
+   LastUpgradeVersion = "0430"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
@@ -39,11 +40,12 @@
       </MacroExpansion>
    </TestAction>
    <LaunchAction
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
       buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
       allowLocationSimulation = "YES">
       <BuildableProductRunnable>

+ 10 - 0
gameplay-encoder/src/Animation.cpp

@@ -51,6 +51,15 @@ void Animation::add(AnimationChannel* animationChannel)
     _channels.push_back(animationChannel);
 }
 
+void Animation::remove(AnimationChannel* animationChannel)
+{
+    std::vector<AnimationChannel*>::iterator it = std::find(_channels.begin(), _channels.end(), animationChannel);
+    if (it != _channels.end())
+    {
+        _channels.erase(it);
+    }
+}
+
 unsigned int Animation::getAnimationChannelCount() const
 {
     return _channels.size();
@@ -58,6 +67,7 @@ unsigned int Animation::getAnimationChannelCount() const
 
 AnimationChannel* Animation::getAnimationChannel(unsigned int index) const
 {
+    assert(index < _channels.size());
     return _channels[index];
 }
 

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

@@ -26,8 +26,20 @@ public:
     virtual void writeBinary(FILE* file);
     virtual void writeText(FILE* file);
 
+    /**
+     * Adds the given animation channel to this animation.
+     * 
+     * @param animationChannel The animation channel to add.
+     */
     void add(AnimationChannel* animationChannel);
 
+    /**
+     * Removes the given animation channel from this animation.
+     * 
+     * @param animationChannel The animation channel to remove.
+     */
+    void remove(AnimationChannel* animationChannel);
+
     /**
      * Returns the number of animation channels contained in this animation.
      * 
@@ -36,7 +48,11 @@ public:
     unsigned int getAnimationChannelCount() const;
 
     /**
-     * Returns the specified animation channel.
+     * Returns the animation channel at the given index.
+     * 
+     * @param index The index of the animation channel to get.
+     * 
+     * @return The pointer to the animation channel or NULL if not found.
      */
     AnimationChannel* getAnimationChannel(unsigned int index) const;
 

+ 19 - 14
gameplay-encoder/src/AnimationChannel.cpp

@@ -43,7 +43,7 @@ void AnimationChannel::writeText(FILE* file)
 {
     fprintElementStart(file);
     fprintfElement(file, "targetId", _targetId);
-    fprintfElement(file, "targetAttrib", _targetAttrib);
+    fprintf(file, "<%s>%u %s</%s>\n", "targetAttrib", _targetAttrib, Transform::getPropertyString(_targetAttrib), "targetAttrib");
     fprintfElement(file, "%f ", "keytimes", _keytimes);
     fprintfElement(file, "%f ", "values", _keyValues);
     fprintfElement(file, "%f ", "tangentsIn", _tangentsIn);
@@ -130,27 +130,29 @@ void AnimationChannel::setInterpolations(const std::vector<unsigned int>& values
 
 void AnimationChannel::removeDuplicates()
 {
-    if (_targetAttrib == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+    size_t propSize = Transform::getPropertySize(_targetAttrib);
+
+    if (propSize > 1 && !_interpolations.empty() && _interpolations[0] == LINEAR)
     {
         size_t prevIndex = 0;
 
         std::vector<float>::iterator prevStart = _keyValues.begin();
-        std::vector<float>::iterator prevEnd   = _keyValues.begin() + 9;
+        std::vector<float>::iterator prevEnd = prevStart + propSize - 1;
         
         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);
+            std::vector<float>::iterator start = _keyValues.begin() + i * propSize;
+            std::vector<float>::iterator end = start + propSize - 1;
 
-            if (!equal(prevStart, prevEnd, start))
+            if (!equal(prevStart, prevEnd, start) || i == _keytimes.size() - 1)
             {
                 if (i - prevIndex > 2)
                 {
-                    deleteRange(prevIndex+1, i);
+                    deleteRange(prevIndex+1, i, propSize);
                     i = prevIndex;
-                    prevStart = _keyValues.begin() + i * 10;
-                    prevEnd = _keyValues.begin() + (i * 10 + 9);
+                    prevStart = _keyValues.begin() + i * propSize;
+                    prevEnd = prevStart + propSize - 1;
                 }
                 else
                 {
@@ -162,7 +164,7 @@ void AnimationChannel::removeDuplicates()
         }
         if (i - 1 - prevIndex >= 2)
         {
-            deleteRange(prevIndex+1, i);
+            deleteRange(prevIndex+1, i, propSize);
         }
     }
 }
@@ -270,13 +272,14 @@ unsigned int AnimationChannel::getInterpolationType(const char* str)
     return value;
 }
 
-void AnimationChannel::deleteRange(size_t begin, size_t end)
+void AnimationChannel::deleteRange(size_t begin, size_t end, size_t propSize)
 {
+    assert(end > begin);
     // 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;
+    std::vector<float>::iterator a = _keyValues.begin() + begin * propSize;
+    std::vector<float>::iterator b = _keyValues.begin() + end * propSize;
     _keyValues.erase(a, b);
 
     a = _keytimes.begin() + begin;
@@ -286,9 +289,11 @@ void AnimationChannel::deleteRange(size_t begin, size_t end)
     if (_interpolations.size() > 1)
     {
         std::vector<unsigned int>::iterator a = _interpolations.begin() + begin;
-        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * 10;
+        std::vector<unsigned int>::iterator b = _interpolations.begin() + end * propSize;
         _interpolations.erase(a, b);
     }
+
+    // TODO: also remove key frames from _tangentsIn and _tangentsOut once other curve types are supported.
 }
 
 }

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

@@ -60,6 +60,9 @@ public:
     const std::vector<float>& getTangentsOut() const;
     const std::vector<unsigned int>& getInterpolationTypes() const;
 
+    /**
+     * Removes duplicate key frames from the animation channel.
+     */
     void removeDuplicates();
 
     void convertToQuaternion();
@@ -77,7 +80,15 @@ public:
 
 private:
 
-    void deleteRange(size_t begin, size_t end);
+    /**
+     * Deletes all key frames from key time index begin to key time index end (exclusive).
+     * 
+     * @param begin The start index to delete.
+     * @param end The index to delete up to but not including.
+     * @param propSize The size of the animation propery to delete. Example: Translate(x,y,z) is size 3.
+     */
+    void deleteRange(size_t begin, size_t end, size_t propSize);
+
 private:
 
     std::string _targetId;

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

@@ -78,6 +78,14 @@ void fillArray(float values[], float value, size_t length);
 
 #define ISZERO(x) (fabs(x) < 0.000001f)
 
+// Object deletion macro
+#define SAFE_DELETE(x) \
+    if (x) \
+    { \
+        delete x; \
+        x = NULL; \
+    }
+
 #ifdef NDEBUG
 #define DEBUGPRINT(x)
 #define DEBUGPRINT_VARG(x, ...)

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

@@ -44,6 +44,7 @@ public:
     };
 
 private:
+    
     unsigned char _cameraType;
     float _fieldOfView;
     float _aspectRatio;

+ 1346 - 0
gameplay-encoder/src/Curve.cpp

@@ -0,0 +1,1346 @@
+// Purposely not including Base.h here, or any other gameplay dependencies
+// so this class can be reused between gameplay and gameplay-encoder.
+#include "Curve.h"
+#include "Quaternion.h"
+#include <cassert>
+#include <cmath>
+#include <memory>
+
+using std::memcpy;
+using std::fabs;
+using std::sqrt;
+using std::cos;
+using std::sin;
+using std::exp;
+using std::strcmp;
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef MATH_PI
+#define MATH_PI 3.14159265358979323846f
+#endif
+
+#ifndef MATH_PIOVER2 
+#define MATH_PIOVER2 1.57079632679489661923f
+#endif
+
+#ifndef MATH_PIX2
+#define MATH_PIX2 6.28318530717958647693f
+#endif
+
+// Object deletion macro
+#ifndef SAFE_DELETE
+#define SAFE_DELETE(x) \
+    if (x) \
+    { \
+        delete x; \
+        x = NULL; \
+    }
+#endif
+
+// Array deletion macro
+#ifndef SAFE_DELETE_ARRAY
+#define SAFE_DELETE_ARRAY(x) \
+    if (x) \
+    { \
+        delete[] x; \
+        x = NULL; \
+    }
+#endif
+
+
+namespace gameplay
+{
+
+Curve::Curve(unsigned int pointCount, unsigned int componentCount)
+    : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
+{
+    _points = new Point[_pointCount];
+    for (unsigned int i = 0; i < _pointCount; i++)
+    {
+        _points[i].time = 0.0f;
+        _points[i].value = new float[_componentCount];
+        _points[i].inValue = new float[_componentCount];
+        _points[i].outValue = new float[_componentCount];
+        _points[i].type = LINEAR;
+    }
+    _points[_pointCount - 1].time = 1.0f;
+}
+
+Curve::~Curve()
+{
+    SAFE_DELETE_ARRAY(_points);
+    SAFE_DELETE_ARRAY(_quaternionOffset);
+}
+
+Curve::Point::Point()
+    : time(0.0f), value(NULL), inValue(NULL), outValue(NULL)
+{
+}
+
+Curve::Point::~Point()
+{
+    SAFE_DELETE_ARRAY(value);
+    SAFE_DELETE_ARRAY(inValue);
+    SAFE_DELETE_ARRAY(outValue);
+}
+
+unsigned int Curve::getPointCount() const
+{
+    return _pointCount;
+}
+
+unsigned int Curve::getComponentCount() const
+{
+    return _componentCount;
+}
+
+float Curve::getStartTime() const
+{
+    return _points[0].time;
+}
+
+float Curve::getEndTime() const
+{
+    return _points[_pointCount-1].time;
+}
+
+void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type)
+{
+    setPoint(index, time, value, type, NULL, NULL);
+}
+
+void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue)
+{
+    assert(index < _pointCount && time >= 0.0f && time <= 1.0f && !(index == 0 && time != 0.0f) && !(index == _pointCount - 1 && time != 1.0f));
+
+    _points[index].time = time;
+    _points[index].type = type;
+
+    if (value)
+        memcpy(_points[index].value, value, _componentSize);
+
+    if (inValue)
+        memcpy(_points[index].inValue, inValue, _componentSize);
+
+    if (outValue)
+        memcpy(_points[index].outValue, outValue, _componentSize);
+}
+
+void Curve::setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue)
+{
+    assert(index < _pointCount);
+
+    _points[index].type = type;
+
+    if (inValue)
+        memcpy(_points[index].inValue, inValue, _componentSize);
+
+    if (outValue)
+        memcpy(_points[index].outValue, outValue, _componentSize);
+}
+
+void Curve::evaluate(float time, float* dst) const
+{
+    assert(dst && time >= 0 && time <= 1.0f);
+
+    // Check if we are at or beyond the bounds of the curve.
+    if (time <= _points[0].time)
+    {
+        memcpy(dst, _points[0].value, _componentSize);
+        return;
+    }
+    else if (time >= _points[_pointCount - 1].time)
+    {
+        memcpy(dst, _points[_pointCount - 1].value, _componentSize);
+        return;
+    }
+
+    // Locate the points we are interpolating between using a binary search.
+    unsigned int index = determineIndex(time);
+    
+    Point* from = _points + index;
+    Point* to = _points + (index + 1);
+
+    // Calculate the fractional time between the two points.
+    float scale = (to->time - from->time);
+    float t = (time - from->time) / scale;
+
+    // Calculate the value of the curve discretely if appropriate.
+    switch (from->type)
+    {
+        case BEZIER:
+        {
+            interpolateBezier(t, from, to, dst);
+            return;
+        }
+        case BSPLINE:
+        {
+            Point* c0;
+            Point* c1;
+            if (index == 0)
+            {
+                c0 = from;
+            }
+            else
+            {
+                c0 = (_points + index - 1);
+            }
+            
+            if (index == _pointCount - 2)
+            {
+                c1 = to;
+            }
+            else
+            {
+                c1 = (_points + index + 2);
+            }
+            interpolateBSpline(t, c0, from, to, c1, dst);
+            return;
+        }
+        case FLAT:
+        {
+            interpolateHermiteFlat(t, from, to, dst);
+            return;
+        }
+        case HERMITE:
+        {
+            interpolateHermite(t, from, to, dst);
+            return;
+        }
+        case LINEAR:
+        {
+            // Can just break here because linear formula follows switch
+            break;
+        }
+        case SMOOTH:
+        {
+            interpolateHermiteSmooth(t, index, from, to, dst);
+            return;
+        }
+        case STEP:
+        {
+            memcpy(dst, from->value, _componentSize);
+            return;
+        }
+        case QUADRATIC_IN:
+        {
+            t *= t;
+            break;
+        }
+        case QUADRATIC_OUT:
+        {
+            t *= -(t - 2.0f);
+            break;
+        }
+        case QUADRATIC_IN_OUT:
+        {
+            float tx2 = t * 2.0f;
+
+            if (tx2 < 1.0f)
+                t = 0.5f * (tx2 * tx2);
+            else
+            {
+                float temp = tx2 - 1.0f;
+                t = 0.5f * (-( temp * (temp - 2.0f)) + 1.0f);
+            }
+            break;
+        }
+        case QUADRATIC_OUT_IN:
+        {
+            if (t < 0.5f)
+            {
+                t = 2.0f * t * (1.0f - t);
+            }
+            else
+            {
+                t = 1.0f + 2.0f * t * (t - 1.0f);
+            }
+            break;
+        }
+        case CUBIC_IN:
+        {
+            t *= t * t;
+            break;
+        }
+        case CUBIC_OUT:
+        {
+            t--;
+            t = t * t * t + 1;
+            break;
+        }
+        case CUBIC_IN_OUT:
+        {
+            if ((t *= 2.0f) < 1.0f)
+            {
+                t = t * t * t * 0.5f;
+            }
+            else
+            {
+                t -= 2.0f;
+                t = (t * t * t + 2.0f) * 0.5f;
+            }
+            break;
+        }
+        case CUBIC_OUT_IN:
+        {
+            t = (2.0f * t - 1.0f);
+            t = (t * t * t + 1) * 0.5f;
+            break;
+        }
+        case QUARTIC_IN:
+        {
+            t *= t * t * t;
+            break;
+        }
+        case QUARTIC_OUT:
+        {
+            t--;
+            t = -(t * t * t * t) + 1.0f;
+            break;
+        }
+        case QUARTIC_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * t * t * t * t;
+            }
+            else
+            {
+                t -= 2.0f;
+                t = -0.5f * (t * t * t * t - 2.0f);
+            }
+            break;
+        }
+        case QUARTIC_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            if (t < 0.0f)
+            {
+                t = 0.5f * (-(t * t) * t * t + 1.0f);
+            }
+            else
+            {
+                t = 0.5f * (t * t * t * t + 1.0f);
+            }
+            break;
+        }
+        case QUINTIC_IN:
+        {
+            t *= t * t * t * t;
+            break;
+        }
+        case QUINTIC_OUT:
+        {
+            t--;
+            t = t * t * t * t * t + 1.0f;
+            break;
+        }
+        case QUINTIC_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * t * t * t * t * t;
+            }
+            else
+            {
+                t -= 2.0f;
+                t = 0.5f * (t * t * t * t * t + 2.0f);
+            }
+            break;
+        }
+        case QUINTIC_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            t = 0.5f * (t * t * t * t * t + 1.0f);
+            break;
+        }
+        case SINE_IN:
+        {
+            t = -(cos(t * MATH_PIOVER2) - 1.0f);
+            break;
+        }
+        case SINE_OUT:
+        {
+            t = sin(t * MATH_PIOVER2);
+            break;
+        }
+        case SINE_IN_OUT:
+        {
+            t = -0.5f * (cos(MATH_PI * t) - 1.0f);
+            break;
+        }
+        case SINE_OUT_IN:
+        {
+            if (t < 0.5f)
+            {
+                t = 0.5f * sin(MATH_PI * t);
+            }
+            else
+            {
+                t = -0.5f * cos(MATH_PIOVER2 * (2.0f * t - 1.0f)) + 1.0f;
+            }
+            break;
+        }
+        case EXPONENTIAL_IN:
+        {
+            if (t != 0.0f)
+            {
+                t = exp(10.0f * (t - 1.0f));
+            }
+            break;
+        }
+        case EXPONENTIAL_OUT:
+        {
+            if (t != 1.0f)
+            {
+                t = -exp(-10.0f * t) + 1.0f;
+            }
+            break;
+        }
+        case EXPONENTIAL_IN_OUT:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                if (t < 0.5f)
+                {
+                    t = 0.5f * exp(10.0f * (2.0f * t - 1.0f));
+                }
+                else
+                {
+                    t = -0.5f * exp(10.0f * (-2.0f * t + 1.0f)) + 1.0f;
+                }
+            }
+            break;
+        }
+        case EXPONENTIAL_OUT_IN:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                if (t < 0.5f)
+                {
+                    t = -0.5f * exp(-20.0f * t) + 0.5f;
+                }
+                else
+                {
+                    t = 0.5f * exp(20.0f * (t - 1.0f)) + 0.5f;
+                }
+            }
+            break;
+        }
+        case CIRCULAR_IN:
+        {
+            t = -(sqrt(1.0f - t * t) - 1.0f);
+            break;
+        }
+        case CIRCULAR_OUT:
+        {
+            t--;
+            t = sqrt(1.0f - t * t);
+            break;
+        }
+        case CIRCULAR_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * (-sqrt((1.0f - t * t)) + 1.0f);
+            }
+            else
+            {
+                t -= 2.0f;
+                t = 0.5f * (sqrt((1.0f - t * t)) + 1.0f);
+            }
+            break;
+        }
+        case CIRCULAR_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            if (t < 0.0f)
+            {
+                t = 0.5f * sqrt(1.0f - t * t);
+            }
+            else
+            {
+                t = 0.5f * (2.0f - sqrt(1.0f - t * t));
+            }
+            break;
+        }
+        case ELASTIC_IN:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t = t - 1.0f;
+                t = -1.0f * ( exp(10.0f * t) * sin( (t - 0.075f) * MATH_PIX2 / 0.3f ) );
+            }
+            break;
+        }
+        case ELASTIC_OUT:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t = exp(-10.0f * t) * sin((t - 0.075f) * MATH_PIX2 / 0.3f) + 1.0f;
+            }
+            break;
+        }
+        case ELASTIC_IN_OUT:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t = 2.0f * t - 1.0f;
+                if (t < 0.0f)
+                {
+                    t = -0.5f * (exp((10 * t)) * sin(((t - 0.1125f) * MATH_PIX2 / 0.45f)));
+                }
+                else
+                {
+                    t = 0.5f * exp((-10 * t)) * sin(((t - 0.1125f) * MATH_PIX2 / 0.45f)) + 1.0f;
+                }
+            }
+            break;
+        }
+        case ELASTIC_OUT_IN:
+        {
+            if (t != 0.0f && t != 1.0f)
+            {
+                t *= 2.0f;
+                if (t < 1.0f)
+                {
+                    t = 0.5f * (exp((-10 * t)) * sin(((t - 0.1125f) * (MATH_PIX2) / 0.45f))) + 0.5f;
+                }
+                else
+                {
+                    t = 0.5f * (exp((10 *(t - 2))) * sin(((t - 0.1125f) * (MATH_PIX2) / 0.45f))) + 0.5f;
+                }
+            }
+            break;
+        }
+        case OVERSHOOT_IN:
+        {
+            t = t * t * (2.70158f * t - 1.70158f);
+            break;
+        }
+        case OVERSHOOT_OUT:
+        {
+            t--;
+            t = t * t * (2.70158f * t + 1.70158f) + 1;
+            break;
+        }
+        case OVERSHOOT_IN_OUT:
+        {
+            t *= 2.0f;
+            if (t < 1.0f)
+            {
+                t = 0.5f * t * t * (3.5949095f * t - 2.5949095f);
+            }
+            else
+            {
+                t -= 2.0f;
+                t = 0.5f * (t * t * (3.5949095f * t + 2.5949095f) + 2.0f);
+            }
+            break;
+        }
+        case OVERSHOOT_OUT_IN:
+        {
+            t = 2.0f * t - 1.0f;
+            if (t < 0.0f)
+            {
+                t = 0.5f * (t * t * (3.5949095f * t + 2.5949095f) + 1.0f);
+            }
+            else
+            {
+                t = 0.5f * (t * t * (3.5949095f * t - 2.5949095f) + 1.0f);
+            }
+            break;
+        }
+        case BOUNCE_IN:
+        {
+            t = 1.0f - t;
+
+            if (t < 0.36363636363636365f)
+            {
+                t = 7.5625f * t * t;
+            }
+            else if (t < 0.7272727272727273f)
+            {
+                t -= 0.5454545454545454f;
+                t = 7.5625f * t * t + 0.75f;
+            }
+            else if (t < 0.9090909090909091f)
+            {
+                t -= 0.8181818181818182f;
+                t = 7.5625f * t * t + 0.9375f;
+            }
+            else
+            {
+                t -= 0.9545454545454546f;
+                t = 7.5625f * t * t + 0.984375f;
+            }
+
+            t = 1.0f - t;
+            break;
+        }
+        case BOUNCE_OUT:
+        {
+            if (t < 0.36363636363636365f)
+            {
+                t = 7.5625f * t * t;
+            }
+            else if (t < 0.7272727272727273f)
+            {
+                t -= 0.5454545454545454f;
+                t = 7.5625f * t * t + 0.75f;
+            }
+            else if (t < 0.9090909090909091f)
+            {
+                t -= 0.8181818181818182f;
+                t = 7.5625f * t * t + 0.9375f;
+            }
+            else
+            {
+                t -= 0.9545454545454546f;
+                t = 7.5625f * t * t + 0.984375f;
+            }
+            break;
+        }
+        case BOUNCE_IN_OUT:
+        {
+            if (t < 0.5f)
+            {
+                t = 1.0f - t * 2.0f;
+
+                if (t < 0.36363636363636365f)
+                {
+                    t = 7.5625f * t * t;
+                }
+                else if (t < 0.7272727272727273f)
+                {
+                    t -= 0.5454545454545454f;
+                    t = 7.5625f * t * t + 0.75f;
+                }
+                else if (t < 0.9090909090909091f)
+                {
+                    t -= 0.8181818181818182f;
+                    t = 7.5625f * t * t + 0.9375f;
+                }
+                else
+                {
+                    t -= 0.9545454545454546f;
+                    t = 7.5625f * t * t + 0.984375f;
+                }
+
+                t = (1.0f - t) * 0.5f;
+            }
+            else
+            {
+                t = t * 2.0f - 1.0f;
+                if (t < 0.36363636363636365f)
+                {
+                    t = 7.5625f * t * t;
+                }
+                else if (t < 0.7272727272727273f)
+                {
+                    t -= 0.5454545454545454f;
+                    t = 7.5625f * t * t + 0.75f;
+                }
+                else if (t < 0.9090909090909091f)
+                {
+                    t -= 0.8181818181818182f;
+                    t = 7.5625f * t * t + 0.9375f;
+                }
+                else
+                {
+                    t -= 0.9545454545454546f;
+                    t = 7.5625f * t * t + 0.984375f;
+                }
+
+                t = 0.5f * t + 0.5f;
+            }
+            break;
+        }
+        case BOUNCE_OUT_IN:
+        {
+            if (t < 0.1818181818f)
+            {
+                t = 15.125f * t * t;
+            }
+            else if (t < 0.3636363636f)
+            {
+                t = 1.5f + (-8.250000001f + 15.125f * t) * t;
+            }
+            else if (t < 0.4545454546f)
+            {
+                t = 3.0f + (-12.375f + 15.125f * t) * t;
+            }
+            else if (t < 0.5f)
+            {
+                t = 3.9375f + (-14.4375f + 15.125f * t) * t;
+            }
+            else if (t <= 0.5454545455f)
+            {
+                t = -3.625000004f + (15.81250001f - 15.125f * t) * t;
+            }
+            else if (t <= 0.6363636365f)
+            {
+                t = -4.75f + (17.875f - 15.125f * t) * t;
+            }
+            else if (t <= 0.8181818180f)
+            {
+                t = -7.374999995f + (21.99999999f - 15.125f * t) * t;
+            }
+            else
+            {
+                t = -14.125f + (30.25f - 15.125f * t) * t;
+            }
+            break;
+        }
+    }
+
+    interpolateLinear(t, from, to, dst);
+}
+
+float Curve::lerp(float t, float from, float to)
+{
+    return lerpInl(t, from, to);
+}
+
+void Curve::setQuaternionOffset(unsigned int offset)
+{
+    assert(offset <= (_componentCount - 4));
+
+    if (!_quaternionOffset)
+        _quaternionOffset = new unsigned int[1];
+    
+    *_quaternionOffset = offset;
+}
+
+void Curve::interpolateBezier(float s, Point* from, Point* to, float* dst) const
+{
+    float s_2 = s * s;
+    float eq0 = 1 - s;
+    float eq0_2 = eq0 * eq0;
+    float eq1 = eq0_2 * eq0;
+    float eq2 = 3 * s * eq0_2;
+    float eq3 = 3 * s_2 * eq0;
+    float eq4 = s_2 * s;
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+    float* outValue = from->outValue;
+    float* inValue = to->inValue;
+
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime = bezier(eq1, eq2, eq3, eq4, from->time, outValue[i], to->time, inValue[i]);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = bezier(eq1, eq2, eq3, eq4, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point* c3, float* dst) const
+{   
+    float s_2 = s * s;
+    float s_3 = s_2 * s;
+    float eq0 = (-s_3 + 3 * s_2 - 3 * s + 1) / 6.0f;
+    float eq1 = (3 * s_3 - 6 * s_2 + 4) / 6.0f;
+    float eq2 = (-3 * s_3 + 3 * s_2 + 3 * s + 1) / 6.0f;
+    float eq3 = s_3 / 6.0f;
+
+    float* c0Value = c0->value;
+    float* c1Value = c1->value;
+    float* c2Value = c2->value;
+    float* c3Value = c3->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime;
+        if (c0->time == c1->time)
+            interpTime = bspline(eq0, eq1, eq2, eq3, -c0->time, c1->time, c2->time, c3->time);
+        else if (c2->time == c3->time)
+            interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, -c3->time); 
+        else
+            interpTime = bspline(eq0, eq1, eq2, eq3, c0->time, c1->time, c2->time, c3->time);
+        interpolateQuaternion(s, (c1Value + i) , (c2Value + i), (dst + i));
+            
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (c1Value[i] == c2Value[i])
+                dst[i] = c1Value[i];
+            else
+                dst[i] = bspline(eq0, eq1, eq2, eq3, c0Value[i], c1Value[i], c2Value[i], c3Value[i]);
+        }
+    }
+}
+
+void Curve::interpolateHermite(float s, Point* from, Point* to, float* dst) const
+{
+    // Calculate the hermite basis functions.
+    float s_2 = s * s;                   // t^2
+    float s_3 = s_2 * s;                 // t^3
+    float h00 = 2 * s_3 - 3 * s_2 + 1;   // basis function 0
+    float h01 = -2 * s_3 + 3 * s_2;      // basis function 1
+    float h10 = s_3 - 2 * s_2 + s;       // basis function 2
+    float h11 = s_3 - s_2;               // basis function 3
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+    float* outValue = from->outValue;
+    float* inValue = to->inValue;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime = hermite(h00, h01, h10, h11, from->time, outValue[i], to->time, inValue[i]);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermite(h00, h01, h10, h11, fromValue[i], outValue[i], toValue[i], inValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateHermiteFlat(float s, Point* from, Point* to, float* dst) const
+{
+    // Calculate the hermite basis functions.
+    float s_2 = s * s;                   // t^2
+    float s_3 = s_2 * s;                 // t^3
+    float h00 = 2 * s_3 - 3 * s_2 + 1;   // basis function 0
+    float h01 = -2 * s_3 + 3 * s_2;      // basis function 1
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+        }
+
+        // Handle quaternion component.
+        float interpTime = hermiteFlat(h00, h01, from->time, to->time);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = hermiteFlat(h00, h01, fromValue[i], toValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const
+{
+    // Calculate the hermite basis functions.
+    float s_2 = s * s;                   // t^2
+    float s_3 = s_2 * s;                 // t^3
+    float h00 = 2 * s_3 - 3 * s_2 + 1;   // basis function 0
+    float h01 = -2 * s_3 + 3 * s_2;      // basis function 1
+    float h10 = s_3 - 2 * s_2 + s;       // basis function 2
+    float h11 = s_3 - s_2;               // basis function 3
+
+    float inValue;
+    float outValue;
+
+    float* fromValue = from->value;
+    float* toValue = to->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+            {
+                dst[i] = fromValue[i];
+            }
+            else
+            {
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
+
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
+
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {   
+            if (fromValue[i] == toValue[i])
+            {
+                dst[i] = fromValue[i];
+            }
+            else
+            {    
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
+
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
+
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
+        }
+
+        // Handle quaternion component.
+        if (index == 0)
+        {
+            outValue = to->time - from->time;
+        }
+        else
+        {
+            outValue = (to->time - (from - 1)->time) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+        }
+
+        if (index == _pointCount - 2)
+        {
+            inValue = to->time - from->time;
+        }
+        else
+        {
+            inValue = ((to + 1)->time - from->time) * ((to->time - from->time) / ((to + 1)->time - from->time));
+        }
+
+        float interpTime = hermiteSmooth(h00, h01, h10, h11, from->time, outValue, to->time, inValue);
+        interpolateQuaternion(interpTime, (fromValue + i), (toValue + i), (dst + i));
+        
+        // Handle remaining components (if any) as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+            {
+                dst[i] = fromValue[i];
+            }
+            else
+            {
+                // Interpolate as scalar.
+                if (index == 0)
+                {
+                    outValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    outValue = (toValue[i] - (from - 1)->value[i]) * ((from->time - (from - 1)->time) / (to->time - (from - 1)->time));
+                }
+
+                if (index == _pointCount - 2)
+                {
+                    inValue = toValue[i] - fromValue[i];
+                }
+                else
+                {
+                    inValue = ((to + 1)->value[i] - fromValue[i]) * ((to->time - from->time) / ((to + 1)->time - from->time));
+                }
+
+                dst[i] = hermiteSmooth(h00, h01, h10, h11, fromValue[i], outValue, toValue[i], inValue);
+            }
+        }
+    }
+}
+
+void Curve::interpolateLinear(float s, Point* from, Point* to, float* dst) const
+{
+    float* fromValue = from->value;
+    float* toValue = to->value;
+
+    if (!_quaternionOffset)
+    {
+        for (unsigned int i = 0; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
+        }
+    }
+    else
+    {
+        // Interpolate any values up to the quaternion offset as scalars.
+        unsigned int quaternionOffset = *_quaternionOffset;
+        unsigned int i = 0;
+        for (i = 0; i < quaternionOffset; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
+        }
+
+        // Handle quaternion component.
+        interpolateQuaternion(s, (fromValue + i), (toValue + i), (dst + i));
+        
+        // handle any remaining components as scalars
+        for (i += 4; i < _componentCount; i++)
+        {
+            if (fromValue[i] == toValue[i])
+                dst[i] = fromValue[i];
+            else
+                dst[i] = lerpInl(s, fromValue[i], toValue[i]);
+        }
+    }
+}
+
+void Curve::interpolateQuaternion(float s, float* from, float* to, float* dst) const
+{
+    // Evaluate.
+    if (s >= 0)
+    {
+        Quaternion::slerp(from[0], from[1], from[2], from[3], to[0], to[1], to[2], to[3], s, dst, dst + 1, dst + 2, dst + 3);
+    }
+    else
+        Quaternion::slerp(to[0], to[1], to[2], to[3], from[0], from[1], from[2], from[3], s, dst, dst + 1, dst + 2, dst + 3);
+
+    //((Quaternion*) dst)->normalize();
+}
+
+int Curve::determineIndex(float time) const
+{
+    unsigned int min = 0;
+    unsigned int max = _pointCount - 1;
+    unsigned int mid = 0;
+
+    // Do a binary search to determine the index.
+    do 
+    {
+        mid = (min + max) >> 1;
+
+        if (time >= _points[mid].time && time <= _points[mid + 1].time)
+            return mid;
+        else if (time < _points[mid].time)
+            max = mid - 1;
+        else
+            min = mid + 1;
+    } while (min <= max);
+    
+    // We should never hit this!
+    return -1;
+}
+
+int Curve::getInterpolationType(const char* curveId)
+{
+    if (strcmp(curveId, "BEZIER") == 0)
+    {
+        return Curve::BEZIER;
+    }
+    else if (strcmp(curveId, "BSPLINE") == 0)
+    {
+        return Curve::BSPLINE;
+    }
+    else if (strcmp(curveId, "FLAT") == 0)
+    {
+        return Curve::FLAT;
+    }
+    else if (strcmp(curveId, "HERMITE") == 0)
+    {
+        return Curve::HERMITE;
+    }
+    else if (strcmp(curveId, "LINEAR") == 0)
+    {
+        return Curve::LINEAR;
+    }
+    else if (strcmp(curveId, "SMOOTH") == 0)
+    {
+        return Curve::SMOOTH;
+    }
+    else if (strcmp(curveId, "STEP") == 0)
+    {
+        return Curve::STEP;
+    }
+    else if (strcmp(curveId, "QUADRATIC_IN") == 0)
+    {
+        return Curve::QUADRATIC_IN;
+    }
+    else if (strcmp(curveId, "QUADRATIC_OUT") == 0)
+    {
+        return Curve::QUADRATIC_OUT;
+    }
+    else if (strcmp(curveId, "QUADRATIC_IN_OUT") == 0)
+    {
+        return Curve::QUADRATIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "QUADRATIC_OUT_IN") == 0)
+    {
+        return Curve::QUADRATIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "CUBIC_IN") == 0)
+    {
+        return Curve::CUBIC_IN;
+    }
+    else if (strcmp(curveId, "CUBIC_OUT") == 0)
+    {
+        return Curve::CUBIC_OUT;
+    }
+    else if (strcmp(curveId, "CUBIC_IN_OUT") == 0)
+    {
+        return Curve::CUBIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "CUBIC_OUT_IN") == 0)
+    {
+        return Curve::CUBIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "QUARTIC_IN") == 0)
+    {
+        return Curve::QUARTIC_IN;
+    }
+    else if (strcmp(curveId, "QUARTIC_OUT") == 0)
+    {
+        return Curve::QUARTIC_OUT;
+    }
+    else if (strcmp(curveId, "QUARTIC_IN_OUT") == 0)
+    {
+        return Curve::QUARTIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "QUARTIC_OUT_IN") == 0)
+    {
+        return Curve::QUARTIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "QUINTIC_IN") == 0)
+    {
+        return Curve::QUINTIC_IN;
+    }
+    else if (strcmp(curveId, "QUINTIC_OUT") == 0)
+    {
+        return Curve::QUINTIC_OUT;
+    }
+    else if (strcmp(curveId, "QUINTIC_IN_OUT") == 0)
+    {
+        return Curve::QUINTIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "QUINTIC_OUT_IN") == 0)
+    {
+        return Curve::QUINTIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "SINE_IN") == 0)
+    {
+        return Curve::SINE_IN;
+    }
+    else if (strcmp(curveId, "SINE_OUT") == 0)
+    {
+        return Curve::SINE_OUT;
+    }
+    else if (strcmp(curveId, "SINE_IN_OUT") == 0)
+    {
+        return Curve::SINE_IN_OUT;
+    }
+    else if (strcmp(curveId, "SINE_OUT_IN") == 0)
+    {
+        return Curve::SINE_OUT_IN;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_IN") == 0)
+    {
+        return Curve::EXPONENTIAL_IN;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_OUT") == 0)
+    {
+        return Curve::EXPONENTIAL_OUT;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_IN_OUT") == 0)
+    {
+        return Curve::EXPONENTIAL_IN_OUT;
+    }
+    else if (strcmp(curveId, "EXPONENTIAL_OUT_IN") == 0)
+    {
+        return Curve::EXPONENTIAL_OUT_IN;
+    }
+    else if (strcmp(curveId, "CIRCULAR_IN") == 0)
+    {
+        return Curve::CIRCULAR_IN;
+    }
+    else if (strcmp(curveId, "CIRCULAR_OUT") == 0)
+    {
+        return Curve::CIRCULAR_OUT;
+    }
+    else if (strcmp(curveId, "CIRCULAR_IN_OUT") == 0)
+    {
+        return Curve::CIRCULAR_IN_OUT;
+    }
+    else if (strcmp(curveId, "CIRCULAR_OUT_IN") == 0)
+    {
+        return Curve::CIRCULAR_OUT_IN;
+    }
+    else if (strcmp(curveId, "ELASTIC_IN") == 0)
+    {
+        return Curve::ELASTIC_IN;
+    }
+    else if (strcmp(curveId, "ELASTIC_OUT") == 0)
+    {
+        return Curve::ELASTIC_OUT;
+    }
+    else if (strcmp(curveId, "ELASTIC_IN_OUT") == 0)
+    {
+        return Curve::ELASTIC_IN_OUT;
+    }
+    else if (strcmp(curveId, "ELASTIC_OUT_IN") == 0)
+    {
+        return Curve::ELASTIC_OUT_IN;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_IN") == 0)
+    {
+        return Curve::OVERSHOOT_IN;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_OUT") == 0)
+    {
+        return Curve::OVERSHOOT_OUT;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_IN_OUT") == 0)
+    {
+        return Curve::OVERSHOOT_IN_OUT;
+    }
+    else if (strcmp(curveId, "OVERSHOOT_OUT_IN") == 0)
+    {
+        return Curve::OVERSHOOT_OUT_IN;
+    }
+    else if (strcmp(curveId, "BOUNCE_IN") == 0)
+    {
+        return Curve::BOUNCE_IN;
+    }
+    else if (strcmp(curveId, "BOUNCE_OUT") == 0)
+    {
+        return Curve::BOUNCE_OUT;
+    }
+    else if (strcmp(curveId, "BOUNCE_IN_OUT") == 0)
+    {
+        return Curve::BOUNCE_IN_OUT;
+    }
+    else if (strcmp(curveId, "BOUNCE_OUT_IN") == 0)
+    {
+        return Curve::BOUNCE_OUT_IN;
+    }
+
+    return -1;
+}
+
+}

+ 484 - 0
gameplay-encoder/src/Curve.h

@@ -0,0 +1,484 @@
+#ifndef CURVE_H_
+#define CURVE_H_
+
+namespace gameplay
+{
+
+/**
+ * Represents an n-dimensional curve.
+ */
+class Curve
+{
+    friend class Animation;
+    friend class AnimationClip;
+    friend class AnimationController;
+    friend class MeshSkin;
+
+public:
+
+    /**
+     * Types of interpolation.
+     *
+     * Defines how the points in the curve are connected.
+     *
+     * Note: InterpolationType::BEZIER requires control points and InterpolationType::HERMITE requires tangents.
+     */
+    enum InterpolationType
+    {
+        /**
+         * Bezier Interpolation. 
+         *
+         * Requires that two control points are set for each segment.
+         */
+        BEZIER,
+
+        /**
+         * B-Spline Interpolation. 
+         *
+         * Uses the points as control points, and the curve is guaranteed to only pass through the
+         * first and last point.
+         */
+        BSPLINE,
+
+        /**
+         * Flat Interpolation. 
+         * 
+         * A form of Hermite interpolation that generates flat tangents for you. The tangents have a value equal to 0.
+         */
+        FLAT,
+
+        /**
+         * Hermite Interpolation. 
+         *
+         * Requires that two tangents for each segment.
+         */
+        HERMITE,
+
+        /**
+         * Linear Interpolation.
+         */
+        LINEAR,
+
+        /** 
+         * Smooth Interpolation. 
+         *
+         * A form of Hermite interpolation that generates tangents for each segment based on the points prior to and after the segment.
+         */
+        SMOOTH,
+
+        /**
+         * Discrete Interpolation.
+         */ 
+        STEP,
+
+        /**
+         * Quadratic-In Interpolation.
+         */
+        QUADRATIC_IN, 
+        
+        /**
+         * Quadratic-Out Interpolation.
+         */
+        QUADRATIC_OUT,
+
+        /**
+         * Quadratic-In-Out Interpolation.
+         */
+        QUADRATIC_IN_OUT,
+
+        /**
+         * Quadratic-Out-In Interpolation.
+         */
+        QUADRATIC_OUT_IN,
+
+        /**
+         * Cubic-In Interpolation.
+         */
+        CUBIC_IN,
+        
+        /**
+         * Cubic-Out Interpolation.
+         */
+        CUBIC_OUT,
+        
+        /**
+         * Cubic-In-Out Interpolation.
+         */
+        CUBIC_IN_OUT,
+        
+        /**
+         * Cubic-Out-In Interpolation.
+         */
+        CUBIC_OUT_IN,
+
+        /**
+         * Quartic-In Interpolation.
+         */
+        QUARTIC_IN,
+
+        /**
+         * Quartic-Out Interpolation.
+         */
+        QUARTIC_OUT,
+
+        /**
+         * Quartic-In-Out Interpolation.
+         */
+        QUARTIC_IN_OUT,
+
+        /**
+         * Quartic-Out-In Interpolation.
+         */
+        QUARTIC_OUT_IN,
+
+        /**
+         * Quintic-In Interpolation.
+         */
+        QUINTIC_IN,
+        
+        /**
+         * Quintic-Out Interpolation.
+         */
+        QUINTIC_OUT,
+        
+        /**
+         * Quintic-In-Out Interpolation.
+         */
+        QUINTIC_IN_OUT,
+        
+        /**
+         * Quintic-Out-In Interpolation.
+         */
+        QUINTIC_OUT_IN,
+        
+        /**
+         * Sine-In Interpolation.
+         */
+        SINE_IN,
+        
+        /**
+         * Sine-Out Interpolation.
+         */
+        SINE_OUT,
+        
+        /**
+         * Sine-In-Out Interpolation.
+         */
+        SINE_IN_OUT,
+        
+        /**
+         * Sine-Out-In Interpolation.
+         */
+        SINE_OUT_IN,
+
+        /**
+         * Exponential-In Interpolation.
+         */
+        EXPONENTIAL_IN,
+
+        /**
+         * Exponential-Out Interpolation.
+         */
+        EXPONENTIAL_OUT,
+
+        /**
+         * Exponential-In-Out Interpolation.
+         */
+        EXPONENTIAL_IN_OUT,
+
+        /**
+         * Exponential-Out-In Interpolation.
+         */
+        EXPONENTIAL_OUT_IN,
+
+        /**
+         * Circular-In Interpolation.
+         */
+        CIRCULAR_IN,
+
+        /**
+         * Circular-Out Interpolation.
+         */
+        CIRCULAR_OUT,
+
+        /**
+         * Circular-In-Out Interpolation.
+         */
+        CIRCULAR_IN_OUT,
+
+        /**
+         * Circular-Out-In Interpolation.
+         */
+        CIRCULAR_OUT_IN,
+
+        /**
+         * Elastic-In Interpolation.
+         */
+        ELASTIC_IN,
+
+        /**
+         * Elastic-Out Interpolation.
+         */
+        ELASTIC_OUT,
+
+        /**
+         * Elastic-In-Out Interpolation.
+         */
+        ELASTIC_IN_OUT,
+
+        /**
+         * Elastic-Out-In Interpolation.
+         */
+        ELASTIC_OUT_IN,
+
+        /**
+         * Overshoot-In Interpolation.
+         */
+        OVERSHOOT_IN,
+
+        /**
+         * Overshoot-Out Interpolation.
+         */
+        OVERSHOOT_OUT,
+
+        /**
+         * Overshoot-In-Out Interpolation.
+         */
+        OVERSHOOT_IN_OUT,
+
+        /**
+         * Overshoot-Out-In Interpolation.
+         */
+        OVERSHOOT_OUT_IN,
+
+        /**
+         * Bounce-In Interpolation.
+         */
+        BOUNCE_IN,
+
+        /**
+         * Bounce-Out Interpolation.
+         */
+        BOUNCE_OUT,
+
+        /**
+         * Bounce-In-Out Interpolation.
+         */
+        BOUNCE_IN_OUT,
+
+        /**
+         * Bounce-Out-In Interpolation.
+         */
+        BOUNCE_OUT_IN
+    };
+
+
+    /**
+     * Constructs a new curve and the specified parameters.
+     *
+     * @param pointCount The number of points in the curve.
+     * @param componentCount The number of float component values per key value.
+     */
+    Curve(unsigned int pointCount, unsigned int componentCount);
+
+    /**
+     * Destructor.
+     */
+    ~Curve();
+
+    /**
+     * Gets the number of points in the curve.
+     *
+     * @return The number of points in the curve.
+     */
+    unsigned int getPointCount() const;
+
+    /**
+     * Gets the number of float component values per points.
+     *
+     * @return The number of float component values per point.
+     */
+    unsigned int getComponentCount() const;
+
+    /**
+     * Returns the start time for the curve.
+     *
+     * @return The curve's start time.
+     */
+    float getStartTime() const;
+
+    /**
+     * Returns the end time for the curve.
+     *
+     * @return The curve's end time.
+     */
+    float getEndTime() const;
+
+    /**
+     * Sets the given point values on the curve the curve.
+     *
+     * @param index The index of the point.
+     * @param time The time for the key.
+     * @param value The point to add.
+     * @param type The curve interpolation type.
+     */
+    void setPoint(unsigned int index, float time, float* value, InterpolationType type);
+
+    /**
+     * Sets the given point on the curve for the specified index and the specified parameters.
+     *
+     * @param index The index of the point.
+     * @param time The time of the point within the curve.
+     * @param value The value of the point to copy the data from.
+     * @param type The curve interpolation type.
+     * @param inValue The tangent approaching the point.
+     * @param outValue The tangent leaving the point.
+     */
+    void setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue);
+
+    /**
+     * Sets the tangents for a point on the curve specified by the index.
+     *
+     * @param index The index of the point.
+     * @param type The curve interpolation type.
+     * @param inValue The tangent approaching the point.
+     * @param outValue The tangent leaving the point.
+     */
+    void setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue);
+    
+    /**
+     * Evaluates the curve at the given position value (between 0.0 and 1.0 inclusive).
+     *
+     * @param time The position to evaluate the curve at.
+     * @param dst The evaluated value of the curve at the given time.
+     */
+    void evaluate(float time, float* dst) const;
+
+    /**
+     * Linear interpolation function.
+     */
+    static float lerp(float t, float from, float to);
+
+private:
+
+    /**
+     * Defines a single point within a curve.
+     */
+    class Point
+    {
+    public:
+
+        /** The time of the point within the curve. */
+        float time;
+        /** The value of the point. */
+        float* value;
+        /** The value of the tangent when approaching this point (from the previous point in the curve). */
+        float* inValue;
+        /** The value of the tangent when leaving this point (towards the next point in the curve). */
+        float* outValue;
+        /** The type of interpolation to use between this point and the next point. */
+        InterpolationType type;
+
+        /**
+         * Constructor.
+         */
+        Point();
+
+        /**
+         * Destructor.
+         */
+        ~Point();
+    };
+
+    /**
+     * Constructor.
+     */
+    Curve();
+
+    /**
+     * Constructor.
+     */
+    Curve(const Curve& copy);
+
+    /**
+     * Bezier interpolation function.
+     */
+    void interpolateBezier(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Bspline interpolation function.
+     */
+    void interpolateBSpline(float s, Point* c0, Point* c1, Point* c2, Point* c3, float* dst) const;
+
+    /**
+     * Hermite interpolation function.
+     */
+    void interpolateHermite(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Hermite interpolation function.
+     */
+    void interpolateHermiteFlat(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Hermite interpolation function.
+     */
+    void interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const;
+
+    /** 
+     * Linear interpolation function.
+     */ 
+    void interpolateLinear(float s, Point* from, Point* to, float* dst) const;
+
+    /**
+     * Quaternion interpolation function.
+     */
+    void interpolateQuaternion(float s, float* from, float* to, float* dst) const;
+    
+    /**
+     * Determines the current keyframe to interpolate from based on the specified time.
+     */ 
+    int determineIndex(float time) const;
+
+    /**
+     * Sets the offset for the beginning of a Quaternion piece of data within the curve's value span at the specified
+     * index. The next four components of data starting at the given index will be interpolated as a Quaternion.
+     * This function will assert an error if the given index is greater than the component size subtracted by the four components required
+     * to store a quaternion.
+     * 
+     * @param index The index of the Quaternion rotation data.
+     */
+    void setQuaternionOffset(unsigned int index);
+
+    /**
+     * Gets the InterpolationType value for the given string ID
+     *
+     * @param interpolationId The string representation of the InterpolationType
+     * @return the InterpolationType value; -1 if the string does not represent an InterpolationType.
+     */
+    static int getInterpolationType(const char* interpolationId);
+
+    unsigned int _pointCount;           // Number of points on the curve.
+    unsigned int _componentCount;       // Number of components on the curve.
+    unsigned int _componentSize;        // The component size (in bytes).
+    unsigned int* _quaternionOffset;    // Offset for the rotation component.
+    Point* _points;                     // The points on the curve.
+};
+
+inline static float bezier(float eq0, float eq1, float eq2, float eq3, float from, float out, float to, float in);
+
+inline static float bspline(float eq0, float eq1, float eq2, float eq3, float c0, float c1, float c2, float c3);
+
+inline static float hermite(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
+
+inline static float hermiteFlat(float h00, float h01, float from, float to);
+
+inline static float hermiteSmooth(float h00, float h01, float h10, float h11, float from, float out, float to, float in);
+
+inline static float lerpInl(float s, float from, float to);
+
+}
+
+#include "Curve.inl"
+
+#endif

+ 36 - 0
gameplay-encoder/src/Curve.inl

@@ -0,0 +1,36 @@
+
+
+namespace gameplay
+{
+
+inline float bezier(float eq0, float eq1, float eq2, float eq3, float from, float out, float to, float in)
+{
+    return from * eq0 + out * eq1 + in * eq2 + to * eq3;
+}
+
+inline float bspline(float eq0, float eq1, float eq2, float eq3, float c0, float c1, float c2, float c3)
+{
+    return c0 * eq0 + c1 * eq1 + c2 * eq2 + c3 * eq3;
+}
+
+inline float hermite(float h00, float h01, float h10, float h11, float from, float out, float to, float in)
+{
+    return h00 * from + h01 * to + h10 * out + h11 * in;
+}
+
+inline float hermiteFlat(float h00, float h01, float from, float to)
+{
+    return h00 * from + h01 * to;
+}
+
+inline float hermiteSmooth(float h00, float h01, float h10, float h11, float from, float out, float to, float in)
+{
+    return h00 * from + h01 * to + h10 * out + h11 * in;
+}
+
+inline float lerpInl(float s, float from, float to)
+{
+    return from + (to - from) * s;
+}
+
+}

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

@@ -55,6 +55,7 @@ public:
     void getPropertyName(size_t index, std::string* str);
 
 private:
+    
     /**
      * The channel element.
      */

+ 72 - 38
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -627,6 +627,7 @@ bool DAESceneEncoder::loadTarget(const domChannelRef& channelRef, AnimationChann
                     Quaternion rotation;
                     Vector3 translation;
                     matrix.decompose(&scale, &rotation, &translation);
+                    rotation.normalize();
 
                     size_t k = i * 10;
                     floats[k+0] = scale.x;
@@ -1240,9 +1241,9 @@ void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeleton
     for (std::vector<std::string>::const_iterator i = jointNames.begin(); i != jointNames.end(); i++)
     {
         Object* obj = _gamePlayFile.getFromRefTable(*i);
-        if (obj)
+        if (obj && obj->getTypeId() == Object::NODE_ID)
         {
-            Node* node = (Node*)obj;
+            Node* node = static_cast<Node*>(obj);
             _joints.push_back(node);
         }
     }
@@ -1673,10 +1674,9 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             {
                 maxOffset = offset;
             }
-            int type = polygonInputs[k]->type;
-
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
-            switch (type)
+
+            switch (polygonInputs[k]->type)
             {
             case POSITION:
                 vertex = Vertex(); // TODO
@@ -1707,16 +1707,52 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 vertex.normal.z = (float)source.get(polyIndex * 3 + 2);
                 break;
 
-            // TODO: Handle reading of per-vertex colors.
-            // HOW do we know how many color components to read?
-            // We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
-//            case Color:
-//                vertex.hasColor = true;
-//                vertex.Diffuse.R = (float)source.get(polyIndex * 3);
-//                vertex.Diffuse.G = (float)source.get(polyIndex * 3 + 1);
-//                vertex.Diffuse.B = (float)source.get(polyIndex * 3 + 2);
-//                vertex.Diffuse.A = (float)source.get(polyIndex * 3 + 3);
-//                break;
+            // TODO: We must examine the Collada input accessor and read the stride/count to verify this - not ONLY for Color, but we should be doing this for ALL components (i.e. Position, Normal, etc).
+            case COLOR:
+            {
+                domAccessor* accessor = polygonInputs[k]->accessor;
+                if (accessor)
+                {
+                    vertex.hasDiffuse = true;
+                    vertex.diffuse.w = 1.0f;
+                    unsigned int stride = (unsigned int)polygonInputs[k]->accessor->getStride();
+                    unsigned int index = polyIndex * stride;
+
+                    const domParam_Array& paramArray = accessor->getParam_array();
+                    const size_t paramArrayCount = paramArray.getCount();
+
+                    for (size_t i = 0; i < paramArrayCount; ++i)
+                    {
+                        const domParamRef& param = paramArray.get(i);
+                        const char* name = param->getName();
+                        if (name)
+                        {
+                            switch (name[0])
+                            {
+                            case 'r':
+                            case 'R':
+                                vertex.diffuse.x = (float)source.get(index + i); // red
+                                break;
+                            case 'g':
+                            case 'G':
+                                vertex.diffuse.y = (float)source.get(index + i); // green
+                                break;
+                            case 'b':
+                            case 'B':
+                                vertex.diffuse.z = (float)source.get(index + i); // blue
+                                break;
+                            case 'a':
+                            case 'A':
+                                vertex.diffuse.w = (float)source.get(index + i); // alpha
+                                break;
+                            default:
+                                break;
+                            }
+                        }
+                    }
+                }
+                break;
+            }
 
             case TANGENT:
                 vertex.hasTangent = true;
@@ -1786,7 +1822,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     }
     
     bool hasNormals = mesh->vertices[0].hasNormal;
-    bool hasColors = mesh->vertices[0].hasColor;
+    bool hasDiffuses = mesh->vertices[0].hasDiffuse;
     bool hasTangents = mesh->vertices[0].hasTangent;
     bool hasBinormals = mesh->vertices[0].hasBinormal;
     bool hasTexCoords = mesh->vertices[0].hasTexCoord;
@@ -1796,38 +1832,38 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
     // It should be the same order as how the Vertex data is written.
 
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
     
     // Normals
     if (hasNormals)
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     // Tangents
     if (hasTangents)
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     // Binormals
     if (hasBinormals)
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     // Texture Coordinates
     if (hasTexCoords)
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     // Diffuse Color
-    if (hasColors)
+    if (hasDiffuses)
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     // Skinning BlendWeights BlendIndices
-    if (hasWeights /*_vertexBlendWeights && _vertexBlendIndices*/)
+    if (hasWeights)
     {
-        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
-        mesh->addVetexAttribute(BLENDINDICES, 4);
+        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
+        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
     }
 
     _gamePlayFile.addMesh(mesh);
@@ -1846,7 +1882,6 @@ void DAESceneEncoder::warning(const char* message)
 
 int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
 {
-    int type = -1;
     if (semantic.length() > 0)
     {
         switch (semantic[0])
@@ -1854,48 +1889,47 @@ int DAESceneEncoder::getVertexUsageType(const std::string& semantic)
         case 'P':
             if (equals(semantic, "POSITION"))
             {
-                type = POSITION;
+                return POSITION;
             }
-            break;
         case 'N':
             if (equals(semantic, "NORMAL"))
             {
-                type = NORMAL;
+                return NORMAL;
             }
         case 'C':
             if (equals(semantic, "COLOR"))
             {
-                type = COLOR;
+                return COLOR;
             }
         case 'T':
             if (equals(semantic, "TANGENT"))
             {
-                type = TANGENT;
+                return TANGENT;
             }
             else if (equals(semantic, "TEXCOORD"))
             {
-                type = TEXCOORD0;
+                return TEXCOORD0;
             }
             else if (equals(semantic, "TEXTANGENT"))
             {
                 // Treat TEXTANGENT as TANGENT
-                type = TANGENT;
+                return TANGENT;
             }
             else if (equals(semantic, "TEXBINORMAL"))
             {
                 // Treat TEXBINORMAL as BINORMAL
-                type = BINORMAL;
+                return BINORMAL;
             }
         case 'B':
             if (equals(semantic, "BINORMAL"))
             {
-                type = BINORMAL;
+                return BINORMAL;
             }
         default:
-            break;
+            return -1;
         }
     }
-    return type;
+    return -1;
 }
 
 DAESceneEncoder::DAEPolygonInput::DAEPolygonInput(void) :

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

@@ -185,11 +185,13 @@ private:
      * Returns the VertexUsage value for the given semantic string.
      * 
      * @param semantic The semantic attribute string from the COLLADA <input> element.
-     * @param The VertexUsage or -1 if the string was not recognized.
+     * 
+     * @return The VertexUsage or -1 if the string was not recognized.
      */
     static int getVertexUsageType(const std::string& semantic);
     
 private:
+    
     DAE* _collada;        // Collada datastore in memory to read from.
     domCOLLADA* _dom;
     FILE* file;        // Output file to write to.

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

@@ -29,6 +29,7 @@ public:
     virtual void writeText(FILE* file);
 
 private:
+    
     std::string _vertexShader;
     std::string _fragmentShader;
 };

+ 159 - 58
gameplay-encoder/src/FBXSceneEncoder.cpp

@@ -15,7 +15,7 @@ using namespace gameplay;
  * 
  * @return The aspect ratio from the camera.
  */
-float getAspectRatio(KFbxCamera* fbxCamera);
+static float getAspectRatio(KFbxCamera* fbxCamera);
 
 /**
  * Returns the field of view Y from the given camera.
@@ -24,7 +24,7 @@ float getAspectRatio(KFbxCamera* fbxCamera);
  * 
  * @return The field of view Y.
  */
-float getFieldOfView(KFbxCamera* fbxCamera);
+static float getFieldOfView(KFbxCamera* fbxCamera);
 
 /**
  * Loads the texture coordinates from given mesh's polygon part into the vertex.
@@ -34,7 +34,7 @@ float getFieldOfView(KFbxCamera* fbxCamera);
  * @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);
+static void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex* vertex);
 
 /**
  * Loads the normal from the mesh and adds it to the given vertex.
@@ -43,7 +43,7 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
  * @param vertexIndex The vertex index in the mesh.
  * @param vertex The vertex to copy to.
  */
-void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 /**
  * Loads the tangent from the mesh and adds it to the given vertex.
@@ -52,7 +52,7 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertex The vertex to copy to.
  */
-void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 /**
  * Loads the binormal from the mesh and adds it to the given vertex.
@@ -61,7 +61,16 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
  * @param vertexIndex The index of the vertex within fbxMesh.
  * @param vertex The vertex to copy to.
  */
-void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+static void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
+
+/**
+ * Loads the vertex diffuse color 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.
+ */
+static void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex);
 
 /**
  * Loads the blend weight and blend indices data into the vertex.
@@ -69,7 +78,7 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* 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);
+static void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
 
 /**
  * Loads the blend weights and blend indices from the given mesh.
@@ -81,17 +90,17 @@ void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex);
  * 
  * @return True if this mesh has a mesh skin, false otherwise.
  */
-bool loadBlendWeights(KFbxMesh* fbxMesh, std::vector<std::vector<Vector2> >& weights);
+static 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);
+static void copyMatrix(const KFbxMatrix& fbxMatrix, float* matrix);
 
 /**
  * Copies from an FBX matrix to a gameplay matrix.
  */
-void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
+static void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
 
 /**
  * Finds the min and max start time and stop time of the given animation curve.
@@ -105,7 +114,7 @@ void copyMatrix(const KFbxMatrix& fbxMatrix, Matrix& matrix);
  * @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);
+static void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime, float* frameRate);
 
 /**
  * Appends a key frame of the given node's transform at the given time.
@@ -115,7 +124,7 @@ void findMinMaxTime(KFbxAnimCurve* animCurve, float* startTime, float* stopTime,
  * @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);
+static 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.
@@ -126,7 +135,7 @@ void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes,
  * @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);
+static 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.
@@ -138,7 +147,7 @@ void decompose(KFbxNode* fbxNode, float time, Vector3* scale, Quaternion* rotati
  * 
  * @return The newly created animation channel.
  */
-AnimationChannel* createAnimationChannel(KFbxNode* fbxNode, unsigned int targetAttrib, const std::vector<float>& keyTimes, const std::vector<float>& keyValues);
+static 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);
 
@@ -240,7 +249,13 @@ void FBXSceneEncoder::loadScene(KFbxScene* fbxScene)
     // Find the ambient light of the scene
     KFbxColor ambientColor = fbxScene->GetGlobalSettings().GetAmbientColor();
     scene->setAmbientColor((float)ambientColor.mRed, (float)ambientColor.mGreen, (float)ambientColor.mBlue);
-
+    
+    // Assign the first camera node (if there is one) in the scene as the active camera
+    // This ensures that if there's a camera in the scene that it is assigned as the 
+    // active camera.
+    // TODO: add logic to find the "active" camera node in the fbxScene
+    scene->setActiveCameraNode(scene->getFirstCameraNode());
+    
     _gamePlayFile.addScene(scene);
 }
 
@@ -260,7 +275,7 @@ void FBXSceneEncoder::loadAnimationChannels(KFbxAnimLayer* animLayer, KFbxNode*
     // 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;
+    float startTime = FLT_MAX, stopTime = -1.0f, frameRate = -FLT_MAX;
     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);
@@ -637,20 +652,65 @@ void FBXSceneEncoder::loadLight(KFbxNode* fbxNode, Node* node)
     switch (fbxLight->LightType.Get())
     {
     case KFbxLight::ePOINT:
-        light->setPointLight();
-        // TODO: range
+    {
+        KFbxLight::EDecayType decayType = fbxLight->DecayType.Get();
+        switch (decayType)
+        {
+        case KFbxLight::eNONE:
+            // No decay. Can assume we have an ambient light, because ambient lights in the scene are 
+            // converted to point lights with no decay when exporting to FBX.
+            light->setAmbientLight();
+            break;
+        case KFbxLight::eLINEAR:
+            light->setPointLight();
+            light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
+            break;
+        case KFbxLight::eQUADRATIC:
+            light->setPointLight();
+            light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
+            break;
+        case KFbxLight::eCUBIC:
+        default:
+            // Not supported..
+            break;
+        }
         break;
+    }
     case KFbxLight::eDIRECTIONAL:
+    {
         light->setDirectionalLight();
         break;
+    }
     case KFbxLight::eSPOT:
+    {
         light->setSpotLight();
-        // TODO: range and angles
+
+        KFbxLight::EDecayType decayType = fbxLight->DecayType.Get();
+        switch (decayType)
+        {
+        case KFbxLight::eNONE:
+            // No decay.
+            break;
+        case KFbxLight::eLINEAR:
+            light->setLinearAttenuation((float)fbxLight->DecayStart.Get());
+            break;  
+        case KFbxLight::eQUADRATIC:
+            light->setQuadraticAttenuation((float)fbxLight->DecayStart.Get());
+            break;
+        case KFbxLight::eCUBIC:
+            // Not supported..
+            break;
+        }
+
+        light->setFalloffAngle(MATH_DEG_TO_RAD((float)fbxLight->ConeAngle.Get())); // fall off angle
         break;
+    }
     default:
+    {
         warning("Unknown light type in node.");
         return;
     }
+    }
 
     _gamePlayFile.addLight(light);
     node->setLight(light);
@@ -778,7 +838,7 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
             loadNormal(fbxMesh, vertexIndex, &vertex);
             loadTangent(fbxMesh, vertexIndex, &vertex);
             loadBinormal(fbxMesh, vertexIndex, &vertex);
-            // TODO: loadDiffuseColors
+            loadVertexColor(fbxMesh, vertexIndex, &vertex);
 
             if (hasSkin)
             {
@@ -819,39 +879,39 @@ Mesh* FBXSceneEncoder::loadMesh(KFbxMesh* fbxMesh)
     // It should be the same order as how the Vertex data is written.
 
     // Position
-    mesh->addVetexAttribute(POSITION, 3);
+    mesh->addVetexAttribute(POSITION, Vertex::POSITION_COUNT);
 
     const Vertex& vertex = mesh->vertices[0];
     // Normals
     if (vertex.hasNormal)
     {
-        mesh->addVetexAttribute(NORMAL, 3);
+        mesh->addVetexAttribute(NORMAL, Vertex::NORMAL_COUNT);
     }
     // Tangents
     if (vertex.hasTangent)
     {
-        mesh->addVetexAttribute(TANGENT, 3);
+        mesh->addVetexAttribute(TANGENT, Vertex::TANGENT_COUNT);
     }
     // Binormals
     if (vertex.hasBinormal)
     {
-        mesh->addVetexAttribute(BINORMAL, 3);
+        mesh->addVetexAttribute(BINORMAL, Vertex::BINORMAL_COUNT);
     }
     // Texture Coordinates
     if (vertex.hasTexCoord)
     {
-        mesh->addVetexAttribute(TEXCOORD0, 2);
+        mesh->addVetexAttribute(TEXCOORD0, Vertex::TEXCOORD_COUNT);
     }
     // Diffuse Color
-    if (vertex.hasColor)
+    if (vertex.hasDiffuse)
     {
-        mesh->addVetexAttribute(COLOR, 3);
+        mesh->addVetexAttribute(COLOR, Vertex::DIFFUSE_COUNT);
     }
     // Skinning BlendWeights BlendIndices
     if (vertex.hasWeights)
     {
-        mesh->addVetexAttribute(BLENDWEIGHTS, 4);
-        mesh->addVetexAttribute(BLENDINDICES, 4);
+        mesh->addVetexAttribute(BLENDWEIGHTS, Vertex::BLEND_WEIGHTS_COUNT);
+        mesh->addVetexAttribute(BLENDINDICES, Vertex::BLEND_INDICES_COUNT);
     }
 
     _gamePlayFile.addMesh(mesh);
@@ -974,23 +1034,23 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
     if (fbxMesh->GetElementUVCount() > 0)
     {
         // Get only the first UV coordinates.
-        KFbxGeometryElementUV* leUV = fbxMesh->GetElementUV(0);
-        switch (leUV->GetMappingMode())
+        KFbxGeometryElementUV* uv = fbxMesh->GetElementUV(0);
+        switch (uv->GetMappingMode())
         {
         case KFbxGeometryElement::eBY_CONTROL_POINT:
-            switch (leUV->GetReferenceMode())
+            switch (uv->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];
+                vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(polyIndex)[0];
+                vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(polyIndex)[1];
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leUV->GetIndexArray().GetAt(polyIndex);
+                    int id = uv->GetIndexArray().GetAt(polyIndex);
                     vertex->hasTexCoord = true;
-                    vertex->texCoord.x = (float)leUV->GetDirectArray().GetAt(id)[0];
-                    vertex->texCoord.y = (float)leUV->GetDirectArray().GetAt(id)[1];
+                    vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(id)[0];
+                    vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(id)[1];
                 }
                 break;
             default:
@@ -1000,13 +1060,13 @@ void loadTextureCoords(KFbxMesh* fbxMesh, int polyIndex, int posInPoly, Vertex*
         case KFbxGeometryElement::eBY_POLYGON_VERTEX:
             {
                 int lTextureUVIndex = fbxMesh->GetTextureUVIndex(polyIndex, posInPoly);
-                switch (leUV->GetReferenceMode())
+                switch (uv->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];
+                    vertex->texCoord.x = (float)uv->GetDirectArray().GetAt(lTextureUVIndex)[0];
+                    vertex->texCoord.y = (float)uv->GetDirectArray().GetAt(lTextureUVIndex)[1];
                     break;
                 default:
                     break;
@@ -1024,14 +1084,14 @@ 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)
+        KFbxGeometryElementNormal* normal = fbxMesh->GetElementNormal(0);
+        if (normal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
-            switch (leNormal->GetReferenceMode())
+            switch (normal->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 {
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
@@ -1040,8 +1100,8 @@ void loadNormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leNormal->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leNormal->GetDirectArray().GetAt(id);
+                    int id = normal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
                     vertex->hasNormal = true;
                     vertex->normal.x = (float)vec4[0];
                     vertex->normal.y = (float)vec4[1];
@@ -1060,14 +1120,14 @@ 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)
+        KFbxGeometryElementTangent* tangent = fbxMesh->GetElementTangent(0);
+        if (tangent->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
-            switch (leTangent->GetReferenceMode())
+            switch (tangent->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 {
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
@@ -1076,8 +1136,8 @@ void loadTangent(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leTangent->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leTangent->GetDirectArray().GetAt(id);
+                    int id = tangent->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = tangent->GetDirectArray().GetAt(id);
                     vertex->hasTangent = true;
                     vertex->tangent.x = (float)vec4[0];
                     vertex->tangent.y = (float)vec4[1];
@@ -1096,14 +1156,14 @@ 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)
+        KFbxGeometryElementBinormal* binormal = fbxMesh->GetElementBinormal(0);
+        if (binormal->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
         {
-            switch (leBinormal->GetReferenceMode())
+            switch (binormal->GetReferenceMode())
             {
             case KFbxGeometryElement::eDIRECT:
                 {
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(vertexIndex);
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
@@ -1112,8 +1172,8 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
                 break;
             case KFbxGeometryElement::eINDEX_TO_DIRECT:
                 {
-                    int id = leBinormal->GetIndexArray().GetAt(vertexIndex);
-                    KFbxVector4 vec4 = leBinormal->GetDirectArray().GetAt(id);
+                    int id = binormal->GetIndexArray().GetAt(vertexIndex);
+                    KFbxVector4 vec4 = binormal->GetDirectArray().GetAt(id);
                     vertex->hasBinormal = true;
                     vertex->binormal.x = (float)vec4[0];
                     vertex->binormal.y = (float)vec4[1];
@@ -1127,6 +1187,46 @@ void loadBinormal(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
     }
 }
 
+void loadVertexColor(KFbxMesh* fbxMesh, int vertexIndex, Vertex* vertex)
+{
+    if (fbxMesh->GetElementVertexColorCount() > 0)
+    {
+        // Get only the first vertex color.
+        KFbxGeometryElementVertexColor* vertexColor = fbxMesh->GetElementVertexColor(0);
+        if (vertexColor->GetMappingMode() == KFbxGeometryElement::eBY_POLYGON_VERTEX)
+        {
+            switch (vertexColor->GetReferenceMode())
+            {
+            case KFbxGeometryElement::eDIRECT:
+                {
+                    KFbxColor color = vertexColor->GetDirectArray().GetAt(vertexIndex);
+
+                    vertex->hasDiffuse = true;
+                    vertex->diffuse.x = (float)color.mRed;
+                    vertex->diffuse.y = (float)color.mGreen;
+                    vertex->diffuse.z = (float)color.mBlue;
+                    vertex->diffuse.w = (float)color.mAlpha;
+                }
+                break;
+            case KFbxGeometryElement::eINDEX_TO_DIRECT:
+                {
+                    int id = vertexColor->GetIndexArray().GetAt(vertexIndex);
+                    KFbxColor color = vertexColor->GetDirectArray().GetAt(id);
+
+                    vertex->hasDiffuse = true;
+                    vertex->diffuse.x = (float)color.mRed;
+                    vertex->diffuse.y = (float)color.mGreen;
+                    vertex->diffuse.z = (float)color.mBlue;
+                    vertex->diffuse.w = (float)color.mAlpha;
+                }
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
 void loadBlendData(const std::vector<Vector2>& vertexWeights, Vertex* vertex)
 {
     size_t size = vertexWeights.size();
@@ -1225,6 +1325,7 @@ void appendKeyFrame(KFbxNode* fbxNode, float time, std::vector<float>* keyTimes,
     Quaternion rotation;
     Vector3 translation;
     matrix.decompose(&scale, &rotation, &translation);
+    rotation.normalize();
 
     keyTimes->push_back(time);
     keyValues->push_back(scale.x);

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

@@ -1,6 +1,9 @@
 #ifndef FILEIO_H_
 #define FILEIO_H_
 
+#include <cstdio>
+#include <list>
+#include <vector>
 
 #include "Vector2.h"
 #include "Vector3.h"

+ 144 - 0
gameplay-encoder/src/GPBFile.cpp

@@ -1,11 +1,19 @@
 #include "Base.h"
 #include "GPBFile.h"
+#include "Transform.h"
+
+#define EPSILON 1.2e-7f;
 
 namespace gameplay
 {
 
 static GPBFile* __instance = NULL;
 
+/**
+ * Returns true if the given value is close to one.
+ */
+static bool isAlmostOne(float value);
+
 GPBFile::GPBFile(void)
     : _file(NULL), _animationsAdded(false)
 {
@@ -245,6 +253,14 @@ void GPBFile::adjust()
         }
     }
 
+    for (std::list<Node*>::const_iterator i = _nodes.begin(); i != _nodes.end(); ++i)
+    {
+        computeBounds(*i);
+    }
+
+    // try to convert joint transform animations into rotation animations
+    //optimizeTransformAnimations();
+
     // TODO:
     // remove ambient _lights
     // for each node
@@ -259,4 +275,132 @@ void GPBFile::adjust()
     //   This can be merged into one animation. Same for scale animations.
 }
 
+void GPBFile::computeBounds(Node* node)
+{
+    assert(node);
+    if (Model* model = node->getModel())
+    {
+        if (Mesh* mesh = model->getMesh())
+        {
+            mesh->computeBounds();
+        }
+        if (MeshSkin* skin = model->getSkin())
+        {
+            skin->computeBounds();
+        }
+    }
+    for (Node* child = node->getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        computeBounds(child);
+    }
+}
+
+void GPBFile::optimizeTransformAnimations()
+{
+    const unsigned int animationCount = _animations.getAnimationCount();
+    for (unsigned int animationIndex = 0; animationIndex < animationCount; ++animationIndex)
+    {
+        Animation* animation = _animations.getAnimation(animationIndex);
+        assert(animation);
+        const int channelCount = animation->getAnimationChannelCount();
+        // loop backwards because we will be adding and removing channels
+        for (int channelIndex = channelCount -1; channelIndex >= 0 ; --channelIndex)
+        {
+            AnimationChannel* channel = animation->getAnimationChannel(channelIndex);
+            assert(channel);
+            // get target node
+            const Object* obj = _refTable.get(channel->getTargetId());
+            if (obj && obj->getTypeId() == Object::NODE_ID)
+            {
+                const Node* node = static_cast<const Node*>(obj);
+                if (node->isJoint() && channel->getTargetAttribute() == Transform::ANIMATE_SCALE_ROTATE_TRANSLATE)
+                {
+                    decomposeTransformAnimationChannel(animation, channel);
+
+                    animation->remove(channel);
+                    SAFE_DELETE(channel);
+                }
+            }
+        }
+    }
+}
+
+
+void GPBFile::decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel)
+{
+    const std::vector<float>& keyTimes = channel->getKeyTimes();
+    const std::vector<float>& keyValues = channel->getKeyValues();
+    const size_t keyTimesSize = keyTimes.size();
+    const size_t keyValuesSize = keyValues.size();
+
+    std::vector<float> scaleKeyValues;
+    std::vector<float> rotateKeyValues;
+    std::vector<float> translateKeyValues;
+                    
+    scaleKeyValues.reserve(keyTimesSize * 3);
+    rotateKeyValues.reserve(keyTimesSize * 4);
+    translateKeyValues.reserve(keyTimesSize * 3);
+
+    for (size_t kv = 0; kv < keyValuesSize; kv += 10)
+    {
+        scaleKeyValues.push_back(keyValues[kv]);
+        scaleKeyValues.push_back(keyValues[kv+1]);
+        scaleKeyValues.push_back(keyValues[kv+2]);
+
+        rotateKeyValues.push_back(keyValues[kv+3]);
+        rotateKeyValues.push_back(keyValues[kv+4]);
+        rotateKeyValues.push_back(keyValues[kv+5]);
+        rotateKeyValues.push_back(keyValues[kv+6]);
+
+        translateKeyValues.push_back(keyValues[kv+7]);
+        translateKeyValues.push_back(keyValues[kv+8]);
+        translateKeyValues.push_back(keyValues[kv+9]);
+    }
+
+    // replace transform animation channel with translate, rotate and scale animation channels
+
+    // Don't add the scale channel if all the key values are close to 1.0
+    size_t oneCount = (size_t)std::count_if(scaleKeyValues.begin(), scaleKeyValues.end(), isAlmostOne);
+    if (scaleKeyValues.size() != oneCount)
+    {
+        AnimationChannel* scaleChannel = new AnimationChannel();
+        scaleChannel->setTargetId(channel->getTargetId());
+        scaleChannel->setKeyTimes(channel->getKeyTimes());
+        scaleChannel->setTangentsIn(channel->getTangentsIn());
+        scaleChannel->setTangentsOut(channel->getTangentsOut());
+        scaleChannel->setInterpolations(channel->getInterpolationTypes());
+        scaleChannel->setTargetAttribute(Transform::ANIMATE_SCALE);
+        scaleChannel->setKeyValues(scaleKeyValues);
+        scaleChannel->removeDuplicates();
+        animation->add(scaleChannel);
+    }
+
+    AnimationChannel* rotateChannel = new AnimationChannel();
+    rotateChannel->setTargetId(channel->getTargetId());
+    rotateChannel->setKeyTimes(channel->getKeyTimes());
+    rotateChannel->setTangentsIn(channel->getTangentsIn());
+    rotateChannel->setTangentsOut(channel->getTangentsOut());
+    rotateChannel->setInterpolations(channel->getInterpolationTypes());
+    rotateChannel->setTargetAttribute(Transform::ANIMATE_ROTATE);
+    rotateChannel->setKeyValues(rotateKeyValues);
+    rotateChannel->removeDuplicates();
+    animation->add(rotateChannel);
+
+    AnimationChannel* translateChannel = new AnimationChannel();
+    translateChannel->setTargetId(channel->getTargetId());
+    translateChannel->setKeyTimes(channel->getKeyTimes());
+    translateChannel->setTangentsIn(channel->getTangentsIn());
+    translateChannel->setTangentsOut(channel->getTangentsOut());
+    translateChannel->setInterpolations(channel->getInterpolationTypes());
+    translateChannel->setTargetAttribute(Transform::ANIMATE_TRANSLATE);
+    translateChannel->setKeyValues(translateKeyValues);
+    translateChannel->removeDuplicates();
+    animation->add(translateChannel);
+}
+
+static bool isAlmostOne(float value)
+{
+    return std::abs(value - 1.0f) < EPSILON;
+}
+
 }

+ 15 - 0
gameplay-encoder/src/GPBFile.h

@@ -98,6 +98,21 @@ public:
      */
     void adjust();
 
+private:
+    /**
+     * Computes the bounds of all meshes in the node hierarchy.
+     */
+    void computeBounds(Node* node);
+    void optimizeTransformAnimations();
+
+    /**
+     * Decomposes an ANIMATE_SCALE_ROTATE_TRANSLATE channel into 3 new channels. (Scale, Rotate and Translate)
+     * 
+     * @param animation The animation that the channel belongs to.
+     * @param channel The animation channel to decompose.
+     */
+    void decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel);
+
 private:
 
     FILE* _file;

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

@@ -156,7 +156,7 @@ void Mesh::generateHeightmap(const char* filename)
     float* heights = new float[width * height];
     int index = 0;
     float minHeight = FLT_MAX;
-    float maxHeight = FLT_MIN;
+    float maxHeight = -FLT_MAX;
     for (int z = minZ; z <= maxZ; z++)
     {
         rayOrigin.z = (float)z;
@@ -273,7 +273,6 @@ void Mesh::writeBinaryVertices(FILE* file)
     }
 
     // Write bounds
-    computeBounds();
     write(&bounds.min.x, 3, file);
     write(&bounds.max.x, 3, file);
     write(&bounds.center.x, 3, file);
@@ -302,7 +301,6 @@ void Mesh::writeText(FILE* file)
     fprintf(file, "</vertices>\n");
 
     // write bounds
-    computeBounds();
     fprintf(file, "<bounds>\n");
     fprintf(file, "<min>\n");
     writeVectorText(bounds.min, file);
@@ -392,7 +390,7 @@ void Mesh::computeBounds()
     }
 
     bounds.min.x = bounds.min.y = bounds.min.z = FLT_MAX;
-    bounds.max.x = bounds.max.y = bounds.max.z = FLT_MIN;
+    bounds.max.x = bounds.max.y = bounds.max.z = -FLT_MAX;
     bounds.center.x = bounds.center.y = bounds.center.z = 0.0f;
     bounds.radius = 0.0f;
 

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

@@ -65,16 +65,14 @@ public:
      */
     void generateHeightmap(const char* filename);
 
+    void computeBounds();
+
     Model* model;
     std::vector<Vertex> vertices;
     std::vector<MeshPart*> parts;
     BoundingVolume bounds;
     std::map<Vertex, unsigned int> vertexLookupTable;
 
-private:
-
-    void computeBounds();
-
 private:
     std::vector<VertexElement> _vertexFormat;
 

+ 17 - 15
gameplay-encoder/src/MeshSkin.cpp

@@ -6,7 +6,7 @@
 #include "GPBFile.h"
 #include "Animations.h"
 #include "Transform.h"
-#include "../../gameplay/src/Curve.h"
+#include "Curve.h"
 #include "Matrix.h"
 
 namespace gameplay
@@ -225,7 +225,7 @@ void MeshSkin::computeBounds()
         vertices.clear();
         BoundingVolume jointBounds;
         jointBounds.min.set(FLT_MAX, FLT_MAX, FLT_MAX);
-        jointBounds.max.set(FLT_MIN, FLT_MIN, FLT_MIN);
+        jointBounds.max.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
         for (unsigned int j = 0; j < vertexCount; ++j)
         {
             const Vertex& v = _mesh->getVertex(j);
@@ -313,26 +313,28 @@ void MeshSkin::computeBounds()
         if (duration > maxDuration)
             maxDuration = duration;
 
-        // Set curve points
-        float* keyValuesPtr = keyValues;
-        for (unsigned int j = 0; j < keyCount; ++j)
+        if (duration > 0.0f)
         {
-            // Store time normalized, between 0-1
-            float t = (keyTimes[j] - startTime) / duration;
+            // Set curve points
+            float* keyValuesPtr = keyValues;
+            for (unsigned int j = 0; j < keyCount; ++j)
+            {
+                // Store time normalized, between 0-1
+                float t = (keyTimes[j] - startTime) / duration;
 
-            // Set the curve point
-            // TODO: Handle other interpolation types
-            curve->setPoint(j, t, keyValuesPtr, gameplay::Curve::LINEAR);
+                // Set the curve point
+                // TODO: Handle other interpolation types
+                curve->setPoint(j, t, keyValuesPtr, gameplay::Curve::LINEAR);
 
-            // Move to the next point on the curve
-            keyValuesPtr += curve->getComponentCount();
+                // Move to the next point on the curve
+                keyValuesPtr += curve->getComponentCount();
+            }
+            curves.push_back(curve);
         }
 
         delete[] keyValues;
         keyValues = NULL;
 
-        curves.push_back(curve);
-
         DEBUGPRINT_VARG("> %d%%\r", (int)((float)(i+1) / (float)channelCount * 100.0f));
     }
     DEBUGPRINT("\n");
@@ -354,7 +356,7 @@ void MeshSkin::computeBounds()
     Matrix temp;
     Matrix* jointTransforms = new Matrix[jointCount];
     _mesh->bounds.min.set(FLT_MAX, FLT_MAX, FLT_MAX);
-    _mesh->bounds.max.set(FLT_MIN, FLT_MIN, FLT_MIN);
+    _mesh->bounds.max.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
     _mesh->bounds.center.set(0, 0, 0);
     _mesh->bounds.radius = 0;
     Vector3 skinnedPos;

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

@@ -296,7 +296,7 @@ void Node::setIsJoint(bool value)
     _joint = value;
 }
 
-bool Node::isJoint()
+bool Node::isJoint() const
 {
     return _joint;
 }
@@ -324,7 +324,7 @@ Node* Node::getFirstCameraNode() const
 {
     if (hasCamera())
     {
-        return (Node*)this;
+        return const_cast<Node*>(this);
     }
     for (Node* node = getFirstChild(); node != NULL; node = node->getNextSibling())
     {

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

@@ -155,7 +155,7 @@ public:
     /**
      * Returns true if this is a joint node.
      */
-    bool isJoint();
+    bool isJoint() const;
 
     Node* getFirstCameraNode() const;
 

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

@@ -1,5 +1,5 @@
-#ifndef REF_H_
-#define REF_H_
+#ifndef REFERENCE_H_
+#define REFERENCE_H_
 
 #include "Object.h"
 

+ 89 - 0
gameplay-encoder/src/Transform.cpp

@@ -1,2 +1,91 @@
 #include "Base.h"
 #include "Transform.h"
+
+namespace gameplay
+{
+
+const char* Transform::getPropertyString(unsigned int prop)
+{
+    switch (prop)
+    {
+        case ANIMATE_SCALE:
+            return "ANIMATE_SCALE";
+        case ANIMATE_SCALE_X:
+            return "ANIMATE_SCALE_X";
+        case ANIMATE_SCALE_Y: 
+            return "ANIMATE_SCALE_Y";
+        case ANIMATE_SCALE_Z:
+            return "ANIMATE_SCALE_Z";
+        case ANIMATE_SCALE_XY: 
+            return "ANIMATE_SCALE_XY";
+        case ANIMATE_SCALE_XZ: 
+            return "ANIMATE_SCALE_XZ";
+        case ANIMATE_SCALE_YZ:
+            return "ANIMATE_SCALE_YZ";
+        case ANIMATE_ROTATE:
+            return "ANIMATE_ROTATE";
+        case ANIMATE_TRANSLATE: 
+            return "ANIMATE_TRANSLATE";
+        case ANIMATE_TRANSLATE_X:
+            return "ANIMATE_TRANSLATE_X";
+        case ANIMATE_TRANSLATE_Y: 
+            return "ANIMATE_TRANSLATE_Y";
+        case ANIMATE_TRANSLATE_Z: 
+            return "ANIMATE_TRANSLATE_Z";
+        case ANIMATE_TRANSLATE_XY: 
+            return "ANIMATE_TRANSLATE_XY";
+        case ANIMATE_TRANSLATE_XZ: 
+            return "ANIMATE_TRANSLATE_XZ";
+        case ANIMATE_TRANSLATE_YZ: 
+            return "ANIMATE_TRANSLATE_YZ";
+        case ANIMATE_ROTATE_TRANSLATE: 
+            return "ANIMATE_ROTATE_TRANSLATE";
+        case ANIMATE_SCALE_ROTATE_TRANSLATE: 
+            return "ANIMATE_SCALE_ROTATE_TRANSLATE";
+        case ANIMATE_ROTATE_X: 
+            return "ANIMATE_ROTATE_X";
+        case ANIMATE_ROTATE_Y: 
+            return "ANIMATE_ROTATE_Y";
+        case ANIMATE_ROTATE_Z: 
+            return "ANIMATE_ROTATE_Z";
+        default:
+            return "";
+    }
+}
+
+unsigned int Transform::getPropertySize(unsigned int prop)
+{
+    switch (prop)
+    {
+        case ANIMATE_SCALE_ROTATE_TRANSLATE: 
+            return 10;
+        case ANIMATE_ROTATE_TRANSLATE: 
+            return 7;
+        case ANIMATE_ROTATE:
+            return 4;
+        case ANIMATE_SCALE:
+        case ANIMATE_TRANSLATE: 
+            return 3;   
+        case ANIMATE_SCALE_XY: 
+        case ANIMATE_SCALE_XZ: 
+        case ANIMATE_SCALE_YZ:
+        case ANIMATE_TRANSLATE_XY: 
+        case ANIMATE_TRANSLATE_XZ: 
+        case ANIMATE_TRANSLATE_YZ: 
+            return 2;
+        case ANIMATE_SCALE_X:
+        case ANIMATE_SCALE_Y:
+        case ANIMATE_SCALE_Z:
+        case ANIMATE_TRANSLATE_X:
+        case ANIMATE_TRANSLATE_Y:
+        case ANIMATE_TRANSLATE_Z:
+        case ANIMATE_ROTATE_X: 
+        case ANIMATE_ROTATE_Y: 
+        case ANIMATE_ROTATE_Z: 
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+}

+ 11 - 0
gameplay-encoder/src/Transform.h

@@ -50,6 +50,17 @@ public:
         ANIMATE_ROTATE_Y = 19,
         ANIMATE_ROTATE_Z = 20
     };
+
+    /**
+     * Returns the string representation of the given TransformProperty.
+     */
+    static const char* getPropertyString(unsigned int prop);
+
+    /**
+     * Returns the number of floats for the given property or zero if not a valid property.
+     */
+    static unsigned int getPropertySize(unsigned int prop);
+
 };
 
 }

+ 18 - 12
gameplay-encoder/src/Vertex.cpp

@@ -5,7 +5,7 @@ namespace gameplay
 {
 
 Vertex::Vertex(void)
-    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasColor(false), hasWeights(false)
+    : hasNormal(false), hasTangent(false), hasBinormal(false), hasTexCoord(false), hasDiffuse(false), hasWeights(false)
 {
 }
 
@@ -15,17 +15,19 @@ Vertex::~Vertex(void)
 
 unsigned int Vertex::byteSize() const
 {
-    unsigned int count = 3;
+    unsigned int count = POSITION_COUNT;
     if (hasNormal)
-        count += 3;
+        count += NORMAL_COUNT;
     if (hasTangent)
-        count += 3;
+        count += TANGENT_COUNT;
     if (hasBinormal)
-        count += 3;
+        count += BINORMAL_COUNT;
     if (hasTexCoord)
-        count += 2;
+        count += TEXCOORD_COUNT;
     if (hasWeights)
-        count += 8;
+        count += BLEND_WEIGHTS_COUNT + BLEND_INDICES_COUNT;
+    if (hasDiffuse)
+        count += DIFFUSE_COUNT;
     return count * sizeof(float);
 }
 
@@ -48,11 +50,10 @@ void Vertex::writeBinary(FILE* file) const
     {
         writeVectorBinary(texCoord, file);
     }
-    // TODO add vertex color?
-    //if (hasColor)
-    //{
-    //    writeVectorBinary(color, file);
-    //}
+    if (hasDiffuse)
+    {
+        writeVectorBinary(diffuse, file);
+    }
     if (hasWeights)
     {
         writeVectorBinary(blendWeights, file);
@@ -84,6 +85,11 @@ void Vertex::writeText(FILE* file) const
         write("// texCoord\n", file);
         writeVectorText(texCoord, file);
     }
+    if (hasDiffuse)
+    {
+        write("// diffuse\n", file);
+        writeVectorText(diffuse, file);
+    }
     if (hasWeights)
     {
         write("// blendWeights\n", file);

+ 21 - 7
gameplay-encoder/src/Vertex.h

@@ -13,6 +13,15 @@ class Vertex
 {
 public:
 
+    static const unsigned int POSITION_COUNT = 3;
+    static const unsigned int NORMAL_COUNT = 3;
+    static const unsigned int TANGENT_COUNT = 3;
+    static const unsigned int BINORMAL_COUNT = 3;
+    static const unsigned int TEXCOORD_COUNT = 2;
+    static const unsigned int DIFFUSE_COUNT = 4;
+    static const unsigned int BLEND_WEIGHTS_COUNT = 4;
+    static const unsigned int BLEND_INDICES_COUNT = 4;
+
     /**
      * Constructor.
      */
@@ -28,11 +37,12 @@ public:
     Vector3 tangent;
     Vector3 binormal;
     Vector2 texCoord;
+    Vector4 diffuse;
 
     Vector4 blendWeights;
     Vector4 blendIndices;
 
-    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasColor, hasWeights;
+    bool hasNormal, hasTangent, hasBinormal, hasTexCoord, hasDiffuse, hasWeights;
 
     inline bool operator<(const Vertex& v) const
     {
@@ -46,15 +56,19 @@ public:
                     {
                         if (texCoord == v.texCoord)
                         {
-                            if (blendWeights == v.blendWeights)
+                            if (diffuse == v.diffuse)
                             {
-                                if (blendIndices == v.blendIndices)
+                                if (blendWeights == v.blendWeights)
                                 {
-                                    return false;
+                                    if (blendIndices == v.blendIndices)
+                                    {
+                                        return false;
+                                    }
+                                    return blendIndices < v.blendIndices;
                                 }
-                                return blendIndices < v.blendIndices;
+                                return blendWeights < v.blendWeights;
                             }
-                            return blendWeights < v.blendWeights;
+                            return diffuse < v.diffuse;
                         }
                         return texCoord < v.texCoord;
                     }
@@ -70,7 +84,7 @@ public:
     inline bool operator==(const Vertex& v) const
     {
         return position==v.position && normal==v.normal && tangent==v.tangent && binormal==v.binormal && texCoord==v.texCoord &&
-            blendWeights==v.blendWeights && blendIndices==v.blendIndices;
+            diffuse==v.diffuse && blendWeights==v.blendWeights && blendIndices==v.blendIndices;
     }
 
     /**

+ 34 - 3
gameplay-newproject.bat

@@ -177,9 +177,9 @@ call:replace %projPath%\%projName%.xcodeproj\project.pbxproj GAMEPLAY_PATH "%gpP
 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%"
+copy gameplay-template\gameplay-template-macosx.plist %projPath%\%projName%-macosx.plist
+call:replace %projPath%\%projName%-macosx.plist TEMPLATE_UUID "%uuid%"
+call:replace %projPath%\%projName%-macosx.plist TEMPLATE_AUTHOR "%author%"
 
 REM Copy BlackBerry NDK project files
 copy gameplay-template\template.cproject %projPath%\.cproject
@@ -197,6 +197,37 @@ 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 Android NDK project files
+mkdir %projPath%\android
+
+copy gameplay-template\android\template.AndroidManifest.xml %projPath%\android\AndroidManifest.xml
+call:replace %projPath%\android\AndroidManifest.xml TEMPLATE_PROJECT "%projName%"
+call:replace %projPath%\android\AndroidManifest.xml TEMPLATE_UUID "%uuid%"
+
+copy gameplay-template\android\template.build.xml %projPath%\android\build.xml
+call:replace %projPath%\android\build.xml TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\android\template.project %projPath%\android\.project
+call:replace %projPath%\android\.project TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\android\template.classpath %projPath%\android\.classpath
+
+mkdir %projPath%\android\jni
+
+copy gameplay-template\android\jni\Application.mk %projPath%\android\jni\Application.mk
+
+copy gameplay-template\android\jni\template.Android.mk %projPath%\android\jni\Android.mk
+call:replace %projPath%\android\jni\Android.mk TemplateGame "%className%"
+call:replace %projPath%\android\jni\Android.mk TEMPLATE_PROJECT "%projName%"
+
+copy gameplay-template\android\jni\main.cpp %projPath%\android\jni\main.cpp
+
+mkdir %projPath%\android\res\values
+
+copy gameplay-template\android\res\values\template.strings.xml %projPath%\android\res\values\strings.xml
+call:replace %projPath%\android\res\values\strings.xml TEMPLATE_TITLE "%title%"
+
+
 REM Copy source files
 copy gameplay-template\src\TemplateGame.h %projPath%\src\%className%.h
 copy gameplay-template\src\TemplateGame.cpp %projPath%\src\%className%.cpp

+ 256 - 0
gameplay-newproject.sh

@@ -0,0 +1,256 @@
+#/bin/bash
+# ********************************************************************
+#
+# generate-project.sh
+#
+# This script generates a set of gameplay project files.
+# The new project will be based of the gameplay-template project and 
+# it will be generated with the name and location that is specified
+# as input parameters.
+#
+# IMPORTANT: This script must be run from the root of the gameplay
+# source tree.
+#
+# ********************************************************************
+
+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
+read -p "Project Name: " projName 
+if [[ "$projName" == "" ]]; then
+	echo
+	echo "ERROR: No project name specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Title: " title 
+if [[ "$title" == "" ]]; then
+	echo
+	echo "ERROR: No game title specified."
+	echo
+	exit -1;
+fi
+echo 
+
+echo
+echo "3. Enter a short game description."
+echo
+read -p "Description: " desc
+if [[ "$desc" == "" ]]; then
+	desc=$title
+fi
+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
+read -p "Unique ID: " uuid
+if [[ "$uuid" == "" ]]; then
+	echo
+	echo "ERROR: No uuid specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Author: " author
+if [[ "$author" == "" ]]; then
+	echo
+	echo "ERROR: No author specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Class name: " className
+if [[ "$className" == "" ]]; then
+	echo
+	echo "ERROR: No class name specified."
+	echo
+	exit -1;
+fi
+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
+read -p "Path: " location
+if [[ "$location" == "" ]]; then
+	projPath=$projName
+else
+	projPath="$location/$projName"
+fi
+echo
+
+# Verify Path and eliminate double '//'
+projPath=`echo "$projPath" | sed 's_//_/_g'`
+if [ -e $projPath ]; then
+	echo
+	echo "ERROR: Path '$projPath' already exists, aborting."
+	echo
+	exit -2
+fi
+
+# Make required source folder directories
+mkdir -p "$projPath"
+mkdir -p "$projPath/src"
+mkdir -p "$projPath/res"
+
+if [[ ${projPath:0:1} != "/" ]]; then
+	currPwd=`pwd`
+	projPath=`cd $projPath; pwd`
+	`cd $currPwd`	
+fi
+
+# Generate relative path from project folder to gameplay folder
+gpPathAbs=`pwd`
+common_path=$projPath
+back=
+while [ "${gpPathAbs#$common_path}" = "${gpPathAbs}" ]; do
+	common_path=$(dirname $common_path)
+	back="../${back}"
+done
+gpPath=${back}${gpPathAbs#$common_path/}
+if [[ ${gpPathAbs} == ${common_path} ]]; then
+	gpPath=${back}
+fi
+
+
+# Below does copy, then uses 'sed' with -i for inplace editing
+# Alternative below uses sed to do a input then output skipping the copy
+# sed "s/TEMPLATE_PROJECT/$projectName/g" "gameplay-template/gameplay-template.vcxproj" > "$projPath/$projName.vcxproj"
+
+#############################################
+# Copy Microsoft Virtual Studio project files
+cp "gameplay-template/gameplay-template.vcxproj" "$projPath/$projName.vcxproj"
+sed -i "" "s*TEMPLATE_PROJECT*$projectName*g" "$projPath/$projName.vcxproj"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.vcxproj"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.vcxproj"
+
+cp "gameplay-template/gameplay-template.vcxproj.filters" "$projPath/$projName.vcxproj.filters"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.vcxproj.filters"
+
+cp "gameplay-template/gameplay-template.vcxproj.user" "$projPath/$projName.vcxproj.user"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.vcxproj.user"
+
+
+#############################################
+# Copy Apple XCode project files
+mkdir -p "$projPath/$projName.xcodeproj"
+cp "gameplay-template/gameplay-template.xcodeproj/project.pbxproj" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/$projName.xcodeproj/project.pbxproj"
+
+cp "gameplay-template/TEMPLATE_PROJECT-macosx.plist" "$projPath/$projName-macosx.plist"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/$projName-macosx.plist"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/$projName-macosx.plist"
+
+cp "gameplay-template/TEMPLATE_PROJECT-ios.plist" "$projPath/$projName-ios.plist"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/$projName-ios.plist"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/$projName-ios.plist"
+
+#############################################
+# Copy BlackBerry NDK project files
+cp "gameplay-template/template.cproject" "$projPath/.cproject"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/.cproject"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/.cproject"
+sed -i "" "s*GAMEPLAY_PATH*$gpPath*g" "$projPath/.cproject"
+
+cp "gameplay-template/template.project" "$projPath/.project"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/.project"
+
+cp "gameplay-template/template.bar-descriptor.xml" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_TITLE*$title*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_AUTHOR*$author*g" "$projPath/bar-descriptor.xml"
+sed -i "" "s*TEMPLATE_DESCRIPTION*$desc*g" "$projPath/bar-descriptor.xml"
+
+#############################################
+# Copy Android NDK project files
+mkdir -p "$projPath/android"
+mkdir -p "$projPath/android/jni"
+mkdir -p "$projPath/android/res/values"
+
+cp "gameplay-template/android/template.AndroidManifest.xml" "$projPath/android/AndroidManifest.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/AndroidManifest.xml"
+sed -i "" "s*TEMPLATE_UUID*$uuid*g" "$projPath/android/AndroidManifest.xml"
+
+cp "gameplay-template/android/template.build.xml" "$projPath/android/build.xml"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/build.xml"
+
+# Does not exist
+#cp "gameplay-template/android/template.project" "$projPath/android/.project"
+#sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/.project"
+
+#cp "gameplay-template/android/template.classpath" "$projPath/android/.classpath"
+
+cp "gameplay-template/android/jni/Application.mk" "$projPath/android/jni/Application.mk"
+
+cp "gameplay-template/android/jni/template.Android.mk" "$projPath/android/jni/Android.mk"
+sed -i "" "s*TEMPLATE_PROJECT*$projName*g" "$projPath/android/jni/Android.mk"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/android/jni/Android.mk"
+
+#cp "gameplay-template/android/jni/main.cpp" "$projPath/android/jni/main.cpp"
+
+cp "gameplay-template/android/res/values/template.strings.xml" "$projPath/android/res/values/strings.xml"
+sed -i "" "s*TEMPLATE_TITLE*$title*g" "$projPath/android/res/values/strings.xml"
+
+
+#############################################
+# Copy source files
+#############################################
+cp "gameplay-template/src/TemplateGame.h" "$projPath/src/$className.h"
+cp "gameplay-template/src/TemplateGame.cpp" "$projPath/src/$className.cpp"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/src/$className.h"
+sed -i "" "s*TemplateGame*$className*g" "$projPath/src/$className.cpp"
+
+# Copy resource files
+cp "gameplay-template/res/"* "$projPath/res/"
+#cp "gameplay-template/res/shaders/colored."* "$projPath/res/"
+
+# Copy icon
+cp "gameplay-template/icon.png" "$projPath/icon.png"
+
+# Open the new project folder
+open $projPath
+
+exit 0

+ 32 - 0
gameplay-template/TEMPLATE_PROJECT-ios.plist

@@ -0,0 +1,32 @@
+<?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>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+</dict>
+</plist>

+ 0 - 0
gameplay-template/gameplay-template-macos.plist → gameplay-template/TEMPLATE_PROJECT-macosx.plist


+ 1 - 0
gameplay-template/android/jni/Application.mk

@@ -0,0 +1 @@
+APP_STL     := stlport_static

+ 62 - 0
gameplay-template/android/jni/template.Android.mk

@@ -0,0 +1,62 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+SAMPLE_PATH := $(call my-dir)/../../src
+LIBPNG_PATH := $(call my-dir)/../../../../external-deps/libpng/lib/android/arm
+ZLIB_PATH := $(call my-dir)/../../../../external-deps/zlib/lib/android/arm
+BULLET_PATH := $(call my-dir)/../../../../external-deps/bullet/lib/android/arm
+
+# gameplay
+LOCAL_PATH := $(call my-dir)/../../../../gameplay/android/obj/local/armeabi
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libgameplay
+LOCAL_SRC_FILES := libgameplay.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# libpng
+LOCAL_PATH := $(LIBPNG_PATH)
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libpng 
+LOCAL_SRC_FILES := libpng.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# libzlib
+LOCAL_PATH := $(ZLIB_PATH)
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libzlib
+LOCAL_SRC_FILES := libzlib.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# libbullet
+LOCAL_PATH := $(BULLET_PATH)
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libbullet
+LOCAL_SRC_FILES := libbullet.a
+include $(PREBUILT_STATIC_LIBRARY)
+
+# TEMPLATE_PROJECT
+LOCAL_PATH := $(SAMPLE_PATH)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := TEMPLATE_PROJECT
+LOCAL_SRC_FILES := ../../../gameplay/src/gameplay-main-android.cpp TemplateGame.cpp
+
+LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv2 -lOpenSLES
+LOCAL_CFLAGS    := -D__ANDROID__ -I"../../../external-deps/bullet/include" -I"../../../external-deps/libpng/include" -I"../../../gameplay/src"
+
+LOCAL_STATIC_LIBRARIES := android_native_app_glue libgameplay libpng libzlib libbullet
+
+include $(BUILD_SHARED_LIBRARY)
+$(call import-module,android/native_app_glue)

+ 4 - 0
gameplay-template/android/res/values/template.strings.xml

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

+ 32 - 0
gameplay-template/android/template.AndroidManifest.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="TEMPLATE_UUID"
+        android:versionCode="1"
+        android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+        
+    <!-- This is the platform API where the app was introduced. -->
+    <uses-sdk android:minSdkVersion="9" />
+	<uses-feature android:glEsVersion="0x00020000"/>
+
+    <application android:label="@string/app_name" android:hasCode="true">
+
+        <!-- Our activity is the built-in NativeActivity framework class.
+             This will take care of integrating with our NDK code. -->
+        <activity android:name="android.app.NativeActivity"
+                android:label="@string/app_name"
+                android:configChanges="orientation|keyboardHidden"
+				android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+				android:screenOrientation="landscape">
+            <!-- Tell NativeActivity the name of or .so -->
+            <meta-data android:name="android.app.lib_name"
+                    android:value="TEMPLATE_PROJECT" />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest> 

+ 92 - 0
gameplay-template/android/template.build.xml

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

+ 266 - 47
gameplay-template/gameplay-template.xcodeproj/project.pbxproj

@@ -7,14 +7,14 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		42C932F11491A5160098216A /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
+		42438B531491AD2000D218B8 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
+		42C932C11491A0DB0098216A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C932C01491A0DB0098216A /* Cocoa.framework */; };
 		42C932EE1491A4CB0098216A /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 42C932ED1491A4CB0098216A /* icon.png */; };
+		42C932F11491A5160098216A /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
 		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 */; };
+		42C9331D1491A6750098216A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9331C1491A6750098216A /* QuartzCore.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 */; };
@@ -22,27 +22,55 @@
 		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 */; };
+		5B61611614CCC24C0073B857 /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
+		5B61611814CCC24C0073B857 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
+		5B61611914CCC24C0073B857 /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933201491A6C70098216A /* libbullet.a */; };
+		5B61611A14CCC24C0073B857 /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933221491A6E50098216A /* libogg.a */; };
+		5B61611B14CCC24C0073B857 /* libvorbis.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933231491A6E50098216A /* libvorbis.a */; };
+		5B61611C14CCC24C0073B857 /* libvorbisenc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933241491A6E50098216A /* libvorbisenc.a */; };
+		5B61611D14CCC24C0073B857 /* libvorbisfile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933251491A6E50098216A /* libvorbisfile.a */; };
+		5B61611E14CCC24C0073B857 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332A1491A7390098216A /* libpng.a */; };
+		5B61611F14CCC24C0073B857 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332D1491A7810098216A /* libz.dylib */; };
+		5B61612614CCC24C0073B857 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 42C932ED1491A4CB0098216A /* icon.png */; };
+		5B61612714CCC24C0073B857 /* res in Resources */ = {isa = PBXBuildFile; fileRef = 42C932F21491A53E0098216A /* res */; };
+		5BAF206D152F2DDD003E2AC3 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2067152F2DDD003E2AC3 /* CoreMotion.framework */; };
+		5BAF206E152F2DDD003E2AC3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2068152F2DDD003E2AC3 /* Foundation.framework */; };
+		5BAF206F152F2DDD003E2AC3 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2069152F2DDD003E2AC3 /* OpenAL.framework */; };
+		5BAF2070152F2DDD003E2AC3 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF206A152F2DDD003E2AC3 /* OpenGLES.framework */; };
+		5BAF2071152F2DDD003E2AC3 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF206B152F2DDD003E2AC3 /* QuartzCore.framework */; };
+		5BAF2072152F2DDD003E2AC3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF206C152F2DDD003E2AC3 /* UIKit.framework */; };
 /* 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>"; };
+		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>"; };
+		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-MacOSX.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		42C932C01491A0DB0098216A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		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; };
+		42C932F21491A53E0098216A /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
 		42C933161491A5EB0098216A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		42C9331C1491A6750098216A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.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>"; };
+		42C933201491A6C70098216A /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "GAMEPLAY_PATH/external-deps/bullet/lib/macosx/libbullet.a"; sourceTree = "<group>"; };
+		42C933221491A6E50098216A /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macosx/libogg.a"; sourceTree = "<group>"; };
+		42C933231491A6E50098216A /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macosx/libvorbis.a"; sourceTree = "<group>"; };
+		42C933241491A6E50098216A /* libvorbisenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisenc.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macosx/libvorbisenc.a"; sourceTree = "<group>"; };
+		42C933251491A6E50098216A /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "GAMEPLAY_PATH/external-deps/oggvorbis/lib/macosx/libvorbisfile.a"; sourceTree = "<group>"; };
+		42C9332A1491A7390098216A /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "GAMEPLAY_PATH/external-deps/libpng/lib/macosx/libpng.a"; sourceTree = "<group>"; };
 		42C9332D1491A7810098216A /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+		5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-macosx.plist"; sourceTree = "<group>"; };
+		5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		5B61612E14CCC24D0073B857 /* TEMPLATE_PROJECT-ios.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-ios.plist"; sourceTree = "<group>"; };
+		5BAF2067152F2DDD003E2AC3 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2068152F2DDD003E2AC3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2069152F2DDD003E2AC3 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF206A152F2DDD003E2AC3 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF206B152F2DDD003E2AC3 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF206C152F2DDD003E2AC3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = gameplay.xcodeproj; path = GAMEPLAY_PATH/gameplay/gameplay.xcodeproj; sourceTree = SOURCE_ROOT; };
+		5BC4E849150F911D00CBE1C0 /* shaders */ = {isa = PBXFileReference; lastKnownFileType = text; name = shaders; path = GAMEPLAY_PATH/gameplay/res/shaders; sourceTree = SOURCE_ROOT; };
+		5BC4E84A150F911D00CBE1C0 /* textures */ = {isa = PBXFileReference; lastKnownFileType = text; name = textures; path = GAMEPLAY_PATH/gameplay/res/textures; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -65,13 +93,35 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B61611714CCC24C0073B857 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5BAF206D152F2DDD003E2AC3 /* CoreMotion.framework in Frameworks */,
+				5BAF206E152F2DDD003E2AC3 /* Foundation.framework in Frameworks */,
+				5BAF206F152F2DDD003E2AC3 /* OpenAL.framework in Frameworks */,
+				5BAF2070152F2DDD003E2AC3 /* OpenGLES.framework in Frameworks */,
+				5BAF2071152F2DDD003E2AC3 /* QuartzCore.framework in Frameworks */,
+				5BAF2072152F2DDD003E2AC3 /* UIKit.framework in Frameworks */,
+				5B61611814CCC24C0073B857 /* libgameplay.a in Frameworks */,
+				5B61611914CCC24C0073B857 /* libbullet.a in Frameworks */,
+				5B61611A14CCC24C0073B857 /* libogg.a in Frameworks */,
+				5B61611B14CCC24C0073B857 /* libvorbis.a in Frameworks */,
+				5B61611C14CCC24C0073B857 /* libvorbisenc.a in Frameworks */,
+				5B61611D14CCC24C0073B857 /* libvorbisfile.a in Frameworks */,
+				5B61611E14CCC24C0073B857 /* libpng.a in Frameworks */,
+				5B61611F14CCC24C0073B857 /* libz.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 		42C932B11491A0DB0098216A = {
 			isa = PBXGroup;
 			children = (
-				42C9336B1491AA0E0098216A /* TEMPLATE_PROJECT-macos.plist */,
+				5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macosx.plist */,
+				5B61612E14CCC24D0073B857 /* TEMPLATE_PROJECT-ios.plist */,
 				42C932ED1491A4CB0098216A /* icon.png */,
 				42C932F21491A53E0098216A /* res */,
 				42C932C61491A0DB0098216A /* src */,
@@ -84,7 +134,8 @@
 		42C932BD1491A0DB0098216A /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */,
+				42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */,
+				5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -92,10 +143,9 @@
 		42C932BF1491A0DB0098216A /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				42C932C01491A0DB0098216A /* Cocoa.framework */,
-				42C9331C1491A6750098216A /* QuartzCore.framework */,
-				42C933161491A5EB0098216A /* OpenGL.framework */,
-				42C9331E1491A67F0098216A /* OpenAL.framework */,
+				5BC4E825150F8CE600CBE1C0 /* GamePlay */,
+				5B61613A14CCC3590073B857 /* MacOSX */,
+				5B61613914CCC3560073B857 /* iOS */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -106,8 +156,7 @@
 				42C932EF1491A5160098216A /* TemplateGame.cpp */,
 				42C932F01491A5160098216A /* TemplateGame.h */,
 			);
-			name = src;
-			path = "src";
+			path = src;
 			sourceTree = "<group>";
 		};
 		42C932DD1491A1050098216A /* Libraries */ = {
@@ -125,25 +174,79 @@
 			name = Libraries;
 			sourceTree = "<group>";
 		};
+		5B61613914CCC3560073B857 /* iOS */ = {
+			isa = PBXGroup;
+			children = (
+				5BAF2067152F2DDD003E2AC3 /* CoreMotion.framework */,
+				5BAF2068152F2DDD003E2AC3 /* Foundation.framework */,
+				5BAF2069152F2DDD003E2AC3 /* OpenAL.framework */,
+				5BAF206A152F2DDD003E2AC3 /* OpenGLES.framework */,
+				5BAF206B152F2DDD003E2AC3 /* QuartzCore.framework */,
+				5BAF206C152F2DDD003E2AC3 /* UIKit.framework */,
+			);
+			name = iOS;
+			sourceTree = "<group>";
+		};
+		5B61613A14CCC3590073B857 /* MacOSX */ = {
+			isa = PBXGroup;
+			children = (
+				42C932C01491A0DB0098216A /* Cocoa.framework */,
+				42C9331C1491A6750098216A /* QuartzCore.framework */,
+				42C933161491A5EB0098216A /* OpenGL.framework */,
+				42C9331E1491A67F0098216A /* OpenAL.framework */,
+			);
+			name = MacOSX;
+			sourceTree = "<group>";
+		};
+		5BC4E825150F8CE600CBE1C0 /* GamePlay */ = {
+			isa = PBXGroup;
+			children = (
+				5BC4E849150F911D00CBE1C0 /* shaders */,
+				5BC4E84A150F911D00CBE1C0 /* textures */,
+				5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */,
+			);
+			name = GamePlay;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT */ = {
+		42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT" */;
+			buildConfigurationList = 42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-MacOSX" */;
 			buildPhases = (
 				42C932B81491A0DB0098216A /* Sources */,
 				42C932B91491A0DB0098216A /* Frameworks */,
 				42C933301491A7B50098216A /* ShellScript */,
 				42C932BA1491A0DB0098216A /* Resources */,
+				5BAF20D7152F30C3003E2AC3 /* Copy Gameplay Resources - Run Script */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "TEMPLATE_PROJECT-MacOSX";
+			productName = TEMPLATE_PROJECT;
+			productReference = 42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */;
+			productType = "com.apple.product-type.application";
+		};
+		5B61611414CCC24C0073B857 /* TEMPLATE_PROJECT-iOS */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 5B61612914CCC24C0073B857 /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-iOS" */;
+			buildPhases = (
+				5B61611514CCC24C0073B857 /* Sources */,
+				5B61611714CCC24C0073B857 /* Frameworks */,
+				5B61612414CCC24C0073B857 /* ShellScript */,
+				5B61612514CCC24C0073B857 /* Resources */,
+				5BAF20A3152F2FCE003E2AC3 /* Copy Gameplay Reousrces Run Script */,
 			);
 			buildRules = (
 			);
 			dependencies = (
 			);
-			name = "TEMPLATE_PROJECT";
-			productName = "TEMPLATE_PROJECT";
-			productReference = 42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT.app */;
+			name = "TEMPLATE_PROJECT-iOS";
+			productName = TEMPLATE_PROJECT;
+			productReference = 5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */;
 			productType = "com.apple.product-type.application";
 		};
 /* End PBXNativeTarget section */
@@ -154,7 +257,7 @@
 			attributes = {
 				LastUpgradeCheck = 0420;
 			};
-			buildConfigurationList = 42C932B61491A0DB0098216A /* Build configuration list for PBXProject "TEMPLATE_PROJECT" */;
+			buildConfigurationList = 42C932B61491A0DB0098216A /* Build configuration list for PBXProject "gameplay-template" */;
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
@@ -166,7 +269,8 @@
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT */,
+				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX */,
+				5B61611414CCC24C0073B857 /* TEMPLATE_PROJECT-iOS */,
 			);
 		};
 /* End PBXProject section */
@@ -181,6 +285,15 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B61612514CCC24C0073B857 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B61612614CCC24C0073B857 /* icon.png in Resources */,
+				5B61612714CCC24C0073B857 /* res in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
@@ -197,6 +310,47 @@
 			shellPath = /bin/sh;
 			shellScript = "touch -cm ${SRCROOT}/res";
 		};
+		5B61612414CCC24C0073B857 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "touch -cm ${SRCROOT}/res";
+		};
+		5BAF20A3152F2FCE003E2AC3 /* Copy Gameplay Reousrces Run Script */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Copy Gameplay Reousrces Run Script";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "cp -rn GAMEPLAY_PATH/gameplay/res/shaders ${SRCROOT}/res\ncp -rn GAMEPLAY_PATH/gameplay/res/logo_powered_white.png ${SRCROOT}/res\ntouch -cm ${SRCROOT}/res";
+		};
+		5BAF20D7152F30C3003E2AC3 /* Copy Gameplay Resources - Run Script */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Copy Gameplay Resources - Run Script";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "cp -rn GAMEPLAY_PATH/gameplay/res/shaders ${SRCROOT}/res\ncp -rn GAMEPLAY_PATH/gameplay/res/logo_powered_white.png ${SRCROOT}/res\ntouch -cm ${SRCROOT}/res";
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -208,6 +362,14 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		5B61611514CCC24C0073B857 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5B61611614CCC24C0073B857 /* TemplateGame.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
@@ -232,7 +394,7 @@
 				GCC_WARN_ABOUT_RETURN_TYPE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GENERATE_PKGINFO_FILE = YES;
-				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macosx.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
 				ONLY_ACTIVE_ARCH = YES;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -255,7 +417,7 @@
 				GCC_WARN_ABOUT_RETURN_TYPE = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				GENERATE_PKGINFO_FILE = YES;
-				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macosx.plist";
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
@@ -270,18 +432,17 @@
 				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
-					"GAMEPLAY_PATH/gameplay/src",
+					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";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macosx.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\"",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macosx\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/macosx\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/macosx\"",
 				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "";
@@ -297,18 +458,17 @@
 				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
-					"GAMEPLAY_PATH/gameplay/src",
+					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";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macosx.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\"",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macosx\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/macosx\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/macosx\"",
 				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				USER_HEADER_SEARCH_PATHS = "";
@@ -316,10 +476,60 @@
 			};
 			name = Release;
 		};
+		5B61612A14CCC24C0073B857 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				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-ios.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/ios/$(CURRENT_ARCH)\"",
+				);
+				SDKROOT = iphoneos;
+				USER_HEADER_SEARCH_PATHS = "";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		5B61612B14CCC24C0073B857 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				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-ios.plist";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"\"GAMEPLAY_PATH/external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/bullet/lib/ios/$(CURRENT_ARCH)\"",
+					"\"GAMEPLAY_PATH/external-deps/oggvorbis/lib/ios/$(CURRENT_ARCH)\"",
+				);
+				SDKROOT = iphoneos;
+				USER_HEADER_SEARCH_PATHS = "";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		42C932B61491A0DB0098216A /* Build configuration list for PBXProject "TEMPLATE_PROJECT" */ = {
+		42C932B61491A0DB0098216A /* Build configuration list for PBXProject "gameplay-template" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				42C932D81491A0DB0098216A /* Debug */,
@@ -328,7 +538,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT" */ = {
+		42C932DA1491A0DB0098216A /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-MacOSX" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				42C932DB1491A0DB0098216A /* Debug */,
@@ -337,6 +547,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		5B61612914CCC24C0073B857 /* Build configuration list for PBXNativeTarget "TEMPLATE_PROJECT-iOS" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				5B61612A14CCC24C0073B857 /* Debug */,
+				5B61612B14CCC24C0073B857 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
 	};
 	rootObject = 42C932B31491A0DB0098216A /* Project object */;

BIN
gameplay-template/icon.png


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

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

+ 3 - 1
gameplay-template/template.bar-descriptor.xml

@@ -38,7 +38,9 @@
     <author>TEMPLATE_AUTHOR</author>
 
     <!--  Unique author ID assigned by signing authority. Required if using debug tokens. -->
-    <!-- <authorId>ABC1234YjsnUk235h</authorId> -->
+    <!-- <authorId>gYAAgPkLP1tZlyYP1wiMaRFFNMw</authorId> -->
+    
+    <platformVersion>2.0.0.7971</platformVersion>
 
     <initialWindow>
         <aspectRatio>landscape</aspectRatio>

+ 86 - 74
gameplay.doxyfile

@@ -1,4 +1,4 @@
-# Doxyfile 1.7.5.1
+# Doxyfile 1.8.0
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project
@@ -26,13 +26,13 @@ DOXYFILE_ENCODING      = UTF-8
 # identify the project. Note that if you do not use Doxywizard you need 
 # to put quotes around the project name if it contains spaces.
 
-PROJECT_NAME           = GamePlay
+PROJECT_NAME           = gameplay
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 
-PROJECT_NUMBER         = 1.1.0
+PROJECT_NUMBER         = 1.2.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description 
 # for a project that appears at the top of each page and should give viewer 
@@ -45,7 +45,7 @@ PROJECT_BRIEF          =
 # exceed 55 pixels and the maximum width should not exceed 200 pixels. 
 # Doxygen will copy the logo to the output directory.
 
-PROJECT_LOGO           = 
+PROJECT_LOGO           = ./gameplay-api/gameplay.png
 
 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
 # base path where the generated documentation will be put. 
@@ -205,6 +205,13 @@ TAB_SIZE               = 8
 
 ALIASES                = 
 
+# This tag can be used to specify a number of word-keyword mappings (TCL only). 
+# A mapping has the form "name=value". For example adding 
+# "class=itcl::class" will allow you to use the command class in the 
+# itcl::class meaning.
+
+TCL_SUBST              = 
+
 # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
 # sources only. Doxygen will then generate output that is more tailored for C. 
 # For instance, some of the names that are used will be different. The list 
@@ -243,6 +250,15 @@ OPTIMIZE_OUTPUT_VHDL   = NO
 
 EXTENSION_MAPPING      = 
 
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all 
+# comments according to the Markdown format, which allows for more readable 
+# documentation. See http://daringfireball.net/projects/markdown/ for details. 
+# The output of markdown processing is further processed by doxygen, so you 
+# can mix doxygen, HTML, and XML commands with Markdown formatting. 
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
 # to include (a tag file for) the STL sources as input, then you should 
 # set this tag to YES in order to let doxygen match functions declarations and 
@@ -325,10 +341,21 @@ TYPEDEF_HIDES_STRUCT   = NO
 # a logarithmic scale so increasing the size by one will roughly double the 
 # memory usage. The cache size is given by this formula: 
 # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
-# corresponding to a cache size of 2^16 = 65536 symbols
+# corresponding to a cache size of 2^16 = 65536 symbols.
 
 SYMBOL_CACHE_SIZE      = 0
 
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 
+# their name and scope. Since this can be an expensive process and often the 
+# same symbol appear multiple times in the code, doxygen keeps a cache of 
+# pre-resolved symbols. If the cache is too small doxygen will become slower. 
+# If the cache is too large, memory is wasted. The cache size is given by this 
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
@@ -345,6 +372,11 @@ EXTRACT_ALL            = NO
 
 EXTRACT_PRIVATE        = NO
 
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
 # If the EXTRACT_STATIC tag is set to YES all static members of a file 
 # will be included in the documentation.
 
@@ -548,7 +580,7 @@ SHOW_FILES             = YES
 # Namespaces page.  This will remove the Namespaces entry from the Quick Index 
 # and from the Folder Tree View (if specified). The default is YES.
 
-SHOW_NAMESPACES        = YES
+SHOW_NAMESPACES        = NO
 
 # The FILE_VERSION_FILTER tag can be used to specify a program or script that 
 # doxygen should invoke to get the current version for each file (typically from 
@@ -574,7 +606,8 @@ LAYOUT_FILE            =
 # .bib extension is automatically appended if omitted. Using this command 
 # requires the bibtex tool to be installed. See also 
 # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 
-# of the bibliography can be controlled using LATEX_BIB_STYLE.
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 
+# feature you need bibtex and perl available in the search path.
 
 CITE_BIB_FILES         = 
 
@@ -656,38 +689,7 @@ INPUT_ENCODING         = UTF-8
 # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 
 # *.f90 *.f *.for *.vhd *.vhdl
 
-FILE_PATTERNS          = *.c \
-                         *.cc \
-                         *.cxx \
-                         *.cpp \
-                         *.c++ \
-                         *.d \
-                         *.java \
-                         *.ii \
-                         *.ixx \
-                         *.ipp \
-                         *.i++ \
-                         *.inl \
-                         *.h \
-                         *.hh \
-                         *.hxx \
-                         *.hpp \
-                         *.h++ \
-                         *.idl \
-                         *.odl \
-                         *.cs \
-                         *.php \
-                         *.php3 \
-                         *.inc \
-                         *.m \
-                         *.mm \
-                         *.dox \
-                         *.py \
-                         *.f90 \
-                         *.f \
-                         *.for \
-                         *.vhd \
-                         *.vhdl
+FILE_PATTERNS          = *.h
 
 # The RECURSIVE tag can be used to turn specify whether or not subdirectories 
 # should be searched for input files as well. Possible values are YES and NO. 
@@ -695,14 +697,15 @@ FILE_PATTERNS          = *.c \
 
 RECURSIVE              = NO
 
-# The EXCLUDE tag can be used to specify files and/or directories that should 
+# The EXCLUDE tag can be used to specify files and/or directories that should be 
 # excluded from the INPUT source files. This way you can easily exclude a 
 # subdirectory from a directory tree whose root is specified with the INPUT tag. 
-# Note that relative paths are relative to directory from which doxygen is run.
+# Note that relative paths are relative to the directory from which doxygen is 
+# run.
 
 EXCLUDE                = 
 
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 
 # directories that are symbolic links (a Unix file system feature) are excluded 
 # from the input.
 
@@ -887,7 +890,7 @@ HTML_FILE_EXTENSION    = .html
 # standard header. Note that when using a custom header you are responsible  
 # for the proper inclusion of any scripts and style sheets that doxygen 
 # needs, which is dependent on the configuration options used. 
-# It is adviced to generate a default header using "doxygen -w html 
+# It is advised to generate a default header using "doxygen -w html 
 # header.html footer.html stylesheet.css YourConfigFile" and then modify 
 # that header. Note that the header is subject to change so you typically 
 # have to redo this when upgrading to a newer version of doxygen or when 
@@ -906,7 +909,7 @@ HTML_FOOTER            =
 # fine-tune the look of the HTML output. If the tag is left blank doxygen 
 # will generate a default style sheet. Note that doxygen will try to copy 
 # the style sheet file to the HTML output directory, so don't put your own 
-# stylesheet in the HTML output directory as well, or it will be erased!
+# style sheet in the HTML output directory as well, or it will be erased!
 
 HTML_STYLESHEET        = 
 
@@ -920,7 +923,7 @@ HTML_STYLESHEET        =
 HTML_EXTRA_FILES       = 
 
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 
-# Doxygen will adjust the colors in the stylesheet and background images 
+# Doxygen will adjust the colors in the style sheet and background images 
 # according to this color. Hue is specified as an angle on a colorwheel, 
 # see http://en.wikipedia.org/wiki/Hue for more information. 
 # For instance the value 0 represents red, 60 is yellow, 120 is green, 
@@ -1115,29 +1118,33 @@ GENERATE_ECLIPSEHELP   = NO
 
 ECLIPSE_DOC_ID         = org.doxygen.Project
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
-# top of each HTML page. The value NO (the default) enables the index and 
-# the value YES disables it.
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 
+# at top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it. Since the tabs have the same information as the 
+# navigation tree you can set this option to NO if you already set 
+# GENERATE_TREEVIEW to YES.
 
 DISABLE_INDEX          = NO
 
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
-# documentation. Note that a value of 0 will completely suppress the enum 
-# values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE   = 4
-
 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
 # structure should be generated to display hierarchical information. 
 # If the tag value is set to YES, a side panel will be generated 
 # containing a tree-like index structure (just like the one that 
 # is generated for HTML Help). For this to work a browser that supports 
 # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 
-# Windows users are probably better off using the HTML help feature.
+# Windows users are probably better off using the HTML help feature. 
+# Since the tree basically has the same information as the tab index you 
+# could consider to set DISABLE_INDEX to NO when enabling this option.
 
 GENERATE_TREEVIEW      = YES
 
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML 
+# documentation. Note that a value of 0 will completely suppress the enum 
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
 # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 
 # and Class Hierarchy pages using a tree view instead of an ordered list.
 
@@ -1174,7 +1181,7 @@ FORMULA_TRANSPARENT    = YES
 # (see http://www.mathjax.org) which uses client side Javascript for the 
 # rendering instead of using prerendered bitmaps. Use this if you do not 
 # have LaTeX installed or if you want to formulas look prettier in the HTML 
-# output. When enabled you also need to install MathJax separately and 
+# output. When enabled you may also need to install MathJax separately and 
 # configure the path to it using the MATHJAX_RELPATH option.
 
 USE_MATHJAX            = NO
@@ -1183,10 +1190,10 @@ USE_MATHJAX            = NO
 # HTML output directory using the MATHJAX_RELPATH option. The destination 
 # directory should contain the MathJax.js script. For instance, if the mathjax 
 # directory is located at the same level as the HTML output directory, then 
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the 
-# mathjax.org site, so you can quickly see the result without installing 
-# MathJax, but it is strongly recommended to install a local copy of MathJax 
-# before deployment.
+# MATHJAX_RELPATH should be ../mathjax. The default value points to 
+# the MathJax Content Delivery Network so you can quickly see the result without 
+# installing MathJax.  However, it is strongly recommended to install a local 
+# copy of MathJax from http://www.mathjax.org before deployment.
 
 MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
 
@@ -1345,7 +1352,7 @@ COMPACT_RTF            = NO
 
 RTF_HYPERLINKS         = NO
 
-# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# Load style sheet definitions from file. Syntax is similar to doxygen's 
 # config file, i.e. a series of assignments. You only have to provide 
 # replacements, missing definitions are set to their default value.
 
@@ -1534,20 +1541,16 @@ SKIP_FUNCTION_MACROS   = YES
 # Configuration::additions related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles. 
-# Optionally an initial location of the external documentation 
-# can be added for each tagfile. The format of a tag file without 
-# this location is as follows: 
+# The TAGFILES option can be used to specify one or more tagfiles. For each 
+# tag file the location of the external documentation should be added. The 
+# format of a tag file without this location is as follows: 
 #   TAGFILES = file1 file2 ... 
 # Adding location for the tag files is done as follows: 
 #   TAGFILES = file1=loc1 "file2 = loc2" ... 
-# where "loc1" and "loc2" can be relative or absolute paths or 
-# URLs. If a location is present for each tag, the installdox tool 
-# does not have to be run to correct the links. 
-# Note that each tag file must have a unique name 
-# (where the name does NOT include the path) 
-# If a tag file is not located in the directory in which doxygen 
-# is run, you must also specify the path to the tagfile here.
+# where "loc1" and "loc2" can be relative or absolute paths 
+# or URLs. Note that each tag file must have a unique name (where the name does 
+# NOT include the path). If a tag file is not located in the directory in which 
+# doxygen is run, you must also specify the path to the tagfile here.
 
 TAGFILES               = 
 
@@ -1638,7 +1641,7 @@ DOT_FONTPATH           =
 # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
 # will generate a graph for each documented class showing the direct and 
 # indirect inheritance relations. Setting this tag to YES will force the 
-# the CLASS_DIAGRAMS tag to NO.
+# CLASS_DIAGRAMS tag to NO.
 
 CLASS_GRAPH            = YES
 
@@ -1660,6 +1663,15 @@ GROUP_GRAPHS           = YES
 
 UML_LOOK               = NO
 
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside 
+# the class node. If there are many fields or methods and many nodes the 
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS 
+# threshold limits the number of items for each type to make the size more 
+# managable. Set this to 0 for no limit. Note that the threshold may be 
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
 # If set to YES, the inheritance and collaboration graphs will show the 
 # relations between templates and their instances.
 

+ 22 - 11
gameplay.sln

@@ -3,11 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual Studio 2010
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay", "gameplay\gameplay.vcxproj", "{1032BA4B-57EB-4348-9E03-29DD63E80E4A}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample00-mesh", "gameplay-samples\sample00-mesh\sample00-mesh.vcxproj", "{D672DC66-3CE0-4878-B0D2-813CA731012F}"
-	ProjectSection(ProjectDependencies) = postProject
-		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample01-longboard", "gameplay-samples\sample01-longboard\sample01-longboard.vcxproj", "{9A515C8B-3320-4C5C-9754-211E91206C9D}"
 	ProjectSection(ProjectDependencies) = postProject
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
@@ -25,6 +20,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample03-character", "gamep
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder\gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample04-particles", "gameplay-samples\sample04-particles\sample04-particles.vcxproj", "{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample00-mesh", "gameplay-samples\sample00-mesh\sample00-mesh.vcxproj", "{D672DC66-3CE0-4878-B0D2-813CA731012F}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -38,12 +43,6 @@ Global
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|Win32.Build.0 = DebugMem|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.ActiveCfg = Release|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.Build.0 = Release|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.Build.0 = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
@@ -68,6 +67,18 @@ Global
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.Build.0 = Debug|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.ActiveCfg = Release|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.Build.0 = Release|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|Win32.ActiveCfg = Debug|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|Win32.Build.0 = Debug|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|Win32.ActiveCfg = Release|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|Win32.Build.0 = Release|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 3 - 0
gameplay.xcworkspace/contents.xcworkspacedata

@@ -19,4 +19,7 @@
    <FileRef
       location = "group:gameplay-samples/sample03-character/sample03-character.xcodeproj">
    </FileRef>
+   <FileRef
+      location = "group:gameplay-samples/sample04-particles/sample04-particles.xcodeproj">
+   </FileRef>
 </Workspace>

+ 1 - 3
gameplay/.cproject

@@ -9,8 +9,6 @@
 				<extensions>
 					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" 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">
@@ -19,7 +17,7 @@
 						<toolChain id="com.qnx.qcc.toolChain.staticLib.debug.1686166742" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
 							<option id="com.qnx.qcc.option.cpu.545743487" 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.158841187" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="cdt.managedbuild.target.gnu.builder.base.2098111998" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="org.eclipse.cdt.build.core.internal.builder.159190287" superClass="org.eclipse.cdt.build.core.internal.builder"/>
 							<tool id="com.qnx.qcc.tool.compiler.96907942" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
 								<option id="com.qnx.qcc.option.compile.debug.1765481355" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>

+ 0 - 12
gameplay/.project

@@ -17,10 +17,6 @@
 					<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>
@@ -33,10 +29,6 @@
 					<key>org.eclipse.cdt.make.core.buildLocation</key>
 					<value>${workspace_loc:/gameplay/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>
@@ -53,10 +45,6 @@
 					<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>

+ 14 - 0
gameplay/android/AndroidManifest.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.gameplay"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="15" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name" >
+    </application>
+
+</manifest>

+ 85 - 0
gameplay/android/build.xml

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

+ 25 - 0
gameplay/android/jni/Android.mk

@@ -0,0 +1,25 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)/../../src
+
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libgameplay
+LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Bundle.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp FlowLayout.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp Image.cpp Joint.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsMotionState.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
+LOCAL_CFLAGS := -D__ANDROID__ -I"../../external-deps/bullet/include" -I"../../external-deps/libpng/include"
+LOCAL_STATIC_LIBRARIES := android_native_app_glue
+
+include $(BUILD_STATIC_LIBRARY)
+
+$(call import-module,android/native_app_glue)

+ 2 - 0
gameplay/android/jni/Application.mk

@@ -0,0 +1,2 @@
+APP_STL     := stlport_static
+APP_MODULES := libgameplay

+ 52 - 7
gameplay/gameplay.vcxproj

@@ -15,6 +15,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="src\AbsoluteLayout.cpp" />
     <ClCompile Include="src\Animation.cpp" />
     <ClCompile Include="src\AnimationClip.cpp" />
     <ClCompile Include="src\AnimationController.cpp" />
@@ -26,20 +27,29 @@
     <ClCompile Include="src\AudioSource.cpp" />
     <ClCompile Include="src\BoundingBox.cpp" />
     <ClCompile Include="src\BoundingSphere.cpp" />
+    <ClCompile Include="src\Button.cpp" />
     <ClCompile Include="src\Camera.cpp" />
+    <ClCompile Include="src\CheckBox.cpp" />
+    <ClCompile Include="src\Container.cpp" />
+    <ClCompile Include="src\Control.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\FlowLayout.cpp" />
     <ClCompile Include="src\Font.cpp" />
+    <ClCompile Include="src\Form.cpp" />
     <ClCompile Include="src\FrameBuffer.cpp" />
     <ClCompile Include="src\Frustum.cpp" />
     <ClCompile Include="src\Game.cpp" />
+    <ClCompile Include="src\gameplay-main-android.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\Label.cpp" />
+    <ClCompile Include="src\Layout.cpp" />
     <ClCompile Include="src\Light.cpp" />
     <ClCompile Include="src\Material.cpp" />
     <ClCompile Include="src\MeshBatch.cpp" />
@@ -51,22 +61,28 @@
     <ClCompile Include="src\MeshSkin.cpp" />
     <ClCompile Include="src\Model.cpp" />
     <ClCompile Include="src\Node.cpp" />
-    <ClCompile Include="src\Package.cpp" />
+    <ClCompile Include="src\Bundle.cpp" />
     <ClCompile Include="src\ParticleEmitter.cpp" />
+    <ClCompile Include="src\PhysicsCharacter.cpp" />
+    <ClCompile Include="src\PhysicsCollisionObject.cpp" />
+    <ClCompile Include="src\PhysicsCollisionShape.cpp" />
     <ClCompile Include="src\PhysicsConstraint.cpp" />
     <ClCompile Include="src\PhysicsController.cpp" />
     <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
     <ClCompile Include="src\PhysicsGenericConstraint.cpp" />
+    <ClCompile Include="src\PhysicsGhostObject.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\PlatformAndroid.cpp" />
     <ClCompile Include="src\PlatformQNX.cpp" />
     <ClCompile Include="src\PlatformWin32.cpp" />
     <ClCompile Include="src\Properties.cpp" />
     <ClCompile Include="src\Quaternion.cpp" />
+    <ClCompile Include="src\RadioButton.cpp" />
     <ClCompile Include="src\Ray.cpp" />
     <ClCompile Include="src\Rectangle.cpp" />
     <ClCompile Include="src\Ref.cpp" />
@@ -74,18 +90,23 @@
     <ClCompile Include="src\RenderTarget.cpp" />
     <ClCompile Include="src\Scene.cpp" />
     <ClCompile Include="src\SceneLoader.cpp" />
+    <ClCompile Include="src\Slider.cpp" />
     <ClCompile Include="src\SpriteBatch.cpp" />
     <ClCompile Include="src\Technique.cpp" />
+    <ClCompile Include="src\TextBox.cpp" />
     <ClCompile Include="src\Texture.cpp" />
+    <ClCompile Include="src\Theme.cpp" />
+    <ClCompile Include="src\ThemeStyle.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" />
+    <ClCompile Include="src\VerticalLayout.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="src\AbsoluteLayout.h" />
     <ClInclude Include="src\Animation.h" />
     <ClInclude Include="src\AnimationClip.h" />
     <ClInclude Include="src\AnimationController.h" />
@@ -98,13 +119,19 @@
     <ClInclude Include="src\Base.h" />
     <ClInclude Include="src\BoundingBox.h" />
     <ClInclude Include="src\BoundingSphere.h" />
+    <ClInclude Include="src\Button.h" />
     <ClInclude Include="src\Camera.h" />
+    <ClInclude Include="src\CheckBox.h" />
+    <ClInclude Include="src\Container.h" />
+    <ClInclude Include="src\Control.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\FlowLayout.h" />
     <ClInclude Include="src\Font.h" />
+    <ClInclude Include="src\Form.h" />
     <ClInclude Include="src\FrameBuffer.h" />
     <ClInclude Include="src\Frustum.h" />
     <ClInclude Include="src\Game.h" />
@@ -112,6 +139,8 @@
     <ClInclude Include="src\Image.h" />
     <ClInclude Include="src\Joint.h" />
     <ClInclude Include="src\Keyboard.h" />
+    <ClInclude Include="src\Label.h" />
+    <ClInclude Include="src\Layout.h" />
     <ClInclude Include="src\Light.h" />
     <ClInclude Include="src\Material.h" />
     <ClInclude Include="src\MeshBatch.h" />
@@ -124,12 +153,16 @@
     <ClInclude Include="src\MeshSkin.h" />
     <ClInclude Include="src\Model.h" />
     <ClInclude Include="src\Node.h" />
-    <ClInclude Include="src\Package.h" />
+    <ClInclude Include="src\Bundle.h" />
     <ClInclude Include="src\ParticleEmitter.h" />
+    <ClInclude Include="src\PhysicsCharacter.h" />
+    <ClInclude Include="src\PhysicsCollisionObject.h" />
+    <ClInclude Include="src\PhysicsCollisionShape.h" />
     <ClInclude Include="src\PhysicsConstraint.h" />
     <ClInclude Include="src\PhysicsController.h" />
     <ClInclude Include="src\PhysicsFixedConstraint.h" />
     <ClInclude Include="src\PhysicsGenericConstraint.h" />
+    <ClInclude Include="src\PhysicsGhostObject.h" />
     <ClInclude Include="src\PhysicsHingeConstraint.h" />
     <ClInclude Include="src\PhysicsMotionState.h" />
     <ClInclude Include="src\PhysicsRigidBody.h" />
@@ -139,6 +172,7 @@
     <ClInclude Include="src\Platform.h" />
     <ClInclude Include="src\Properties.h" />
     <ClInclude Include="src\Quaternion.h" />
+    <ClInclude Include="src\RadioButton.h" />
     <ClInclude Include="src\Ray.h" />
     <ClInclude Include="src\Rectangle.h" />
     <ClInclude Include="src\Ref.h" />
@@ -146,9 +180,15 @@
     <ClInclude Include="src\RenderTarget.h" />
     <ClInclude Include="src\Scene.h" />
     <ClInclude Include="src\SceneLoader.h" />
+    <ClInclude Include="src\ScreenDisplayer.h" />
+    <ClInclude Include="src\Slider.h" />
     <ClInclude Include="src\SpriteBatch.h" />
     <ClInclude Include="src\Technique.h" />
+    <ClInclude Include="src\TextBox.h" />
     <ClInclude Include="src\Texture.h" />
+    <ClInclude Include="src\Theme.h" />
+    <ClInclude Include="src\ThemeStyle.h" />
+    <ClInclude Include="src\TimeListener.h" />
     <ClInclude Include="src\Touch.h" />
     <ClInclude Include="src\Transform.h" />
     <ClInclude Include="src\Vector2.h" />
@@ -156,9 +196,13 @@
     <ClInclude Include="src\Vector4.h" />
     <ClInclude Include="src\VertexAttributeBinding.h" />
     <ClInclude Include="src\VertexFormat.h" />
-    <ClInclude Include="src\Viewport.h" />
+    <ClInclude Include="src\VerticalLayout.h" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="res\logo_black.png" />
+    <None Include="res\logo_powered_black.png" />
+    <None Include="res\logo_powered_white.png" />
+    <None Include="res\logo_white.png" />
     <None Include="res\shaders\bumped-specular.fsh" />
     <None Include="res\shaders\bumped-specular.vsh" />
     <None Include="res\shaders\bumped.fsh" />
@@ -179,17 +223,18 @@
     <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\gameplay-main-ios.mm" />
+    <None Include="src\gameplay-main-macosx.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\PlatformiOS.mm" />
+    <None Include="src\PlatformMacOSX.mm" />
     <None Include="src\Quaternion.inl" />
     <None Include="src\Ray.inl" />
     <None Include="src\Vector2.inl" />

+ 152 - 20
gameplay/gameplay.vcxproj.filters

@@ -10,9 +10,6 @@
     <Filter Include="res\shaders">
       <UniqueIdentifier>{be0b36f1-49ed-4a06-9f1f-57c654a554fe}</UniqueIdentifier>
     </Filter>
-    <Filter Include="res\textures">
-      <UniqueIdentifier>{7c4ef2fb-63f2-4d5a-b31e-0dc78329abfd}</UniqueIdentifier>
-    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\Animation.cpp">
@@ -75,9 +72,6 @@
     <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>
@@ -126,9 +120,6 @@
     <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>
@@ -222,6 +213,72 @@
     <ClCompile Include="src\MeshBatch.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\gameplay-main-android.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PlatformAndroid.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AbsoluteLayout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Button.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\CheckBox.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Container.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Control.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Label.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\RadioButton.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Slider.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\VerticalLayout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Form.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Theme.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\TextBox.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsCharacter.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsCollisionObject.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsGhostObject.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsCollisionShape.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ThemeStyle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Layout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Bundle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FlowLayout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -293,9 +350,6 @@
     <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>
@@ -341,9 +395,6 @@
     <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>
@@ -437,6 +488,72 @@
     <ClInclude Include="src\Mouse.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\AbsoluteLayout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Button.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\CheckBox.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Container.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Control.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Label.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Layout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\RadioButton.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Slider.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\VerticalLayout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Form.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Theme.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\TextBox.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsCharacter.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsCollisionObject.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\TimeListener.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsGhostObject.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsCollisionShape.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ScreenDisplayer.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ThemeStyle.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Bundle.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FlowLayout.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">
@@ -499,15 +616,12 @@
     <None Include="res\shaders\bumped-specular.fsh">
       <Filter>res\shaders</Filter>
     </None>
-    <None Include="src\gameplay-main-macos.mm">
+    <None Include="src\gameplay-main-macosx.mm">
       <Filter>src</Filter>
     </None>
-    <None Include="src\PlatformMacOS.mm">
+    <None Include="src\PlatformMacOSX.mm">
       <Filter>src</Filter>
     </None>
-    <None Include="res\textures\particle-default.png">
-      <Filter>res\textures</Filter>
-    </None>
     <None Include="src\Curve.inl">
       <Filter>src</Filter>
     </None>
@@ -520,6 +634,24 @@
     <None Include="src\MeshBatch.inl">
       <Filter>src</Filter>
     </None>
+    <None Include="src\gameplay-main-ios.mm">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\PlatformiOS.mm">
+      <Filter>src</Filter>
+    </None>
+    <None Include="res\logo_black.png">
+      <Filter>res</Filter>
+    </None>
+    <None Include="res\logo_powered_black.png">
+      <Filter>res</Filter>
+    </None>
+    <None Include="res\logo_powered_white.png">
+      <Filter>res</Filter>
+    </None>
+    <None Include="res\logo_white.png">
+      <Filter>res</Filter>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\PhysicsFixedConstraint.inl">

+ 401 - 172
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -13,12 +13,29 @@
 		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 */; };
+		422260D61537790F0011E3AB /* Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 422260D41537790F0011E3AB /* Bundle.cpp */; };
+		422260D71537790F0011E3AB /* Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 422260D41537790F0011E3AB /* Bundle.cpp */; };
+		422260D81537790F0011E3AB /* Bundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 422260D51537790F0011E3AB /* Bundle.h */; };
+		422260D91537790F0011E3AB /* Bundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 422260D51537790F0011E3AB /* Bundle.h */; };
 		4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4234D99D14686C52003031B3 /* Cocoa.framework */; };
+		4251B131152D049B002F6199 /* ScreenDisplayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4251B12E152D049B002F6199 /* ScreenDisplayer.h */; };
+		4251B132152D049B002F6199 /* ScreenDisplayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4251B12E152D049B002F6199 /* ScreenDisplayer.h */; };
+		4251B133152D049B002F6199 /* ThemeStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4251B12F152D049B002F6199 /* ThemeStyle.cpp */; };
+		4251B134152D049B002F6199 /* ThemeStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4251B12F152D049B002F6199 /* ThemeStyle.cpp */; };
+		4251B135152D049B002F6199 /* ThemeStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 4251B130152D049B002F6199 /* ThemeStyle.h */; };
+		4251B136152D049B002F6199 /* ThemeStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 4251B130152D049B002F6199 /* ThemeStyle.h */; };
+		42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */; };
+		42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */; };
+		42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
+		42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
+		426878AC153F4BB300844500 /* FlowLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 426878AA153F4BB300844500 /* FlowLayout.cpp */; };
+		426878AD153F4BB300844500 /* FlowLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 426878AA153F4BB300844500 /* FlowLayout.cpp */; };
+		426878AE153F4BB300844500 /* FlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 426878AB153F4BB300844500 /* FlowLayout.h */; };
+		426878AF153F4BB300844500 /* FlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 426878AB153F4BB300844500 /* FlowLayout.h */; };
+		4271C08E15337C8200B89DA7 /* Layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4271C08D15337C8200B89DA7 /* Layout.cpp */; };
+		4271C08F15337C8200B89DA7 /* Layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4271C08D15337C8200B89DA7 /* Layout.cpp */; };
 		428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
-		4299EFA9146AC94300FF4A73 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4299EFA8146AC94300FF4A73 /* OpenGL.framework */; };
-		4299EFAB146AC94B00FF4A73 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4299EFAA146AC94B00FF4A73 /* OpenAL.framework */; };
 		42CCD556146EC1EB00353661 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
 		42CD0DAB147D8EA80000361E /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA6147D8EA80000361E /* libbullet.a */; };
 		42CD0DAC147D8EA80000361E /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA7147D8EA80000361E /* libogg.a */; };
@@ -68,7 +85,7 @@
 		42CD0E6E147D8FF60000361E /* Frustum.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DDB147D8FF50000361E /* Frustum.h */; };
 		42CD0E6F147D8FF60000361E /* Game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDC147D8FF50000361E /* Game.cpp */; };
 		42CD0E70147D8FF60000361E /* Game.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DDD147D8FF50000361E /* Game.h */; };
-		42CD0E71147D8FF60000361E /* gameplay-main-macos.mm in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */; };
+		42CD0E71147D8FF60000361E /* gameplay-main-macosx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DDE147D8FF50000361E /* gameplay-main-macosx.mm */; };
 		42CD0E74147D8FF60000361E /* gameplay.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE1147D8FF50000361E /* gameplay.h */; };
 		42CD0E77147D8FF60000361E /* Joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DE4147D8FF50000361E /* Joint.cpp */; };
 		42CD0E78147D8FF60000361E /* Joint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DE5147D8FF50000361E /* Joint.h */; };
@@ -90,8 +107,6 @@
 		42CD0E88147D8FF60000361E /* Model.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF6147D8FF50000361E /* Model.h */; };
 		42CD0E89147D8FF60000361E /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF7147D8FF50000361E /* Node.cpp */; };
 		42CD0E8A147D8FF60000361E /* Node.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF8147D8FF50000361E /* Node.h */; };
-		42CD0E8B147D8FF60000361E /* Package.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF9147D8FF50000361E /* Package.cpp */; };
-		42CD0E8C147D8FF60000361E /* Package.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFA147D8FF50000361E /* Package.h */; };
 		42CD0E8D147D8FF60000361E /* ParticleEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */; };
 		42CD0E8E147D8FF60000361E /* ParticleEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFC147D8FF50000361E /* ParticleEmitter.h */; };
 		42CD0E8F147D8FF60000361E /* Pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFD147D8FF50000361E /* Pass.cpp */; };
@@ -117,7 +132,7 @@
 		42CD0EA3147D8FF60000361E /* Plane.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E16147D8FF50000361E /* Plane.cpp */; };
 		42CD0EA4147D8FF60000361E /* Plane.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E17147D8FF50000361E /* Plane.h */; };
 		42CD0EA5147D8FF60000361E /* Platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E19147D8FF50000361E /* Platform.h */; };
-		42CD0EA6147D8FF60000361E /* PlatformMacOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */; };
+		42CD0EA6147D8FF60000361E /* PlatformMacOSX.mm in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1A147D8FF50000361E /* PlatformMacOSX.mm */; };
 		42CD0EA9147D8FF60000361E /* Properties.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1D147D8FF50000361E /* Properties.cpp */; };
 		42CD0EAA147D8FF60000361E /* Properties.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E1E147D8FF50000361E /* Properties.h */; };
 		42CD0EAB147D8FF60000361E /* Quaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E1F147D8FF50000361E /* Quaternion.cpp */; };
@@ -152,8 +167,6 @@
 		42CD0EC8147D8FF60000361E /* VertexAttributeBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */; };
 		42CD0EC9147D8FF60000361E /* VertexFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E42147D8FF50000361E /* VertexFormat.cpp */; };
 		42CD0ECA147D8FF60000361E /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
-		42CD0ECB147D8FF60000361E /* Viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E44147D8FF50000361E /* Viewport.cpp */; };
-		42CD0ECC147D8FF60000361E /* Viewport.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E45147D8FF50000361E /* Viewport.h */; };
 		5B04C52D14BFCFE100EB0071 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB1147D8FF50000361E /* Animation.cpp */; };
 		5B04C52E14BFCFE100EB0071 /* AnimationClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB3147D8FF50000361E /* AnimationClip.cpp */; };
 		5B04C52F14BFCFE100EB0071 /* AnimationController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DB5147D8FF50000361E /* AnimationController.cpp */; };
@@ -185,7 +198,6 @@
 		5B04C54C14BFCFE100EB0071 /* MeshSkin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF3147D8FF50000361E /* MeshSkin.cpp */; };
 		5B04C54D14BFCFE100EB0071 /* Model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF5147D8FF50000361E /* Model.cpp */; };
 		5B04C54E14BFCFE100EB0071 /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF7147D8FF50000361E /* Node.cpp */; };
-		5B04C54F14BFCFE100EB0071 /* Package.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF9147D8FF50000361E /* Package.cpp */; };
 		5B04C55014BFCFE100EB0071 /* ParticleEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */; };
 		5B04C55114BFCFE100EB0071 /* Pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFD147D8FF50000361E /* Pass.cpp */; };
 		5B04C55214BFCFE100EB0071 /* PhysicsConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */; };
@@ -215,7 +227,6 @@
 		5B04C56D14BFCFE100EB0071 /* Vector4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E3D147D8FF50000361E /* Vector4.cpp */; };
 		5B04C56E14BFCFE100EB0071 /* VertexAttributeBinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E40147D8FF50000361E /* VertexAttributeBinding.cpp */; };
 		5B04C56F14BFCFE100EB0071 /* VertexFormat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E42147D8FF50000361E /* VertexFormat.cpp */; };
-		5B04C57014BFCFE100EB0071 /* Viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0E44147D8FF50000361E /* Viewport.cpp */; };
 		5B04C57114BFCFE100EB0071 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		5B04C57214BFCFE100EB0071 /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4208DEE614A4079F00D3C511 /* Image.cpp */; };
 		5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4201818D14A41B18008C3F56 /* MeshBatch.cpp */; };
@@ -258,7 +269,6 @@
 		5B04C59F14BFCFE100EB0071 /* MeshSkin.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF4147D8FF50000361E /* MeshSkin.h */; };
 		5B04C5A014BFCFE100EB0071 /* Model.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF6147D8FF50000361E /* Model.h */; };
 		5B04C5A114BFCFE100EB0071 /* Node.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF8147D8FF50000361E /* Node.h */; };
-		5B04C5A214BFCFE100EB0071 /* Package.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFA147D8FF50000361E /* Package.h */; };
 		5B04C5A314BFCFE100EB0071 /* ParticleEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFC147D8FF50000361E /* ParticleEmitter.h */; };
 		5B04C5A414BFCFE100EB0071 /* Pass.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFE147D8FF50000361E /* Pass.h */; };
 		5B04C5A514BFCFE100EB0071 /* PhysicsConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E00147D8FF50000361E /* PhysicsConstraint.h */; };
@@ -289,7 +299,6 @@
 		5B04C5BE14BFCFE100EB0071 /* Vector4.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E3E147D8FF50000361E /* Vector4.h */; };
 		5B04C5BF14BFCFE100EB0071 /* VertexAttributeBinding.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */; };
 		5B04C5C014BFCFE100EB0071 /* VertexFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E43147D8FF50000361E /* VertexFormat.h */; };
-		5B04C5C114BFCFE100EB0071 /* Viewport.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E45147D8FF50000361E /* Viewport.h */; };
 		5B04C5C214BFCFE100EB0071 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
 		5B04C5C314BFCFE100EB0071 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEE714A4079F00D3C511 /* Image.h */; };
 		5B04C5C414BFCFE100EB0071 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
@@ -297,13 +306,83 @@
 		5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4201818E14A41B18008C3F56 /* MeshBatch.h */; };
 		5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */; };
 		5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */; };
-		5B04C5F614BFE50100EB0071 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F514BFE50100EB0071 /* UIKit.framework */; };
-		5B04C5F814BFE50B00EB0071 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */; };
-		5B04C5FA14BFE51100EB0071 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F914BFE51000EB0071 /* OpenGLES.framework */; };
-		5B04C5FC14BFE51600EB0071 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5FB14BFE51600EB0071 /* OpenAL.framework */; };
-		5B5ADCE314C22DF900AC6109 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADCE214C22DF900AC6109 /* libz.dylib */; };
-		5B5ADCE514C22E1F00AC6109 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADCE414C22E1F00AC6109 /* libz.dylib */; };
-		5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADD2E14C2439700AC6109 /* Foundation.framework */; };
+		5B2BC75F1512514500D176CD /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC75D1512514500D176CD /* OpenAL.framework */; };
+		5B2BC7601512514500D176CD /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC75E1512514500D176CD /* OpenGL.framework */; };
+		5B2BC7621512514D00D176CD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC7611512514D00D176CD /* QuartzCore.framework */; };
+		5B2BC7641512516B00D176CD /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC7631512516B00D176CD /* libz.dylib */; };
+		5BAF201F152F2A6D003E2AC3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF201E152F2A6D003E2AC3 /* libz.dylib */; };
+		5BAF2027152F2AF0003E2AC3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2020152F2AF0003E2AC3 /* CoreGraphics.framework */; };
+		5BAF2028152F2AF0003E2AC3 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2021152F2AF0003E2AC3 /* CoreMotion.framework */; };
+		5BAF2029152F2AF0003E2AC3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2022152F2AF0003E2AC3 /* Foundation.framework */; };
+		5BAF202A152F2AF0003E2AC3 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2023152F2AF0003E2AC3 /* OpenAL.framework */; };
+		5BAF202B152F2AF0003E2AC3 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2024152F2AF0003E2AC3 /* OpenGLES.framework */; };
+		5BAF202C152F2AF0003E2AC3 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2025152F2AF0003E2AC3 /* QuartzCore.framework */; };
+		5BAF202D152F2AF0003E2AC3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BAF2026152F2AF0003E2AC3 /* UIKit.framework */; };
+		5BB0823D14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
+		5BB0823E14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
+		5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */; };
+		5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */; };
+		5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */; };
+		5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */; };
+		5BC4E73F150F843D00CBE1C0 /* AbsoluteLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */; };
+		5BC4E740150F843D00CBE1C0 /* AbsoluteLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52635150F822A004C9099 /* AbsoluteLayout.h */; };
+		5BC4E741150F843D00CBE1C0 /* Button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52636150F822A004C9099 /* Button.cpp */; };
+		5BC4E742150F843D00CBE1C0 /* Button.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52637150F822A004C9099 /* Button.h */; };
+		5BC4E743150F843D00CBE1C0 /* CheckBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52638150F822A004C9099 /* CheckBox.cpp */; };
+		5BC4E744150F843D00CBE1C0 /* CheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52639150F822A004C9099 /* CheckBox.h */; };
+		5BC4E745150F843D00CBE1C0 /* Container.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263A150F822A004C9099 /* Container.cpp */; };
+		5BC4E746150F843D00CBE1C0 /* Container.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263B150F822A004C9099 /* Container.h */; };
+		5BC4E747150F843D00CBE1C0 /* Control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263C150F822A004C9099 /* Control.cpp */; };
+		5BC4E748150F843D00CBE1C0 /* Control.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263D150F822A004C9099 /* Control.h */; };
+		5BC4E74A150F843D00CBE1C0 /* Form.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263F150F822A004C9099 /* Form.cpp */; };
+		5BC4E74B150F843D00CBE1C0 /* Form.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52640150F822A004C9099 /* Form.h */; };
+		5BC4E74C150F843D00CBE1C0 /* Label.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52641150F822A004C9099 /* Label.cpp */; };
+		5BC4E74D150F843D00CBE1C0 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52642150F822A004C9099 /* Label.h */; };
+		5BC4E74E150F843D00CBE1C0 /* Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52643150F822A004C9099 /* Layout.h */; };
+		5BC4E74F150F843D00CBE1C0 /* RadioButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52644150F822A004C9099 /* RadioButton.cpp */; };
+		5BC4E750150F843D00CBE1C0 /* RadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52645150F822A004C9099 /* RadioButton.h */; };
+		5BC4E751150F843D00CBE1C0 /* Slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52646150F822A004C9099 /* Slider.cpp */; };
+		5BC4E752150F843D00CBE1C0 /* Slider.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52647150F822A004C9099 /* Slider.h */; };
+		5BC4E753150F843D00CBE1C0 /* TextBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52648150F822A004C9099 /* TextBox.cpp */; };
+		5BC4E754150F843D00CBE1C0 /* TextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52649150F822A004C9099 /* TextBox.h */; };
+		5BC4E755150F843D00CBE1C0 /* Theme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264A150F822A004C9099 /* Theme.cpp */; };
+		5BC4E756150F843D00CBE1C0 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264B150F822A004C9099 /* Theme.h */; };
+		5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264D150F822A004C9099 /* VerticalLayout.cpp */; };
+		5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264E150F822A004C9099 /* VerticalLayout.h */; };
+		5BD5264F150F822A004C9099 /* AbsoluteLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */; };
+		5BD52650150F822A004C9099 /* AbsoluteLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52635150F822A004C9099 /* AbsoluteLayout.h */; };
+		5BD52651150F822A004C9099 /* Button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52636150F822A004C9099 /* Button.cpp */; };
+		5BD52652150F822A004C9099 /* Button.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52637150F822A004C9099 /* Button.h */; };
+		5BD52653150F822A004C9099 /* CheckBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52638150F822A004C9099 /* CheckBox.cpp */; };
+		5BD52654150F822A004C9099 /* CheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52639150F822A004C9099 /* CheckBox.h */; };
+		5BD52655150F822A004C9099 /* Container.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263A150F822A004C9099 /* Container.cpp */; };
+		5BD52656150F822A004C9099 /* Container.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263B150F822A004C9099 /* Container.h */; };
+		5BD52657150F822A004C9099 /* Control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263C150F822A004C9099 /* Control.cpp */; };
+		5BD52658150F822A004C9099 /* Control.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263D150F822A004C9099 /* Control.h */; };
+		5BD5265A150F822A004C9099 /* Form.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263F150F822A004C9099 /* Form.cpp */; };
+		5BD5265B150F822A004C9099 /* Form.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52640150F822A004C9099 /* Form.h */; };
+		5BD5265C150F822A004C9099 /* Label.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52641150F822A004C9099 /* Label.cpp */; };
+		5BD5265D150F822A004C9099 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52642150F822A004C9099 /* Label.h */; };
+		5BD5265E150F822A004C9099 /* Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52643150F822A004C9099 /* Layout.h */; };
+		5BD5265F150F822A004C9099 /* RadioButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52644150F822A004C9099 /* RadioButton.cpp */; };
+		5BD52660150F822A004C9099 /* RadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52645150F822A004C9099 /* RadioButton.h */; };
+		5BD52661150F822A004C9099 /* Slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52646150F822A004C9099 /* Slider.cpp */; };
+		5BD52662150F822A004C9099 /* Slider.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52647150F822A004C9099 /* Slider.h */; };
+		5BD52663150F822A004C9099 /* TextBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52648150F822A004C9099 /* TextBox.cpp */; };
+		5BD52664150F822A004C9099 /* TextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52649150F822A004C9099 /* TextBox.h */; };
+		5BD52665150F822A004C9099 /* Theme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264A150F822A004C9099 /* Theme.cpp */; };
+		5BD52666150F822A004C9099 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264B150F822A004C9099 /* Theme.h */; };
+		5BD52667150F822A004C9099 /* TimeListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264C150F822A004C9099 /* TimeListener.h */; };
+		5BD52668150F822A004C9099 /* VerticalLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264D150F822A004C9099 /* VerticalLayout.cpp */; };
+		5BD52669150F822A004C9099 /* VerticalLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264E150F822A004C9099 /* VerticalLayout.h */; };
+		5BD5266F150F8258004C9099 /* PhysicsCharacter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */; };
+		5BD52670150F8258004C9099 /* PhysicsCharacter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */; };
+		5BD52671150F8258004C9099 /* PhysicsCharacter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266C150F8257004C9099 /* PhysicsCharacter.h */; };
+		5BD52672150F8258004C9099 /* PhysicsCharacter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266C150F8257004C9099 /* PhysicsCharacter.h */; };
+		5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
+		5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
+		5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
+		5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -316,20 +395,27 @@
 		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; };
+		422260D41537790F0011E3AB /* Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Bundle.cpp; path = src/Bundle.cpp; sourceTree = SOURCE_ROOT; };
+		422260D51537790F0011E3AB /* Bundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Bundle.h; path = src/Bundle.h; sourceTree = SOURCE_ROOT; };
 		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; };
+		4251B12E152D049B002F6199 /* ScreenDisplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenDisplayer.h; path = src/ScreenDisplayer.h; sourceTree = SOURCE_ROOT; };
+		4251B12F152D049B002F6199 /* ThemeStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThemeStyle.cpp; path = src/ThemeStyle.cpp; sourceTree = SOURCE_ROOT; };
+		4251B130152D049B002F6199 /* ThemeStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThemeStyle.h; path = src/ThemeStyle.h; sourceTree = SOURCE_ROOT; };
+		42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionShape.cpp; path = src/PhysicsCollisionShape.cpp; sourceTree = SOURCE_ROOT; };
+		42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionShape.h; path = src/PhysicsCollisionShape.h; sourceTree = SOURCE_ROOT; };
+		426878AA153F4BB300844500 /* FlowLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FlowLayout.cpp; path = src/FlowLayout.cpp; sourceTree = SOURCE_ROOT; };
+		426878AB153F4BB300844500 /* FlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FlowLayout.h; path = src/FlowLayout.h; sourceTree = SOURCE_ROOT; };
+		4271C08D15337C8200B89DA7 /* Layout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Layout.cpp; path = src/Layout.cpp; sourceTree = SOURCE_ROOT; };
 		428390971489D6E800E2B2F5 /* SceneLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SceneLoader.cpp; path = src/SceneLoader.cpp; sourceTree = SOURCE_ROOT; };
 		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; };
-		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>"; };
-		42CD0DA7147D8EA80000361E /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "../external-deps/oggvorbis/lib/macos/libogg.a"; sourceTree = "<group>"; };
-		42CD0DA8147D8EA80000361E /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "../external-deps/oggvorbis/lib/macos/libvorbis.a"; sourceTree = "<group>"; };
-		42CD0DA9147D8EA80000361E /* libvorbisenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisenc.a; path = "../external-deps/oggvorbis/lib/macos/libvorbisenc.a"; sourceTree = "<group>"; };
-		42CD0DAA147D8EA80000361E /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "../external-deps/oggvorbis/lib/macos/libvorbisfile.a"; sourceTree = "<group>"; };
+		42CCD555146EC1EB00353661 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macosx/libpng.a"; sourceTree = "<group>"; };
+		42CD0DA6147D8EA80000361E /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/macosx/libbullet.a"; sourceTree = "<group>"; };
+		42CD0DA7147D8EA80000361E /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "../external-deps/oggvorbis/lib/macosx/libogg.a"; sourceTree = "<group>"; };
+		42CD0DA8147D8EA80000361E /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "../external-deps/oggvorbis/lib/macosx/libvorbis.a"; sourceTree = "<group>"; };
+		42CD0DA9147D8EA80000361E /* libvorbisenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisenc.a; path = "../external-deps/oggvorbis/lib/macosx/libvorbisenc.a"; sourceTree = "<group>"; };
+		42CD0DAA147D8EA80000361E /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "../external-deps/oggvorbis/lib/macosx/libvorbisfile.a"; sourceTree = "<group>"; };
 		42CD0DB1147D8FF50000361E /* Animation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Animation.cpp; path = src/Animation.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DB2147D8FF50000361E /* Animation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Animation.h; path = src/Animation.h; sourceTree = SOURCE_ROOT; };
 		42CD0DB3147D8FF50000361E /* AnimationClip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnimationClip.cpp; path = src/AnimationClip.cpp; sourceTree = SOURCE_ROOT; };
@@ -375,7 +461,7 @@
 		42CD0DDB147D8FF50000361E /* Frustum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Frustum.h; path = src/Frustum.h; sourceTree = SOURCE_ROOT; };
 		42CD0DDC147D8FF50000361E /* Game.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Game.cpp; path = src/Game.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DDD147D8FF50000361E /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Game.h; path = src/Game.h; sourceTree = SOURCE_ROOT; };
-		42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-macos.mm"; path = "src/gameplay-main-macos.mm"; sourceTree = SOURCE_ROOT; };
+		42CD0DDE147D8FF50000361E /* gameplay-main-macosx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-macosx.mm"; path = "src/gameplay-main-macosx.mm"; sourceTree = SOURCE_ROOT; };
 		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; };
@@ -400,8 +486,6 @@
 		42CD0DF6147D8FF50000361E /* Model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Model.h; path = src/Model.h; sourceTree = SOURCE_ROOT; };
 		42CD0DF7147D8FF50000361E /* Node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Node.cpp; path = src/Node.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DF8147D8FF50000361E /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Node.h; path = src/Node.h; sourceTree = SOURCE_ROOT; };
-		42CD0DF9147D8FF50000361E /* Package.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Package.cpp; path = src/Package.cpp; sourceTree = SOURCE_ROOT; };
-		42CD0DFA147D8FF50000361E /* Package.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Package.h; path = src/Package.h; sourceTree = SOURCE_ROOT; };
 		42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ParticleEmitter.cpp; path = src/ParticleEmitter.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DFC147D8FF50000361E /* ParticleEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ParticleEmitter.h; path = src/ParticleEmitter.h; sourceTree = SOURCE_ROOT; };
 		42CD0DFD147D8FF50000361E /* Pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Pass.cpp; path = src/Pass.cpp; sourceTree = SOURCE_ROOT; };
@@ -433,7 +517,7 @@
 		42CD0E17147D8FF50000361E /* Plane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Plane.h; path = src/Plane.h; sourceTree = SOURCE_ROOT; };
 		42CD0E18147D8FF50000361E /* Plane.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Plane.inl; path = src/Plane.inl; sourceTree = SOURCE_ROOT; };
 		42CD0E19147D8FF50000361E /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Platform.h; path = src/Platform.h; sourceTree = SOURCE_ROOT; };
-		42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformMacOS.mm; path = src/PlatformMacOS.mm; sourceTree = SOURCE_ROOT; };
+		42CD0E1A147D8FF50000361E /* PlatformMacOSX.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformMacOSX.mm; path = src/PlatformMacOSX.mm; sourceTree = SOURCE_ROOT; };
 		42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformQNX.cpp; path = src/PlatformQNX.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformWin32.cpp; path = src/PlatformWin32.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0E1D147D8FF50000361E /* Properties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Properties.cpp; path = src/Properties.cpp; sourceTree = SOURCE_ROOT; };
@@ -475,28 +559,65 @@
 		42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexAttributeBinding.h; path = src/VertexAttributeBinding.h; sourceTree = SOURCE_ROOT; };
 		42CD0E42147D8FF50000361E /* VertexFormat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VertexFormat.cpp; path = src/VertexFormat.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0E43147D8FF50000361E /* VertexFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VertexFormat.h; path = src/VertexFormat.h; sourceTree = SOURCE_ROOT; };
-		42CD0E44147D8FF50000361E /* Viewport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Viewport.cpp; path = src/Viewport.cpp; sourceTree = SOURCE_ROOT; };
-		42CD0E45147D8FF50000361E /* Viewport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Viewport.h; path = src/Viewport.h; sourceTree = SOURCE_ROOT; };
 		5B04C5CA14BFCFE100EB0071 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
 		5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformiOS.mm; path = src/PlatformiOS.mm; sourceTree = SOURCE_ROOT; };
-		5B04C5F514BFE50100EB0071 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
-		5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
-		5B04C5F914BFE51000EB0071 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
-		5B04C5FB14BFE51600EB0071 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
-		5B3383A214C5181E000DC4F8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
-		5B3383A414C5181E000DC4F8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
-		5B3383A614C5181E000DC4F8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
-		5B43D17914C3497B008A5D9D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
-		5B5ADCE214C22DF900AC6109 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.7.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
-		5B5ADCE414C22E1F00AC6109 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
-		5B5ADD2E14C2439700AC6109 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC75D1512514500D176CD /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
+		5B2BC75E1512514500D176CD /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		5B2BC7611512514D00D176CD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		5B2BC7631512516B00D176CD /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = "<absolute>"; };
+		5B2BC768151251EB00D176CD /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
 		5B5DB92D14C25B7B007755DB /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/ios/i386/libbullet.a"; sourceTree = "<group>"; };
 		5B5DB92F14C25B94007755DB /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/ios/armv7/libpng.a"; sourceTree = "<group>"; };
 		5B5DB93114C25BA5007755DB /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libogg.a"; sourceTree = "<group>"; };
 		5B5DB93214C25BA5007755DB /* libvorbis.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbis.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libvorbis.a"; sourceTree = "<group>"; };
 		5B5DB93314C25BA5007755DB /* libvorbisenc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisenc.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libvorbisenc.a"; sourceTree = "<group>"; };
 		5B5DB93414C25BA5007755DB /* libvorbisfile.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libvorbisfile.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libvorbisfile.a"; sourceTree = "<group>"; };
+		5BAF201E152F2A6D003E2AC3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+		5BAF2020152F2AF0003E2AC3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2021152F2AF0003E2AC3 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2022152F2AF0003E2AC3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2023152F2AF0003E2AC3 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2024152F2AF0003E2AC3 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2025152F2AF0003E2AC3 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
+		5BAF2026152F2AF0003E2AC3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gameplay-main-android.cpp"; path = "src/gameplay-main-android.cpp"; sourceTree = SOURCE_ROOT; };
+		5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformAndroid.cpp; path = src/PlatformAndroid.cpp; sourceTree = SOURCE_ROOT; };
+		5BB0823C14C6FEC40019975F /* Mouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mouse.h; path = src/Mouse.h; sourceTree = SOURCE_ROOT; };
+		5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsGhostObject.cpp; path = src/PhysicsGhostObject.cpp; sourceTree = SOURCE_ROOT; };
+		5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsGhostObject.h; path = src/PhysicsGhostObject.h; sourceTree = SOURCE_ROOT; };
+		5BC4E7D4150F8C3C00CBE1C0 /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
+		5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AbsoluteLayout.cpp; path = src/AbsoluteLayout.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52635150F822A004C9099 /* AbsoluteLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AbsoluteLayout.h; path = src/AbsoluteLayout.h; sourceTree = SOURCE_ROOT; };
+		5BD52636150F822A004C9099 /* Button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Button.cpp; path = src/Button.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52637150F822A004C9099 /* Button.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Button.h; path = src/Button.h; sourceTree = SOURCE_ROOT; };
+		5BD52638150F822A004C9099 /* CheckBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckBox.cpp; path = src/CheckBox.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52639150F822A004C9099 /* CheckBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CheckBox.h; path = src/CheckBox.h; sourceTree = SOURCE_ROOT; };
+		5BD5263A150F822A004C9099 /* Container.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Container.cpp; path = src/Container.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5263B150F822A004C9099 /* Container.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Container.h; path = src/Container.h; sourceTree = SOURCE_ROOT; };
+		5BD5263C150F822A004C9099 /* Control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Control.cpp; path = src/Control.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5263D150F822A004C9099 /* Control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Control.h; path = src/Control.h; sourceTree = SOURCE_ROOT; };
+		5BD5263F150F822A004C9099 /* Form.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Form.cpp; path = src/Form.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52640150F822A004C9099 /* Form.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Form.h; path = src/Form.h; sourceTree = SOURCE_ROOT; };
+		5BD52641150F822A004C9099 /* Label.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Label.cpp; path = src/Label.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52642150F822A004C9099 /* Label.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Label.h; path = src/Label.h; sourceTree = SOURCE_ROOT; };
+		5BD52643150F822A004C9099 /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Layout.h; path = src/Layout.h; sourceTree = SOURCE_ROOT; };
+		5BD52644150F822A004C9099 /* RadioButton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RadioButton.cpp; path = src/RadioButton.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52645150F822A004C9099 /* RadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RadioButton.h; path = src/RadioButton.h; sourceTree = SOURCE_ROOT; };
+		5BD52646150F822A004C9099 /* Slider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Slider.cpp; path = src/Slider.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52647150F822A004C9099 /* Slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Slider.h; path = src/Slider.h; sourceTree = SOURCE_ROOT; };
+		5BD52648150F822A004C9099 /* TextBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextBox.cpp; path = src/TextBox.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52649150F822A004C9099 /* TextBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextBox.h; path = src/TextBox.h; sourceTree = SOURCE_ROOT; };
+		5BD5264A150F822A004C9099 /* Theme.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Theme.cpp; path = src/Theme.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5264B150F822A004C9099 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = src/Theme.h; sourceTree = SOURCE_ROOT; };
+		5BD5264C150F822A004C9099 /* TimeListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeListener.h; path = src/TimeListener.h; sourceTree = SOURCE_ROOT; };
+		5BD5264D150F822A004C9099 /* VerticalLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerticalLayout.cpp; path = src/VerticalLayout.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5264E150F822A004C9099 /* VerticalLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VerticalLayout.h; path = src/VerticalLayout.h; sourceTree = SOURCE_ROOT; };
+		5BD5266A150F8257004C9099 /* gameplay.dox */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = gameplay.dox; path = src/gameplay.dox; sourceTree = SOURCE_ROOT; };
+		5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCharacter.cpp; path = src/PhysicsCharacter.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5266C150F8257004C9099 /* PhysicsCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCharacter.h; path = src/PhysicsCharacter.h; sourceTree = SOURCE_ROOT; };
+		5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionObject.cpp; path = src/PhysicsCollisionObject.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionObject.h; path = src/PhysicsCollisionObject.h; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -504,7 +625,10 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5B5ADCE314C22DF900AC6109 /* libz.dylib in Frameworks */,
+				5B2BC7641512516B00D176CD /* libz.dylib in Frameworks */,
+				5B2BC7621512514D00D176CD /* QuartzCore.framework in Frameworks */,
+				5B2BC75F1512514500D176CD /* OpenAL.framework in Frameworks */,
+				5B2BC7601512514500D176CD /* OpenGL.framework in Frameworks */,
 				42CD0DAB147D8EA80000361E /* libbullet.a in Frameworks */,
 				42CD0DAC147D8EA80000361E /* libogg.a in Frameworks */,
 				42CD0DAD147D8EA80000361E /* libvorbis.a in Frameworks */,
@@ -512,9 +636,6 @@
 				42CD0DAF147D8EA80000361E /* libvorbisfile.a in Frameworks */,
 				42CCD556146EC1EB00353661 /* libpng.a in Frameworks */,
 				4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */,
-				4220A6E8146B122B00CAEB3A /* QuartzCore.framework in Frameworks */,
-				4299EFA9146AC94300FF4A73 /* OpenGL.framework in Frameworks */,
-				4299EFAB146AC94B00FF4A73 /* OpenAL.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -522,12 +643,14 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */,
-				5B5ADCE514C22E1F00AC6109 /* libz.dylib in Frameworks */,
-				5B04C5FC14BFE51600EB0071 /* OpenAL.framework in Frameworks */,
-				5B04C5FA14BFE51100EB0071 /* OpenGLES.framework in Frameworks */,
-				5B04C5F814BFE50B00EB0071 /* QuartzCore.framework in Frameworks */,
-				5B04C5F614BFE50100EB0071 /* UIKit.framework in Frameworks */,
+				5BAF2027152F2AF0003E2AC3 /* CoreGraphics.framework in Frameworks */,
+				5BAF2028152F2AF0003E2AC3 /* CoreMotion.framework in Frameworks */,
+				5BAF2029152F2AF0003E2AC3 /* Foundation.framework in Frameworks */,
+				5BAF202A152F2AF0003E2AC3 /* OpenAL.framework in Frameworks */,
+				5BAF202B152F2AF0003E2AC3 /* OpenGLES.framework in Frameworks */,
+				5BAF202C152F2AF0003E2AC3 /* QuartzCore.framework in Frameworks */,
+				5BAF202D152F2AF0003E2AC3 /* UIKit.framework in Frameworks */,
+				5BAF201F152F2A6D003E2AC3 /* libz.dylib in Frameworks */,
 				5B04C57514BFCFE100EB0071 /* libbullet.a in Frameworks */,
 				5B04C57614BFCFE100EB0071 /* libogg.a in Frameworks */,
 				5B04C57714BFCFE100EB0071 /* libvorbis.a in Frameworks */,
@@ -543,6 +666,7 @@
 		4234D98A14686BB6003031B3 = {
 			isa = PBXGroup;
 			children = (
+				5BC4E7D4150F8C3C00CBE1C0 /* res */,
 				4234D9A314686C52003031B3 /* src */,
 				427D4F42147DC8DE0076760E /* Libraries */,
 				42CCD4AF146D811D00353661 /* Frameworks */,
@@ -562,83 +686,8 @@
 		4234D9A314686C52003031B3 /* src */ = {
 			isa = PBXGroup;
 			children = (
-				5B43D19714C35347008A5D9D /* gameplay */,
-				5B43D19614C35344008A5D9D /* platform */,
-			);
-			name = src;
-			path = gameplay;
-			sourceTree = "<group>";
-		};
-		427D4F42147DC8DE0076760E /* Libraries */ = {
-			isa = PBXGroup;
-			children = (
-				42CD0DA6147D8EA80000361E /* libbullet.a */,
-				42CD0DA7147D8EA80000361E /* libogg.a */,
-				42CD0DA8147D8EA80000361E /* libvorbis.a */,
-				42CD0DA9147D8EA80000361E /* libvorbisenc.a */,
-				42CD0DAA147D8EA80000361E /* libvorbisfile.a */,
-				42CCD555146EC1EB00353661 /* libpng.a */,
-				5B5ADCE114C22DC700AC6109 /* Mac OS X */,
-				5B5ADCE014C22DBE00AC6109 /* iOS */,
-			);
-			name = Libraries;
-			sourceTree = "<group>";
-		};
-		42CCD4AF146D811D00353661 /* Frameworks */ = {
-			isa = PBXGroup;
-			children = (
-				5B04C5FE14BFE52F00EB0071 /* Mac OS X */,
-				5B04C5FD14BFE52300EB0071 /* iOS */,
-				5B3383A214C5181E000DC4F8 /* UIKit.framework */,
-				5B3383A414C5181E000DC4F8 /* Foundation.framework */,
-				5B3383A614C5181E000DC4F8 /* CoreGraphics.framework */,
-			);
-			name = Frameworks;
-			sourceTree = "<group>";
-		};
-		5B04C5FD14BFE52300EB0071 /* iOS */ = {
-			isa = PBXGroup;
-			children = (
-				5B43D17914C3497B008A5D9D /* CoreGraphics.framework */,
-				5B5ADD2E14C2439700AC6109 /* Foundation.framework */,
-				5B04C5FB14BFE51600EB0071 /* OpenAL.framework */,
-				5B04C5F914BFE51000EB0071 /* OpenGLES.framework */,
-				5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */,
-				5B04C5F514BFE50100EB0071 /* UIKit.framework */,
-			);
-			name = iOS;
-			sourceTree = "<group>";
-		};
-		5B04C5FE14BFE52F00EB0071 /* Mac OS X */ = {
-			isa = PBXGroup;
-			children = (
-				4234D99D14686C52003031B3 /* Cocoa.framework */,
-				4220A6E7146B122B00CAEB3A /* QuartzCore.framework */,
-				4299EFA8146AC94300FF4A73 /* OpenGL.framework */,
-				4299EFAA146AC94B00FF4A73 /* OpenAL.framework */,
-			);
-			name = "Mac OS X";
-			sourceTree = "<group>";
-		};
-		5B43D19614C35344008A5D9D /* platform */ = {
-			isa = PBXGroup;
-			children = (
-				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
-				42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */,
-				5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */,
-				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
-				42CD0E19147D8FF50000361E /* Platform.h */,
-				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
-				42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */,
-				5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */,
-				42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */,
-			);
-			name = platform;
-			sourceTree = "<group>";
-		};
-		5B43D19714C35347008A5D9D /* gameplay */ = {
-			isa = PBXGroup;
-			children = (
+				5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */,
+				5BD52635150F822A004C9099 /* AbsoluteLayout.h */,
 				42CD0DB1147D8FF50000361E /* Animation.cpp */,
 				42CD0DB2147D8FF50000361E /* Animation.h */,
 				42CD0DB3147D8FF50000361E /* AnimationClip.cpp */,
@@ -664,8 +713,18 @@
 				42CD0DC7147D8FF50000361E /* BoundingSphere.cpp */,
 				42CD0DC8147D8FF50000361E /* BoundingSphere.h */,
 				42CD0DC9147D8FF50000361E /* BoundingSphere.inl */,
+				422260D41537790F0011E3AB /* Bundle.cpp */,
+				422260D51537790F0011E3AB /* Bundle.h */,
+				5BD52636150F822A004C9099 /* Button.cpp */,
+				5BD52637150F822A004C9099 /* Button.h */,
 				42CD0DCA147D8FF50000361E /* Camera.cpp */,
 				42CD0DCB147D8FF50000361E /* Camera.h */,
+				5BD52638150F822A004C9099 /* CheckBox.cpp */,
+				5BD52639150F822A004C9099 /* CheckBox.h */,
+				5BD5263A150F822A004C9099 /* Container.cpp */,
+				5BD5263B150F822A004C9099 /* Container.h */,
+				5BD5263C150F822A004C9099 /* Control.cpp */,
+				5BD5263D150F822A004C9099 /* Control.h */,
 				42CD0DCC147D8FF50000361E /* Curve.cpp */,
 				42CD0DCD147D8FF50000361E /* Curve.h */,
 				4208DEE514A4078100D3C511 /* Curve.inl */,
@@ -677,8 +736,12 @@
 				42CD0DD3147D8FF50000361E /* Effect.h */,
 				42CD0DD4147D8FF50000361E /* FileSystem.cpp */,
 				42CD0DD5147D8FF50000361E /* FileSystem.h */,
+				426878AA153F4BB300844500 /* FlowLayout.cpp */,
+				426878AB153F4BB300844500 /* FlowLayout.h */,
 				42CD0DD6147D8FF50000361E /* Font.cpp */,
 				42CD0DD7147D8FF50000361E /* Font.h */,
+				5BD5263F150F822A004C9099 /* Form.cpp */,
+				5BD52640150F822A004C9099 /* Form.h */,
 				42CD0DD8147D8FF50000361E /* FrameBuffer.cpp */,
 				42CD0DD9147D8FF50000361E /* FrameBuffer.h */,
 				42CD0DDA147D8FF50000361E /* Frustum.cpp */,
@@ -686,13 +749,23 @@
 				42CD0DDC147D8FF50000361E /* Game.cpp */,
 				42CD0DDD147D8FF50000361E /* Game.h */,
 				42C932AF14919FD10098216A /* Game.inl */,
+				5BD5266A150F8257004C9099 /* gameplay.dox */,
 				42CD0DE1147D8FF50000361E /* gameplay.h */,
+				5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */,
+				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
+				42CD0DDE147D8FF50000361E /* gameplay-main-macosx.mm */,
+				5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */,
+				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
 				4208DEE614A4079F00D3C511 /* Image.cpp */,
 				4208DEE714A4079F00D3C511 /* Image.h */,
 				4208DEE814A4079F00D3C511 /* Image.inl */,
 				42CD0DE4147D8FF50000361E /* Joint.cpp */,
 				42CD0DE5147D8FF50000361E /* Joint.h */,
 				4208DEEB14A407B900D3C511 /* Keyboard.h */,
+				5BD52641150F822A004C9099 /* Label.cpp */,
+				5BD52642150F822A004C9099 /* Label.h */,
+				4271C08D15337C8200B89DA7 /* Layout.cpp */,
+				5BD52643150F822A004C9099 /* Layout.h */,
 				42CD0DE6147D8FF50000361E /* Light.cpp */,
 				42CD0DE7147D8FF50000361E /* Light.h */,
 				42CD0DE8147D8FF50000361E /* Material.cpp */,
@@ -713,14 +786,22 @@
 				42CD0DF4147D8FF50000361E /* MeshSkin.h */,
 				42CD0DF5147D8FF50000361E /* Model.cpp */,
 				42CD0DF6147D8FF50000361E /* Model.h */,
+				5BB0823C14C6FEC40019975F /* Mouse.h */,
 				42CD0DF7147D8FF50000361E /* Node.cpp */,
 				42CD0DF8147D8FF50000361E /* Node.h */,
-				42CD0DF9147D8FF50000361E /* Package.cpp */,
-				42CD0DFA147D8FF50000361E /* Package.h */,
 				42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */,
 				42CD0DFC147D8FF50000361E /* ParticleEmitter.h */,
 				42CD0DFD147D8FF50000361E /* Pass.cpp */,
 				42CD0DFE147D8FF50000361E /* Pass.h */,
+				42CD0E16147D8FF50000361E /* Plane.cpp */,
+				42CD0E17147D8FF50000361E /* Plane.h */,
+				42CD0E18147D8FF50000361E /* Plane.inl */,
+				5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */,
+				5BD5266C150F8257004C9099 /* PhysicsCharacter.h */,
+				5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */,
+				5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */,
+				42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */,
+				42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */,
 				42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */,
 				42CD0E00147D8FF50000361E /* PhysicsConstraint.h */,
 				42CD0E01147D8FF50000361E /* PhysicsConstraint.inl */,
@@ -734,6 +815,8 @@
 				42CD0E09147D8FF50000361E /* PhysicsGenericConstraint.inl */,
 				42CD0E0A147D8FF50000361E /* PhysicsHingeConstraint.cpp */,
 				42CD0E0B147D8FF50000361E /* PhysicsHingeConstraint.h */,
+				5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */,
+				5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */,
 				42CD0E0C147D8FF50000361E /* PhysicsMotionState.cpp */,
 				42CD0E0D147D8FF50000361E /* PhysicsMotionState.h */,
 				42CD0E0E147D8FF50000361E /* PhysicsRigidBody.cpp */,
@@ -744,14 +827,19 @@
 				42CD0E13147D8FF50000361E /* PhysicsSpringConstraint.cpp */,
 				42CD0E14147D8FF50000361E /* PhysicsSpringConstraint.h */,
 				42CD0E15147D8FF50000361E /* PhysicsSpringConstraint.inl */,
-				42CD0E16147D8FF50000361E /* Plane.cpp */,
-				42CD0E17147D8FF50000361E /* Plane.h */,
-				42CD0E18147D8FF50000361E /* Plane.inl */,
+				42CD0E19147D8FF50000361E /* Platform.h */,
+				5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */,
+				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
+				42CD0E1A147D8FF50000361E /* PlatformMacOSX.mm */,
+				5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */,
+				42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */,
 				42CD0E1D147D8FF50000361E /* Properties.cpp */,
 				42CD0E1E147D8FF50000361E /* Properties.h */,
 				42CD0E1F147D8FF50000361E /* Quaternion.cpp */,
 				42CD0E20147D8FF50000361E /* Quaternion.h */,
 				42CD0E21147D8FF50000361E /* Quaternion.inl */,
+				5BD52644150F822A004C9099 /* RadioButton.cpp */,
+				5BD52645150F822A004C9099 /* RadioButton.h */,
 				42CD0E22147D8FF50000361E /* Ray.cpp */,
 				42CD0E23147D8FF50000361E /* Ray.h */,
 				42CD0E24147D8FF50000361E /* Ray.inl */,
@@ -767,12 +855,22 @@
 				42CD0E2E147D8FF50000361E /* Scene.h */,
 				428390971489D6E800E2B2F5 /* SceneLoader.cpp */,
 				428390981489D6E800E2B2F5 /* SceneLoader.h */,
+				4251B12E152D049B002F6199 /* ScreenDisplayer.h */,
+				5BD52646150F822A004C9099 /* Slider.cpp */,
+				5BD52647150F822A004C9099 /* Slider.h */,
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
 				42CD0E30147D8FF50000361E /* SpriteBatch.h */,
 				42CD0E31147D8FF50000361E /* Technique.cpp */,
 				42CD0E32147D8FF50000361E /* Technique.h */,
 				42CD0E33147D8FF50000361E /* Texture.cpp */,
 				42CD0E34147D8FF50000361E /* Texture.h */,
+				5BD52648150F822A004C9099 /* TextBox.cpp */,
+				5BD52649150F822A004C9099 /* TextBox.h */,
+				5BD5264C150F822A004C9099 /* TimeListener.h */,
+				5BD5264A150F822A004C9099 /* Theme.cpp */,
+				5BD5264B150F822A004C9099 /* Theme.h */,
+				4251B12F152D049B002F6199 /* ThemeStyle.cpp */,
+				4251B130152D049B002F6199 /* ThemeStyle.h */,
 				4208DEED14A407D500D3C511 /* Touch.h */,
 				42CD0E35147D8FF50000361E /* Transform.cpp */,
 				42CD0E36147D8FF50000361E /* Transform.h */,
@@ -789,10 +887,61 @@
 				42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */,
 				42CD0E42147D8FF50000361E /* VertexFormat.cpp */,
 				42CD0E43147D8FF50000361E /* VertexFormat.h */,
-				42CD0E44147D8FF50000361E /* Viewport.cpp */,
-				42CD0E45147D8FF50000361E /* Viewport.h */,
+				5BD5264D150F822A004C9099 /* VerticalLayout.cpp */,
+				5BD5264E150F822A004C9099 /* VerticalLayout.h */,
+			);
+			name = src;
+			path = gameplay;
+			sourceTree = "<group>";
+		};
+		427D4F42147DC8DE0076760E /* Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				42CD0DA6147D8EA80000361E /* libbullet.a */,
+				42CD0DA7147D8EA80000361E /* libogg.a */,
+				42CD0DA8147D8EA80000361E /* libvorbis.a */,
+				42CD0DA9147D8EA80000361E /* libvorbisenc.a */,
+				42CD0DAA147D8EA80000361E /* libvorbisfile.a */,
+				42CCD555146EC1EB00353661 /* libpng.a */,
+				5B5ADCE114C22DC700AC6109 /* MacOSX */,
+				5B5ADCE014C22DBE00AC6109 /* iOS */,
+			);
+			name = Libraries;
+			sourceTree = "<group>";
+		};
+		42CCD4AF146D811D00353661 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				5B04C5FD14BFE52300EB0071 /* iOS */,
+				5B04C5FE14BFE52F00EB0071 /* MacOSX */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		5B04C5FD14BFE52300EB0071 /* iOS */ = {
+			isa = PBXGroup;
+			children = (
+				5BAF201E152F2A6D003E2AC3 /* libz.dylib */,
+				5BAF2020152F2AF0003E2AC3 /* CoreGraphics.framework */,
+				5BAF2021152F2AF0003E2AC3 /* CoreMotion.framework */,
+				5BAF2022152F2AF0003E2AC3 /* Foundation.framework */,
+				5BAF2023152F2AF0003E2AC3 /* OpenAL.framework */,
+				5BAF2024152F2AF0003E2AC3 /* OpenGLES.framework */,
+				5BAF2025152F2AF0003E2AC3 /* QuartzCore.framework */,
+				5BAF2026152F2AF0003E2AC3 /* UIKit.framework */,
+			);
+			name = iOS;
+			sourceTree = "<group>";
+		};
+		5B04C5FE14BFE52F00EB0071 /* MacOSX */ = {
+			isa = PBXGroup;
+			children = (
+				5B2BC7611512514D00D176CD /* QuartzCore.framework */,
+				5B2BC75D1512514500D176CD /* OpenAL.framework */,
+				5B2BC75E1512514500D176CD /* OpenGL.framework */,
+				4234D99D14686C52003031B3 /* Cocoa.framework */,
 			);
-			name = gameplay;
+			name = MacOSX;
 			sourceTree = "<group>";
 		};
 		5B5ADCE014C22DBE00AC6109 /* iOS */ = {
@@ -804,17 +953,17 @@
 				5B5DB93414C25BA5007755DB /* libvorbisfile.a */,
 				5B5DB92F14C25B94007755DB /* libpng.a */,
 				5B5DB92D14C25B7B007755DB /* libbullet.a */,
-				5B5ADCE414C22E1F00AC6109 /* libz.dylib */,
+				5B2BC768151251EB00D176CD /* libz.dylib */,
 			);
 			name = iOS;
 			sourceTree = "<group>";
 		};
-		5B5ADCE114C22DC700AC6109 /* Mac OS X */ = {
+		5B5ADCE114C22DC700AC6109 /* MacOSX */ = {
 			isa = PBXGroup;
 			children = (
-				5B5ADCE214C22DF900AC6109 /* libz.dylib */,
+				5B2BC7631512516B00D176CD /* libz.dylib */,
 			);
-			name = "Mac OS X";
+			name = MacOSX;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -857,7 +1006,6 @@
 				42CD0E86147D8FF60000361E /* MeshSkin.h in Headers */,
 				42CD0E88147D8FF60000361E /* Model.h in Headers */,
 				42CD0E8A147D8FF60000361E /* Node.h in Headers */,
-				42CD0E8C147D8FF60000361E /* Package.h in Headers */,
 				42CD0E8E147D8FF60000361E /* ParticleEmitter.h in Headers */,
 				42CD0E90147D8FF60000361E /* Pass.h in Headers */,
 				42CD0E92147D8FF60000361E /* PhysicsConstraint.h in Headers */,
@@ -888,12 +1036,34 @@
 				42CD0EC6147D8FF60000361E /* Vector4.h in Headers */,
 				42CD0EC8147D8FF60000361E /* VertexAttributeBinding.h in Headers */,
 				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 */,
+				5BB0823D14C6FEC40019975F /* Mouse.h in Headers */,
+				5BD52650150F822A004C9099 /* AbsoluteLayout.h in Headers */,
+				5BD52652150F822A004C9099 /* Button.h in Headers */,
+				5BD52654150F822A004C9099 /* CheckBox.h in Headers */,
+				5BD52656150F822A004C9099 /* Container.h in Headers */,
+				5BD52658150F822A004C9099 /* Control.h in Headers */,
+				5BD5265B150F822A004C9099 /* Form.h in Headers */,
+				5BD5265D150F822A004C9099 /* Label.h in Headers */,
+				5BD5265E150F822A004C9099 /* Layout.h in Headers */,
+				5BD52660150F822A004C9099 /* RadioButton.h in Headers */,
+				5BD52662150F822A004C9099 /* Slider.h in Headers */,
+				5BD52664150F822A004C9099 /* TextBox.h in Headers */,
+				5BD52666150F822A004C9099 /* Theme.h in Headers */,
+				5BD52667150F822A004C9099 /* TimeListener.h in Headers */,
+				5BD52669150F822A004C9099 /* VerticalLayout.h in Headers */,
+				5BD52671150F8258004C9099 /* PhysicsCharacter.h in Headers */,
+				5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
+				5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */,
+				42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
+				4251B131152D049B002F6199 /* ScreenDisplayer.h in Headers */,
+				4251B135152D049B002F6199 /* ThemeStyle.h in Headers */,
+				422260D81537790F0011E3AB /* Bundle.h in Headers */,
+				426878AE153F4BB300844500 /* FlowLayout.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -934,7 +1104,6 @@
 				5B04C59F14BFCFE100EB0071 /* MeshSkin.h in Headers */,
 				5B04C5A014BFCFE100EB0071 /* Model.h in Headers */,
 				5B04C5A114BFCFE100EB0071 /* Node.h in Headers */,
-				5B04C5A214BFCFE100EB0071 /* Package.h in Headers */,
 				5B04C5A314BFCFE100EB0071 /* ParticleEmitter.h in Headers */,
 				5B04C5A414BFCFE100EB0071 /* Pass.h in Headers */,
 				5B04C5A514BFCFE100EB0071 /* PhysicsConstraint.h in Headers */,
@@ -965,21 +1134,42 @@
 				5B04C5BE14BFCFE100EB0071 /* Vector4.h in Headers */,
 				5B04C5BF14BFCFE100EB0071 /* VertexAttributeBinding.h in Headers */,
 				5B04C5C014BFCFE100EB0071 /* VertexFormat.h in Headers */,
-				5B04C5C114BFCFE100EB0071 /* Viewport.h in Headers */,
 				5B04C5C214BFCFE100EB0071 /* SceneLoader.h in Headers */,
 				5B04C5C314BFCFE100EB0071 /* Image.h in Headers */,
 				5B04C5C414BFCFE100EB0071 /* Keyboard.h in Headers */,
 				5B04C5C514BFCFE100EB0071 /* Touch.h in Headers */,
 				5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */,
+				5BB0823E14C6FEC40019975F /* Mouse.h in Headers */,
+				5BD52672150F8258004C9099 /* PhysicsCharacter.h in Headers */,
+				5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
+				5BC4E740150F843D00CBE1C0 /* AbsoluteLayout.h in Headers */,
+				5BC4E742150F843D00CBE1C0 /* Button.h in Headers */,
+				5BC4E744150F843D00CBE1C0 /* CheckBox.h in Headers */,
+				5BC4E746150F843D00CBE1C0 /* Container.h in Headers */,
+				5BC4E748150F843D00CBE1C0 /* Control.h in Headers */,
+				5BC4E74B150F843D00CBE1C0 /* Form.h in Headers */,
+				5BC4E74D150F843D00CBE1C0 /* Label.h in Headers */,
+				5BC4E74E150F843D00CBE1C0 /* Layout.h in Headers */,
+				5BC4E750150F843D00CBE1C0 /* RadioButton.h in Headers */,
+				5BC4E752150F843D00CBE1C0 /* Slider.h in Headers */,
+				5BC4E754150F843D00CBE1C0 /* TextBox.h in Headers */,
+				5BC4E756150F843D00CBE1C0 /* Theme.h in Headers */,
+				5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */,
+				5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */,
+				42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
+				4251B132152D049B002F6199 /* ScreenDisplayer.h in Headers */,
+				4251B136152D049B002F6199 /* ThemeStyle.h in Headers */,
+				422260D91537790F0011E3AB /* Bundle.h in Headers */,
+				426878AF153F4BB300844500 /* FlowLayout.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
-		4234D99914686C52003031B3 /* gameplay-macos */ = {
+		4234D99914686C52003031B3 /* gameplay-macosx */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = 4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay-macos" */;
+			buildConfigurationList = 4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay-macosx" */;
 			buildPhases = (
 				4234D99614686C52003031B3 /* Sources */,
 				4234D99714686C52003031B3 /* Frameworks */,
@@ -989,7 +1179,7 @@
 			);
 			dependencies = (
 			);
-			name = "gameplay-macos";
+			name = "gameplay-macosx";
 			productName = gameplay;
 			productReference = 4234D99A14686C52003031B3 /* libgameplay.a */;
 			productType = "com.apple.product-type.library.static";
@@ -1017,7 +1207,7 @@
 		4234D98C14686BB6003031B3 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0420;
+				LastUpgradeCheck = 0430;
 			};
 			buildConfigurationList = 4234D98F14686BB6003031B3 /* Build configuration list for PBXProject "gameplay" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -1031,7 +1221,7 @@
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				4234D99914686C52003031B3 /* gameplay-macos */,
+				4234D99914686C52003031B3 /* gameplay-macosx */,
 				5B04C52B14BFCFE100EB0071 /* gameplay-ios */,
 			);
 		};
@@ -1063,7 +1253,7 @@
 				42CD0E6B147D8FF60000361E /* FrameBuffer.cpp in Sources */,
 				42CD0E6D147D8FF60000361E /* Frustum.cpp in Sources */,
 				42CD0E6F147D8FF60000361E /* Game.cpp in Sources */,
-				42CD0E71147D8FF60000361E /* gameplay-main-macos.mm in Sources */,
+				42CD0E71147D8FF60000361E /* gameplay-main-macosx.mm in Sources */,
 				42CD0E77147D8FF60000361E /* Joint.cpp in Sources */,
 				42CD0E79147D8FF60000361E /* Light.cpp in Sources */,
 				42CD0E7B147D8FF60000361E /* Material.cpp in Sources */,
@@ -1074,7 +1264,6 @@
 				42CD0E85147D8FF60000361E /* MeshSkin.cpp in Sources */,
 				42CD0E87147D8FF60000361E /* Model.cpp in Sources */,
 				42CD0E89147D8FF60000361E /* Node.cpp in Sources */,
-				42CD0E8B147D8FF60000361E /* Package.cpp in Sources */,
 				42CD0E8D147D8FF60000361E /* ParticleEmitter.cpp in Sources */,
 				42CD0E8F147D8FF60000361E /* Pass.cpp in Sources */,
 				42CD0E91147D8FF60000361E /* PhysicsConstraint.cpp in Sources */,
@@ -1087,7 +1276,7 @@
 				42CD0E9F147D8FF60000361E /* PhysicsSocketConstraint.cpp in Sources */,
 				42CD0EA1147D8FF60000361E /* PhysicsSpringConstraint.cpp in Sources */,
 				42CD0EA3147D8FF60000361E /* Plane.cpp in Sources */,
-				42CD0EA6147D8FF60000361E /* PlatformMacOS.mm in Sources */,
+				42CD0EA6147D8FF60000361E /* PlatformMacOSX.mm in Sources */,
 				42CD0EA9147D8FF60000361E /* Properties.cpp in Sources */,
 				42CD0EAB147D8FF60000361E /* Quaternion.cpp in Sources */,
 				42CD0EAD147D8FF60000361E /* Ray.cpp in Sources */,
@@ -1105,10 +1294,29 @@
 				42CD0EC5147D8FF60000361E /* Vector4.cpp in Sources */,
 				42CD0EC7147D8FF60000361E /* VertexAttributeBinding.cpp in Sources */,
 				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 */,
+				5BD5264F150F822A004C9099 /* AbsoluteLayout.cpp in Sources */,
+				5BD52651150F822A004C9099 /* Button.cpp in Sources */,
+				5BD52653150F822A004C9099 /* CheckBox.cpp in Sources */,
+				5BD52655150F822A004C9099 /* Container.cpp in Sources */,
+				5BD52657150F822A004C9099 /* Control.cpp in Sources */,
+				5BD5265A150F822A004C9099 /* Form.cpp in Sources */,
+				5BD5265C150F822A004C9099 /* Label.cpp in Sources */,
+				5BD5265F150F822A004C9099 /* RadioButton.cpp in Sources */,
+				5BD52661150F822A004C9099 /* Slider.cpp in Sources */,
+				5BD52663150F822A004C9099 /* TextBox.cpp in Sources */,
+				5BD52665150F822A004C9099 /* Theme.cpp in Sources */,
+				5BD52668150F822A004C9099 /* VerticalLayout.cpp in Sources */,
+				5BD5266F150F8258004C9099 /* PhysicsCharacter.cpp in Sources */,
+				5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
+				5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
+				42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
+				4251B133152D049B002F6199 /* ThemeStyle.cpp in Sources */,
+				4271C08E15337C8200B89DA7 /* Layout.cpp in Sources */,
+				422260D61537790F0011E3AB /* Bundle.cpp in Sources */,
+				426878AC153F4BB300844500 /* FlowLayout.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1147,7 +1355,6 @@
 				5B04C54C14BFCFE100EB0071 /* MeshSkin.cpp in Sources */,
 				5B04C54D14BFCFE100EB0071 /* Model.cpp in Sources */,
 				5B04C54E14BFCFE100EB0071 /* Node.cpp in Sources */,
-				5B04C54F14BFCFE100EB0071 /* Package.cpp in Sources */,
 				5B04C55014BFCFE100EB0071 /* ParticleEmitter.cpp in Sources */,
 				5B04C55114BFCFE100EB0071 /* Pass.cpp in Sources */,
 				5B04C55214BFCFE100EB0071 /* PhysicsConstraint.cpp in Sources */,
@@ -1177,12 +1384,31 @@
 				5B04C56D14BFCFE100EB0071 /* Vector4.cpp in Sources */,
 				5B04C56E14BFCFE100EB0071 /* VertexAttributeBinding.cpp in Sources */,
 				5B04C56F14BFCFE100EB0071 /* VertexFormat.cpp in Sources */,
-				5B04C57014BFCFE100EB0071 /* Viewport.cpp in Sources */,
 				5B04C57114BFCFE100EB0071 /* SceneLoader.cpp in Sources */,
 				5B04C57214BFCFE100EB0071 /* Image.cpp in Sources */,
 				5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */,
 				5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */,
 				5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */,
+				5BD52670150F8258004C9099 /* PhysicsCharacter.cpp in Sources */,
+				5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
+				5BC4E73F150F843D00CBE1C0 /* AbsoluteLayout.cpp in Sources */,
+				5BC4E741150F843D00CBE1C0 /* Button.cpp in Sources */,
+				5BC4E743150F843D00CBE1C0 /* CheckBox.cpp in Sources */,
+				5BC4E745150F843D00CBE1C0 /* Container.cpp in Sources */,
+				5BC4E747150F843D00CBE1C0 /* Control.cpp in Sources */,
+				5BC4E74A150F843D00CBE1C0 /* Form.cpp in Sources */,
+				5BC4E74C150F843D00CBE1C0 /* Label.cpp in Sources */,
+				5BC4E74F150F843D00CBE1C0 /* RadioButton.cpp in Sources */,
+				5BC4E751150F843D00CBE1C0 /* Slider.cpp in Sources */,
+				5BC4E753150F843D00CBE1C0 /* TextBox.cpp in Sources */,
+				5BC4E755150F843D00CBE1C0 /* Theme.cpp in Sources */,
+				5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */,
+				5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
+				42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
+				4251B134152D049B002F6199 /* ThemeStyle.cpp in Sources */,
+				4271C08F15337C8200B89DA7 /* Layout.cpp in Sources */,
+				422260D71537790F0011E3AB /* Bundle.cpp in Sources */,
+				426878AD153F4BB300844500 /* FlowLayout.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1192,6 +1418,8 @@
 		4234D99114686BB6003031B3 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
 				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
 				VALID_ARCHS = "armv7 armv6 i386 x86_64";
 			};
@@ -1200,6 +1428,7 @@
 		4234D99214686BB6003031B3 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				SDKROOT = macosx;
 				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
 				VALID_ARCHS = "armv7 armv6 i386 x86_64";
 			};
@@ -1209,7 +1438,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				COPY_PHASE_STRIP = NO;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -1234,18 +1463,18 @@
 					"../external-deps/libpng/include",
 					"../external-deps/bullet/include",
 					"../external-deps/oggvorbis/include",
+					./gameplay,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
-					"\"$(SRCROOT)/../external-deps/libpng/lib/macos\"",
-					"\"$(SRCROOT)/../external-deps/bullet/lib/macos\"",
-					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/macos\"",
+					"\"$(SRCROOT)/../external-deps/libpng/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/bullet/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/macosx\"",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
-				ONLY_ACTIVE_ARCH = NO;
+				ONLY_ACTIVE_ARCH = YES;
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
 				PRODUCT_NAME = gameplay;
-				SDKROOT = macosx;
 				SHARED_PRECOMPS_DIR = "";
 				SUPPORTED_PLATFORMS = macosx;
 				USER_HEADER_SEARCH_PATHS = "";
@@ -1257,7 +1486,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				COPY_PHASE_STRIP = YES;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@@ -1276,17 +1505,17 @@
 					"../external-deps/libpng/include",
 					"../external-deps/bullet/include",
 					"../external-deps/oggvorbis/include",
+					./gameplay,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
-					"\"$(SRCROOT)/../external-deps/libpng/lib/macos\"",
-					"\"$(SRCROOT)/../external-deps/bullet/lib/macos\"",
-					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/macos\"",
+					"\"$(SRCROOT)/../external-deps/libpng/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/bullet/lib/macosx\"",
+					"\"$(SRCROOT)/../external-deps/oggvorbis/lib/macosx\"",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
 				PRODUCT_NAME = gameplay;
-				SDKROOT = macosx;
 				SHARED_PRECOMPS_DIR = "";
 				SUPPORTED_PLATFORMS = macosx;
 				USER_HEADER_SEARCH_PATHS = "";
@@ -1399,7 +1628,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay-macos" */ = {
+		4234D9AB14686C52003031B3 /* Build configuration list for PBXNativeTarget "gameplay-macosx" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				4234D9A914686C52003031B3 /* Debug */,

+ 0 - 57
gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-MacOSX.xcscheme

@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "4234D99914686C52003031B3"
-               BuildableName = "libgameplay.a"
-               BlueprintName = "gameplay-macos"
-               ReferencedContainer = "container:gameplay.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Debug">
-      <Testables>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Debug"
-      debugDocumentVersioning = "YES"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 0 - 57
gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-iOS.xcscheme

@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "5B04C52B14BFCFE100EB0071"
-               BuildableName = "libgameplay.a"
-               BlueprintName = "gameplay-ios"
-               ReferencedContainer = "container:gameplay.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      buildConfiguration = "Debug">
-      <Testables>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Debug"
-      debugDocumentVersioning = "YES"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Release"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

BIN
gameplay/res/icon.png


BIN
gameplay/res/icon_128.ico


BIN
gameplay/res/icon_16.ico


BIN
gameplay/res/icon_32.ico


BIN
gameplay/res/icon_64.ico


Fișier diff suprimat deoarece este prea mare
+ 27 - 0
gameplay/res/logo.ai


BIN
gameplay/res/logo_black.png


BIN
gameplay/res/logo_powered_black.png


BIN
gameplay/res/logo_powered_white.png


BIN
gameplay/res/logo_white.png


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

@@ -8,6 +8,9 @@ uniform vec3 u_ambientColor;                // Ambient color.
 uniform float u_specularExponent;           // Specular exponent or shininess property.
 uniform sampler2D u_diffuseTexture;         // Diffuse texture.
 uniform sampler2D u_normalMapTexture;       // Normal map texture.
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec2 v_texCoord;                    // Texture Coordinate.
@@ -114,4 +117,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
 }

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

@@ -7,6 +7,9 @@ uniform vec3 u_lightColor;                   // Light color.
 uniform vec3 u_ambientColor;                 // Ambient color.
 uniform sampler2D u_diffuseTexture;          // Diffuse texture.
 uniform sampler2D u_normalMapTexture;        // Normal map texture.
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec2 v_texCoord;                     // Texture Coordinate.
@@ -103,4 +106,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor;
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
 }

+ 23 - 6
gameplay/res/shaders/colored-specular.fsh

@@ -5,12 +5,20 @@ precision highp float;
 // Uniforms
 uniform vec3 u_lightColor;                      // Light color
 uniform vec3 u_ambientColor;                    // Ambient color
-uniform float u_specularExponent;               // Specular exponent or shininess property.
+uniform float u_specularExponent;               // Specular exponent or shininess property
+#if !defined(VERTEX_COLOR)
 uniform vec4 u_diffuseColor;                    // Diffuse color
+#endif
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
-varying vec3 v_normalVector;                    // NormalVector in view space.
+varying vec3 v_normalVector;                    // NormalVector in view space
 varying vec3 v_cameraDirection;                 // Camera direction
+#if defined(VERTEX_COLOR)
+varying vec4 v_color;							// Vertex color
+#endif
 
 // Global variables
 vec4 _baseColor;                                // Base color
@@ -24,7 +32,8 @@ void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, floa
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
+    float ddot = abs(dot(normalVector, lightDirection));
+    float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
 
@@ -103,8 +112,12 @@ void applyLight()
 
 void main()
 {
-    // Fetch diffuse color from texture.
-    _baseColor = u_diffuseColor;
+    // Set base diffuse color
+#if defined(VERTEX_COLOR)
+	_baseColor = v_color;
+#else
+	_baseColor = u_diffuseColor;
+#endif
 
     // Apply light
     applyLight();
@@ -112,4 +125,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-}
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
+}

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

@@ -7,11 +7,16 @@ uniform vec3 u_cameraPosition;                      // Position of the camera.
 // Inputs
 attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
 attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
-attribute vec2 a_texCoord;                          // Vertex Texture Coordinate (u, v)
+#if defined(VERTEX_COLOR)
+attribute vec4 a_color;
+#endif
 
 // Outputs
-varying vec3 v_normalVector;                        // NormalVector in view space.
+varying vec3 v_normalVector;                        // NormalVector in view space
 varying vec3 v_cameraDirection;                     // Camera direction
+#if defined(VERTEX_COLOR)
+varying vec4 v_color;								// Vertex color
+#endif
 
 #if defined(SKINNING)
 
@@ -189,6 +194,10 @@ void main()
     vec4 positionWorldSpace = u_worldMatrix * position;
     v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
 
+#if defined(VERTEX_COLOR)
+	v_color = a_color;
+#endif
+
     // Apply light.
     applyLight(position);
 }

+ 9 - 1
gameplay/res/shaders/colored.fsh

@@ -6,6 +6,9 @@ precision highp float;
 uniform vec3 u_lightColor;                      // Light color
 uniform vec3 u_ambientColor;                    // Ambient color
 uniform vec4 u_diffuseColor;                    // Diffuse color
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec3 v_normalVector;                    // NormalVector in view space.
@@ -21,7 +24,8 @@ void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
+    float ddot = dot(normalVector, lightDirection);
+    float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
 }
@@ -100,4 +104,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor;
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
 }

+ 11 - 3
gameplay/res/shaders/diffuse-specular.fsh

@@ -7,6 +7,9 @@ uniform vec3 u_lightColor;                      // Light color
 uniform vec3 u_ambientColor;                    // Ambient color
 uniform float u_specularExponent;               // Specular exponent or shininess property.
 uniform sampler2D u_diffuseTexture;             // Diffuse texture.
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec3 v_normalVector;                    // NormalVector in view space.
@@ -25,12 +28,13 @@ void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, floa
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
+    float ddot = dot(normalVector, lightDirection);
+    float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
 
     // Specular
-    vec3 halfVector = normalize(cameraDirection + lightDirection);
+    vec3 halfVector = normalize(lightDirection + cameraDirection);
     float specularIntensity = attenuation * max(0.0, pow(dot(normalVector, halfVector), u_specularExponent));
     specularIntensity = max(0.0, specularIntensity);
     _specularColor = u_lightColor * _baseColor.rgb * specularIntensity;
@@ -113,4 +117,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-}
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
+}

+ 9 - 11
gameplay/res/shaders/diffuse-specular.vsh

@@ -1,8 +1,8 @@
 // Uniforms
 uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
 uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
-uniform mat4 u_worldMatrix;                         // Matrix to tranform a position to world space.
-uniform vec3 u_cameraPosition;                      // Position of the camera.
+uniform mat4 u_worldViewMatrix;                     // Matrix to tranform a position to view space.
+uniform vec3 u_cameraPosition;                      // Position of the camera in view space.
 
 // Inputs
 attribute vec4 a_position;                          // Vertex Position (x, y, z, w)
@@ -117,7 +117,6 @@ vec3 getNormal()
 
 #if defined(POINT_LIGHT)
 
-uniform mat4 u_worldViewMatrix;                         // Matrix to tranform a position to view space.
 uniform vec3 u_pointLightPosition;                      // Position
 uniform float u_pointLightRangeInverse;                 // Inverse of light range.
 varying vec4 v_vertexToPointLightDirection;             // Light direction w.r.t current vertex.
@@ -141,7 +140,6 @@ void applyLight(vec4 position)
 
 #elif defined(SPOT_LIGHT)
 
-uniform mat4 u_worldViewMatrix;                         // Matrix to tranform a position to view space.
 uniform vec3 u_spotLightPosition;                       // Position
 uniform float u_spotLightRangeInverse;                  // Inverse of light range.
 varying vec3 v_vertexToSpotLightDirection;              // Light direction w.r.t current vertex.
@@ -179,18 +177,18 @@ void main()
     gl_Position = u_worldViewProjectionMatrix * position;
 
     // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
-                                                u_inverseTransposeWorldViewMatrix[1].xyz,
-                                                u_inverseTransposeWorldViewMatrix[2].xyz);
-    v_normalVector = inverseTransposeWorldViewMatrix * normal;
+    mat3 normalMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz,
+                             u_inverseTransposeWorldViewMatrix[1].xyz,
+                             u_inverseTransposeWorldViewMatrix[2].xyz);
+    v_normalVector = normalMatrix * normal;
 
     // Compute the camera direction.
-    vec4 positionWorldSpace = u_worldMatrix * position;
+    vec4 positionWorldSpace = u_worldViewMatrix * position;
     v_cameraDirection = u_cameraPosition - positionWorldSpace.xyz;
 
     // Apply light.
     applyLight(position);
 
-    // Pass on the texture coordinates to Fragment shader.
+	// Pass on the texture coordinates to Fragment shader.
     v_texCoord = a_texCoord;
-}
+}

+ 9 - 1
gameplay/res/shaders/diffuse.fsh

@@ -6,6 +6,9 @@ precision highp float;
 uniform vec3 u_lightColor;                      // Light color
 uniform vec3 u_ambientColor;                    // Ambient color
 uniform sampler2D u_diffuseTexture;             // Diffuse texture.
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec3 v_normalVector;                    // NormalVector in view space.
@@ -22,7 +25,8 @@ void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-    float diffuseIntensity = attenuation * max(0.0, dot(normalVector, lightDirection));
+	float ddot = dot(normalVector, lightDirection);
+    float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
 }
@@ -100,4 +104,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor;
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
 }

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

@@ -10,6 +10,9 @@ uniform sampler2D u_diffuseTexture;             // Diffuse texture.
 uniform sampler2D u_bumpMapTexture;             // Height map texture
 uniform sampler2D u_normalMapTexture;           // Normal map texture.
 uniform float u_parallaxHeight;                 // Parallax height
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec2 v_texCoord;                        // Texture Coordinate.
@@ -165,4 +168,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
 }

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

@@ -9,6 +9,9 @@ uniform sampler2D u_diffuseTexture;             // Diffuse texture.
 uniform sampler2D u_bumpMapTexture;             // Height map texture
 uniform sampler2D u_normalMapTexture;           // Normal map texture.
 uniform float u_parallaxHeight;                 // Parallax height
+#if defined(GLOBAL_ALPHA)
+uniform float u_globalAlpha;                    // Global alpha value
+#endif
 
 // Inputs
 varying vec2 v_texCoord;                        // Texture Coordinate.
@@ -157,4 +160,8 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor;
+
+#if defined(GLOBAL_ALPHA)
+    gl_FragColor.a *= u_globalAlpha;
+#endif
 }

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

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

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

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

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


+ 58 - 0
gameplay/src/AbsoluteLayout.cpp

@@ -0,0 +1,58 @@
+#include "Base.h"
+#include "Control.h"
+#include "AbsoluteLayout.h"
+#include "Container.h"
+
+namespace gameplay
+{
+    static AbsoluteLayout* __instance;
+
+    AbsoluteLayout::AbsoluteLayout()
+    {
+    }
+
+    AbsoluteLayout::AbsoluteLayout(const AbsoluteLayout& copy)
+    {
+    }
+
+    AbsoluteLayout::~AbsoluteLayout()
+    {
+    }
+
+    AbsoluteLayout* AbsoluteLayout::create()
+    {
+        if (!__instance)
+        {
+            __instance = new AbsoluteLayout();
+        }
+        else
+        {
+            __instance->addRef();
+        }
+
+        return __instance;
+    }
+
+    Layout::Type AbsoluteLayout::getType()
+    {
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+
+    void AbsoluteLayout::update(const Container* container)
+    {
+        // An AbsoluteLayout does nothing to modify the layout of Controls.
+        std::vector<Control*> controls = container->getControls();
+        unsigned int controlsCount = controls.size();
+        for (unsigned int i = 0; i < controlsCount; i++)
+        {
+            Control* control = controls[i];
+
+            align(control, container);
+
+            if (control->isDirty() || control->isContainer())
+            {
+                control->update(container->getClip());
+            }
+        }
+    }
+}

+ 66 - 0
gameplay/src/AbsoluteLayout.h

@@ -0,0 +1,66 @@
+#ifndef ABSOLUTELAYOUT_H_
+#define ABSOLUTELAYOUT_H_
+
+#include "Layout.h"
+
+namespace gameplay
+{
+
+/**
+ * Defines a Layout for forms and containers that requires the user
+ * to specify absolute positions for all contained controls.
+ */
+class AbsoluteLayout : public Layout
+{
+    friend class Form;
+    friend class Container;
+
+public:
+
+    /**
+     * Get the type of this Layout.
+     *
+     * @return Layout::LAYOUT_ABSOLUTE
+     */
+    Layout::Type getType();
+
+protected:
+
+    /**
+     * Create an AbsoluteLayout.
+     *
+     * @return An AbsoluteLayout object.
+     */
+    static AbsoluteLayout* create();
+
+    /**
+     * Update the controls contained by the specified container.
+     *
+     * An AbsoluteLayout does nothing to modify the layout of controls.
+     * It simply calls update() on any control that is dirty.
+     *
+     * @param container The container to update.
+     */
+    void update(const Container* container);
+
+private:
+    
+    /*
+     * Constructor.
+     */
+    AbsoluteLayout();
+    
+    /*
+     * Constructor.
+     */
+    AbsoluteLayout(const AbsoluteLayout& copy);
+    
+    /*
+     * Destructor.
+     */
+    virtual ~AbsoluteLayout();
+};
+
+}
+
+#endif

+ 96 - 25
gameplay/src/Animation.cpp

@@ -19,19 +19,33 @@ Animation::Animation(const char* id, AnimationTarget* target, int propertyId, un
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
+    // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
+    release();
+    assert(getRefCount() == 1);
 }
 
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, unsigned int type)
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
+    // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
+    release();
+    assert(getRefCount() == 1);
+}
+
+Animation::Animation(const char* id)
+    : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
+{
 }
 
 Animation::~Animation()
 {
+    _channels.clear();
+
     if (_defaultClip)
     {
-        _defaultClip->stop();
+        if (_defaultClip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+            _controller->unschedule(_defaultClip);
         SAFE_RELEASE(_defaultClip);
     }
 
@@ -42,7 +56,8 @@ Animation::~Animation()
         while (clipIter != _clips->end())
         {   
             AnimationClip* clip = *clipIter;
-            clip->stop();
+            if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+                _controller->unschedule(clip);
             SAFE_RELEASE(clip);
             clipIter++;
         }
@@ -56,19 +71,30 @@ Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int p
 {
     // get property component count, and ensure the property exists on the AnimationTarget by getting the property component count.
     assert(_target->getAnimationPropertyComponentCount(propertyId));
-
+    _curve->addRef();
+    _target->addChannel(this);
     _animation->addRef();
+}
 
+Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
+    : _animation(animation), _target(target), _propertyId(copy._propertyId), _curve(copy._curve), _duration(copy._duration)
+{
+    _curve->addRef();
     _target->addChannel(this);
+    _animation->addRef();
 }
 
 Animation::Channel::~Channel()
 {
-    SAFE_DELETE(_curve);
-    _animation->removeChannel(this);
+    SAFE_RELEASE(_curve);
     SAFE_RELEASE(_animation);
 }
 
+Curve* Animation::Channel::getCurve() const
+{
+    return _curve;
+}
+
 const char* Animation::getId() const
 {
     return _id.c_str();
@@ -120,10 +146,23 @@ AnimationClip* Animation::getClip(const char* id)
     }
 }
 
-void Animation::play(const char* id)
+AnimationClip* Animation::getClip(unsigned int index) const
+{
+    if (_clips)
+        return _clips->at(index);
+
+    return NULL;
+}
+
+unsigned int Animation::getClipCount() const
+{
+    return _clips ? _clips->size() : 0;
+}
+
+void Animation::play(const char* clipId)
 {
     // If id is NULL, play the default clip.
-    if (id == NULL)
+    if (clipId == NULL)
     {
         if (_defaultClip == NULL)
             createDefaultClip();
@@ -133,33 +172,54 @@ void Animation::play(const char* id)
     else
     {
         // Find animation clip.. and play.
-        AnimationClip* clip = findClip(id);
+        AnimationClip* clip = findClip(clipId);
         if (clip != NULL)
-        {
             clip->play();
-        }
     }
 }
 
-void Animation::stop(const char* id)
+void Animation::stop(const char* clipId)
 {
     // If id is NULL, play the default clip.
-    if (id == NULL)
+    if (clipId == NULL)
     {
-        if (_defaultClip == NULL)
-            createDefaultClip();
-
-        _defaultClip->stop();
+        if (_defaultClip)
+            _defaultClip->stop();
     }
     else
     {
         // Find animation clip.. and play.
-        AnimationClip* clip = findClip(id);
+        AnimationClip* clip = findClip(clipId);
         if (clip != NULL)
-        {
             clip->stop();
+    }
+}
+
+void Animation::pause(const char * clipId)
+{
+    if (clipId == NULL)
+    {
+        if (_defaultClip)
+            _defaultClip->pause();
+    }
+    else
+    {
+        AnimationClip* clip = findClip(clipId);
+        if (clip != NULL)
+            clip->pause();
+    }
+}
+
+bool Animation::targets(AnimationTarget* target) const
+{
+    for (std::vector<Animation::Channel*>::const_iterator itr = _channels.begin(); itr != _channels.end(); ++itr)
+    {
+        if ((*itr)->_target == target)
+        {
+            return true;
         }
     }
+    return false;
 }
 
 void Animation::createDefaultClip()
@@ -168,7 +228,7 @@ void Animation::createDefaultClip()
 }
 
 void Animation::createClips(Properties* animationProperties, unsigned int frameCount)
-{   
+{
     assert(animationProperties);
     
     Properties* pClip = animationProperties->getNextNamespace();
@@ -238,7 +298,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
 
-    Curve* curve = new Curve(keyCount, propertyComponentCount);
+    Curve* curve = Curve::create(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
         setTransformRotationOffset(curve, propertyId);
 
@@ -265,6 +325,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
+    curve->release();
     addChannel(channel);
     return channel;
 }
@@ -274,7 +335,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
 
-    Curve* curve = new Curve(keyCount, propertyComponentCount);
+    Curve* curve = Curve::create(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
         setTransformRotationOffset(curve, propertyId);
     
@@ -301,6 +362,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
+    curve->release();
     addChannel(channel);
     return channel;
 }
@@ -322,16 +384,13 @@ void Animation::removeChannel(Channel* channel)
         if (channel == chan) 
         {
             _channels.erase(itr);
-            itr = _channels.end();
+            return;
         }
         else
         {
             itr++;
         }
     }
-
-    if (_channels.empty())
-        _controller->destroyAnimation(this);
 }
 
 void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId)
@@ -350,4 +409,16 @@ void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId
     return;
 }
 
+Animation* Animation::clone(Channel* channel, AnimationTarget* target)
+{
+    Animation* animation = new Animation(getId());
+
+    Animation::Channel* channelCopy = new Animation::Channel(*channel, animation, target);
+    animation->addChannel(channelCopy);
+    // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
+    animation->release();
+    assert(animation->getRefCount() == 1);
+    return animation;
+}
+
 }

+ 52 - 11
gameplay/src/Animation.h

@@ -3,6 +3,7 @@
 
 #include "Ref.h"
 #include "Properties.h"
+#include "Curve.h"
 
 namespace gameplay
 {
@@ -10,7 +11,6 @@ namespace gameplay
 class AnimationTarget;
 class AnimationController;
 class AnimationClip;
-class Curve;
 
 /**
  * Defines a generic property animation.
@@ -22,10 +22,9 @@ class Curve;
  */
 class Animation : public Ref
 {
-    friend class AnimationController;
     friend class AnimationClip;
     friend class AnimationTarget;
-    friend class Package;
+    friend class Bundle;
 
 public:
     
@@ -67,6 +66,18 @@ public:
      * @return The AnimationClip with the specified ID; NULL if an AnimationClip with the given ID is not found.
      */
     AnimationClip* getClip(const char* clipId = NULL);
+
+    /**
+     * Returns the AnimationClip at the given index.
+     *
+     * @param index Index of the clip to return.
+     */
+    AnimationClip* getClip(unsigned int index) const;
+
+    /**
+     * Returns the number of animation clips in this animation.
+     */
+    unsigned int getClipCount() const;
     
     /**
      * Plays the AnimationClip with the specified name. 
@@ -82,6 +93,18 @@ public:
      */
     void stop(const char* clipId = NULL);
 
+    /** 
+     * Pauses the AnimationClip with the specified name.
+     *
+     * @param clipId The ID of the AnimationClip to pause. If NULL, pauses the default clip.
+     */
+    void pause(const char* clipId = NULL);
+
+    /**
+     * Returns true if this animation targets the given AnimationTarget.
+     */
+    bool targets(AnimationTarget* target) const;
+    
 private:
 
     /**
@@ -99,8 +122,11 @@ private:
     private:
 
         Channel(Animation* animation, AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration);
-        Channel(const Channel& copy);
+        Channel(const Channel& copy, Animation* animation, AnimationTarget* target);
+        Channel(const Channel&); // Hidden copy constructor.
         ~Channel();
+        Channel& operator=(const Channel&); // Hidden copy assignment operator.
+        Curve* getCurve() const;
 
         Animation* _animation;                // Reference to the animation this channel belongs to.
         AnimationTarget* _target;             // The target of this channel.
@@ -110,12 +136,7 @@ private:
     };
 
     /**
-     * Constructor.
-     */
-    Animation();
-
-    /**
-     * Constructor.
+     * Hidden copy constructor.
      */
     Animation(const Animation& copy);
 
@@ -129,11 +150,21 @@ private:
      */
     Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, unsigned int type);
 
+    /**
+     * Constructor.
+     */
+    Animation(const char* id);
+
     /**
      * Destructor.
      */
     ~Animation();
-
+    
+    /**
+     * Hidden copy assignment operator.
+     */
+    Animation& operator=(const Animation&);
+    
     /**
      * Creates the default clip.
      */
@@ -178,6 +209,16 @@ private:
      * Sets the rotation offset in a Curve representing a Transform's animation data.
      */
     void setTransformRotationOffset(Curve* curve, unsigned int propertyId);
+
+    /**
+     * Clones this animation.
+     * 
+     * @param channel The channel to clone and add to the animation.
+     * @param target The target of the animation.
+     * 
+     * @return The newly created animation.
+     */
+    Animation* clone(Channel* channel, AnimationTarget* target);
     
     AnimationController* _controller;       // The AnimationController that this Animation will run on.
     std::string _id;                        // The Animation's ID.

+ 248 - 83
gameplay/src/AnimationClip.cpp

@@ -9,17 +9,17 @@ 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), 
-      _crossFadeToClip(NULL), _crossFadeStart(0), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
-      _isFadingOutStarted(false), _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL)
+    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), 
+      _stateBits(0x00), _repeatCount(1.0f), _activeDuration(_duration * _repeatCount), _speed(1.0f), _timeStarted(0), 
+      _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL)
 {
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     
     unsigned int channelCount = _animation->_channels.size();    
     for (unsigned int i = 0; i < channelCount; i++)
     {
-        _values.push_back(new AnimationValue(_animation->_channels[i]->_curve->getComponentCount()));
+        _values.push_back(new AnimationValue(_animation->_channels[i]->getCurve()->getComponentCount()));
     }
 }
 
@@ -36,6 +36,29 @@ AnimationClip::~AnimationClip()
     SAFE_RELEASE(_crossFadeToClip);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
+
+    if (_listeners)
+    {
+        *_listenerItr = _listeners->begin();
+        while (*_listenerItr != _listeners->end())
+        {
+            ListenerEvent* lEvt = **_listenerItr;
+            SAFE_DELETE(lEvt);
+            ++*_listenerItr;
+        }
+        SAFE_DELETE(_listeners);
+    }
+    SAFE_DELETE(_listenerItr);
+}
+
+AnimationClip::ListenerEvent::ListenerEvent(Listener* listener, unsigned long eventTime)
+{
+    _listener = listener;
+    _eventTime = eventTime;
+}
+
+AnimationClip::ListenerEvent::~ListenerEvent()
+{
 }
 
 const char* AnimationClip::getID() const
@@ -106,6 +129,11 @@ unsigned long AnimationClip::getActiveDuration() const
     return _activeDuration;
 }
 
+unsigned long AnimationClip::getDuration() const
+{
+    return _duration;
+}
+
 void AnimationClip::setSpeed(float speed)
 {
     _speed = speed;
@@ -128,22 +156,54 @@ float AnimationClip::getBlendWeight() const
 
 bool AnimationClip::isPlaying() const
 {
-    return _isPlaying;
+    return isClipStateBitSet(CLIP_IS_PLAYING_BIT);
 }
 
 void AnimationClip::play()
 {
-    _animation->_controller->schedule(this);
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+    {
+        // If paused, reset the bit and return.
+        if (isClipStateBitSet(CLIP_IS_PAUSED_BIT))
+        {
+            resetClipStateBit(CLIP_IS_PAUSED_BIT);
+            return;
+        }
+
+        // If the clip is set to be removed, reset the flag.
+        if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+            resetClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
+
+        // Set the state bit to restart.
+        setClipStateBit(CLIP_IS_RESTARTED_BIT);
+    }
+    else
+    {
+        setClipStateBit(CLIP_IS_PLAYING_BIT);
+        _animation->_controller->schedule(this);
+    }
+    
     _timeStarted = Game::getGameTime();
 }
 
 void AnimationClip::stop()
 {
-    _animation->_controller->unschedule(this);
-    if (_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
     {
-        _isPlaying = false;
-        onEnd();
+        // Reset the restarted and paused bits. 
+        resetClipStateBit(CLIP_IS_RESTARTED_BIT);
+        resetClipStateBit(CLIP_IS_PAUSED_BIT);
+
+        // Mark the clip to removed from the AnimationController.
+        setClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
+    }
+}
+
+void AnimationClip::pause()
+{
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT) && !isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+    {
+        setClipStateBit(CLIP_IS_PAUSED_BIT);
     }
 }
 
@@ -151,37 +211,83 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 {
     assert(clip);
 
-    if (clip->_isPlaying && clip->_isFadingOut)
+    // Check if the given clip is fading into this clip.
+    // We should reset the clip from fading out, and this one from fading in 
+    // in order to start the crossfade back the other way.
+    if (clip->isClipStateBitSet(CLIP_IS_FADING_OUT_BIT) && clip->_crossFadeToClip == this)
     {
-        clip->_isFadingOut = false;
-        clip->_crossFadeToClip->_isFadingIn = false;
+        clip->resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+        clip->_crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
         SAFE_RELEASE(clip->_crossFadeToClip);
     }
 
-    // If I already have a clip I'm fading too.. release it.
+    // If I already have a clip I'm fading to and it's not the same as the given clip release it.
+    // Assign the new clip and increase it's ref count.
     if (_crossFadeToClip)
+    {
         SAFE_RELEASE(_crossFadeToClip);
+    }
 
-    // Assign the clip we're fading to, and increase its ref count.
+    // Set and initialize the crossfade clip
     _crossFadeToClip = clip;
     _crossFadeToClip->addRef();
-        
-    // Set the fade in clip to fading in, and set the duration of the fade in.
-    _crossFadeToClip->_isFadingIn = true;
+    _crossFadeToClip->setClipStateBit(CLIP_IS_FADING_IN_BIT);
+    _crossFadeToClip->_blendWeight = 0.0f;
     
-    // Set this clip to fade out, and reset the elapsed time for the fade out.
-    _isFadingOut = true;
-    _crossFadeOutElapsed = 0;
+    // Set and intiliaze this clip to fade out
+    setClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
+    setClipStateBit(CLIP_IS_FADING_OUT_BIT);
+    _crossFadeOutElapsed = 0L;
     _crossFadeOutDuration = duration;
-    _crossFadeStart = (Game::getGameTime() - _timeStarted);
-    _isFadingOutStarted = true;
     
-    if (!_isPlaying)
+    // If this clip is currently not playing, we should start playing it.
+    if (!isClipStateBitSet(CLIP_IS_PLAYING_BIT))
         play();
 
+    // Start playing the cross fade clip.
     _crossFadeToClip->play(); 
 }
 
+void AnimationClip::addListener(AnimationClip::Listener* listener, unsigned long eventTime)
+{
+    assert(listener);
+    assert(eventTime < _activeDuration);
+
+    ListenerEvent* listenerEvent = new ListenerEvent(listener, eventTime);
+
+    if (!_listeners)
+    {
+        _listeners = new std::list<ListenerEvent*>;
+        _listeners->push_front(listenerEvent);
+
+        _listenerItr = new std::list<ListenerEvent*>::iterator;
+        if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+            *_listenerItr = _listeners->begin();
+    }
+    else
+    {
+        for (std::list<ListenerEvent*>::iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
+        {
+            if (eventTime < (*itr)->_eventTime)
+            {
+                itr = _listeners->insert(itr, listenerEvent);
+
+                // If playing, update the iterator if we need to.
+                // otherwise, it will just be set the next time the clip gets played.
+                if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+                {
+                    unsigned long currentTime = _elapsedTime % _duration;
+                    if ((_speed >= 0.0f && currentTime < eventTime && (*_listenerItr == _listeners->end() || eventTime < (**_listenerItr)->_eventTime)) || 
+                        (_speed <= 0 && currentTime > eventTime && (*_listenerItr == _listeners->begin() || eventTime > (**_listenerItr)->_eventTime)))
+                        *_listenerItr = itr;
+                }
+                return;
+            }
+        }
+        _listeners->push_back(listenerEvent);
+    }
+}
+
 void AnimationClip::addBeginListener(AnimationClip::Listener* listener)
 {
     if (!_beginListeners)
@@ -200,87 +306,125 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
 
 bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
 {
-    float speed = _speed;
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_PAUSED_BIT))
+    {
+        return false;
+    }
+    else if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+    {   // If the marked for removal bit is set, it means stop() was called on the AnimationClip at some point
+        // after the last update call. Reset the flag, and return true so the AnimationClip is removed from the 
+        // running clips on the AnimationController.
+        onEnd();
+        return true;
+    }
+    else if (!isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
         onBegin();
-        _elapsedTime = Game::getGameTime() - _timeStarted;
-        _runningTime = _elapsedTime * speed;
     }
     else
     {
-        // Update elapsed time.
-        _elapsedTime += elapsedTime;
-        _runningTime += elapsedTime * speed;
-    }
+        _elapsedTime += elapsedTime * _speed;
 
-    float percentComplete = 0.0f;
+        if (_repeatCount == REPEAT_INDEFINITE && _elapsedTime <= 0)
+            _elapsedTime = _activeDuration + _elapsedTime;
+    }
 
+    unsigned long currentTime = 0L;
     // Check to see if clip is complete.
-    if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0 && _runningTime >= (long) _activeDuration) || (_speed < 0 && _runningTime <= 0)))
+    if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0.0f && _elapsedTime >= (long) _activeDuration) || (_speed <= 0.0f && _elapsedTime <= 0L)))
     {
-        _isPlaying = false;
-        if (_speed >= 0)
+        resetClipStateBit(CLIP_IS_STARTED_BIT);
+        if (_speed >= 0.0f)
         {
-            percentComplete = _activeDuration % _duration; // Get's the fractional part of the final repeat.
-            if (percentComplete == 0.0f)
-                percentComplete = _duration;
+            // If _duration == 0, we have a "pose". Just set currentTime to 0.
+            if (_duration == 0)
+            {
+                currentTime = 0L;
+            }
+            else
+            {
+                currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
+                if (currentTime == 0L)
+                    currentTime = _duration;
+            }
         }
         else
         {
-            percentComplete = 0.0f; // If we are negative speed, the end value should be 0.
+            currentTime = 0L; // If we are negative speed, the end value should be 0.
         }
     }
     else
     {
-        // Gets portion/fraction of the repeat.
-        percentComplete = (float) (_runningTime % _duration);
+        // If _duration == 0, we have a "pose". Just set currentTime to 0.
+        if (_duration == 0)
+            currentTime = 0L;
+        else // Gets portion/fraction of the repeat.
+            currentTime = _elapsedTime % _duration;
+    }
+
+    // Notify any listeners of Animation events.
+    if (_listeners)
+    {
+        if (_speed >= 0.0f)
+        {
+            while (*_listenerItr != _listeners->end() && _elapsedTime >= (long) (**_listenerItr)->_eventTime)
+            {
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
+                ++*_listenerItr;
+            }
+        }
+        else
+        {
+            while (*_listenerItr != _listeners->begin() && _elapsedTime <= (long) (**_listenerItr)->_eventTime)
+            {
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
+                --*_listenerItr;
+            }
+        }
     }
 
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
-    percentComplete = (float)(_startTime + percentComplete) / (float) _animation->_duration;
+    float percentComplete = (float)(_startTime + currentTime) / (float) _animation->_duration;
     
-    if (_isFadingOut)
+    if (isClipStateBitSet(CLIP_IS_FADING_OUT_BIT))
     {
-        if (_isFadingOutStarted) // Calculate elapsed time since the fade out begin.
+        if (isClipStateBitSet(CLIP_IS_FADING_OUT_STARTED_BIT)) // Calculate elapsed time since the fade out begin.
         {
-            _crossFadeOutElapsed = (_elapsedTime - _crossFadeStart) * speed;
-            _isFadingOutStarted = false;
+            _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * abs(_speed); 
+            resetClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
         }
         else
         {
             // continue tracking elapsed time.
-            _crossFadeOutElapsed += elapsedTime * speed;
+            _crossFadeOutElapsed += elapsedTime * abs(_speed);
         }
 
         if (_crossFadeOutElapsed < _crossFadeOutDuration)
         {
+            // Calculate this clip's blend weight.
             float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
-            _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight);
             
-            // adjust the clip your blending to's weight to be a percentage of your current blend weight
-            if (_isFadingIn)
+            // If this clip is fading in, adjust the crossfade clip's weight to be a percentage of your current blend weight
+            if (isClipStateBitSet(CLIP_IS_FADING_IN_BIT))
             {
-                _crossFadeToClip->_blendWeight *= _blendWeight;
+                _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
                 _blendWeight -= _crossFadeToClip->_blendWeight;
             }
             else
             {
+                // Just set the blend weight.
+                _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight);
                 _blendWeight = tempBlendWeight;
             }
         }
         else
-        {   // Fade done.
+        {   // Fade is done.
             _crossFadeToClip->_blendWeight = 1.0f;
-                
-            if (_isFadingIn)
-                _crossFadeToClip->_blendWeight *= _blendWeight;
-
-            _crossFadeToClip->_isFadingIn = false;
+            _blendWeight = 0.0f;
+            resetClipStateBit(CLIP_IS_STARTED_BIT);            
+            resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+            _crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
             SAFE_RELEASE(_crossFadeToClip);
-            _blendWeight = 0.0f; 
-            _isFadingOut = false;
-            _isPlaying = false;
         }
     }
     
@@ -302,45 +446,40 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
             activeTargets->push_front(target);
 
         // Evaluate the point on Curve
-        channel->_curve->evaluate(percentComplete, value->_value);
+        channel->getCurve()->evaluate(percentComplete, value->_value);
         // Set the animation value on the target property.
         target->setAnimationPropertyValue(channel->_propertyId, value, _blendWeight);
     }
 
     // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT) || !isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
         onEnd();
-        // Notify end listeners if any.
-        if (_endListeners)
-        {
-            std::vector<Listener*>::iterator listener = _endListeners->begin();
-            while (listener != _endListeners->end())
-            {
-                (*listener)->animationEvent(this, Listener::END);
-                listener++;
-            }
-        }
+        return true;
     }
 
-    return !_isPlaying;
+    return false;
 }
 
 void AnimationClip::onBegin()
 {
     // Initialize animation to play.
-    _isPlaying = true;
-    _elapsedTime = 0;
-
-    if (_speed > 0)
+    setClipStateBit(CLIP_IS_STARTED_BIT);
+    if (_speed >= 0)
     {
-        _runningTime = 0;
+        _elapsedTime = (Game::getGameTime() - _timeStarted) * _speed;
+
+        if (_listeners)
+            *_listenerItr = _listeners->begin(); 
     }
     else
     {
-        _runningTime = _activeDuration;
-    }
+        _elapsedTime = _activeDuration + (Game::getGameTime() - _timeStarted) * _speed;
 
+        if (_listeners)
+            *_listenerItr = _listeners->end();
+    }
+    
     // Notify begin listeners.. if any.
     if (_beginListeners)
     {
@@ -356,7 +495,33 @@ void AnimationClip::onBegin()
 void AnimationClip::onEnd()
 {
     _blendWeight = 1.0f;
-    _timeStarted = 0;
+    resetClipStateBit(CLIP_ALL_BITS);
+
+    // Notify end listeners if any.
+    if (_endListeners)
+    {
+        std::vector<Listener*>::iterator listener = _endListeners->begin();
+        while (listener != _endListeners->end())
+        {
+            (*listener)->animationEvent(this, Listener::END);
+            listener++;
+        }
+    }
+}
+
+bool AnimationClip::isClipStateBitSet(unsigned char bit) const
+{
+    return (_stateBits & bit) == bit;
+}
+
+void AnimationClip::setClipStateBit(unsigned char bit)
+{
+    _stateBits |= bit;
+}
+
+void AnimationClip::resetClipStateBit(unsigned char bit)
+{
+    _stateBits &= ~bit;
 }
 
 }

+ 108 - 30
gameplay/src/AnimationClip.h

@@ -32,13 +32,27 @@ public:
      */
     class Listener
     {
+        friend class AnimationClip;
+
     public:
 
+        /*
+         * Constructor.
+         */
+        Listener() 
+        {
+        }
+
         /**
          * The type of animation event.
          */
         enum EventType 
         {
+            /**
+             * Default event type.
+             */
+            DEFAULT,
+
             /**
              * Event fired when the clip begins.
              */
@@ -94,7 +108,7 @@ public:
     /**
      * Sets the AnimationClip's repeat count. Overrides repeat duration.
      *
-     * Use ANIMATION_REPEAT_INDEFINITE to play the AnimationClip indefinitely.
+     * Use REPEAT_INDEFINITE to play the AnimationClip indefinitely.
      * 
      * @param repeatCount The repeat count to set on the AnimationClip.
      */
@@ -110,7 +124,7 @@ public:
     /**
      * Sets the AnimationClip's active duration. Overrides repeat count.
      *
-     * Use ANIMATION_REPEAT_INDEFINITE to play the AnimationClip indefinitely.
+     * Use REPEAT_INDEFINITE to play the AnimationClip indefinitely.
      *
      * @param duration The active duration that is set on the AnimationClip.
      */
@@ -123,6 +137,13 @@ public:
      */
     unsigned long getActiveDuration() const;
 
+    /**
+     * Gets the AnimationClip's duration.
+     *
+     * @return the AnimationClip's duration.
+     */
+    unsigned long getDuration() const;
+
     /**
      * Set the AnimationClip's running speed. 
      *
@@ -168,6 +189,11 @@ public:
      */
     void stop();
 
+    /**
+     * Pauses the AnimationClip.
+     */
+    void pause();
+
     /**
      * Fades this clip out, and the specified clip in over the given duration.
      *
@@ -177,20 +203,62 @@ public:
     void crossFade(AnimationClip* clip, unsigned long duration);
 
     /**
-     * Adds a animation begin listener.
+     * Adds an animation begin listener.
      *
-     * @param listener The listener to be called when an animation clip begins.
+     * @param listener The listener to be called when an AnimationClip begins.
      */
     void addBeginListener(AnimationClip::Listener* listener);
 
     /**
-     * Adds a animation end listener.
+     * Adds an animation end listener.
      *
-     * @param listener The listener to be called when an animation clip ends.
+     * @param listener The listener to be called when an AnimationClip ends.
      */
     void addEndListener(AnimationClip::Listener* listener);
 
+    /**
+     * Adds an animation listener to be called back at the specified eventTime during the playback 
+     * of the AnimationClip.
+     *
+     * @param listener The listener to be called when the AnimationClip reaches the 
+     *      specified time in its playback.
+     * @param eventTime The time the listener will be called during the playback of the AnimationClip. 
+     *      Must be between 0 and the duration of the AnimationClip.
+     */
+    void addListener(AnimationClip::Listener* listener, unsigned long eventTime);
+
 private:
+    
+    static const unsigned char CLIP_IS_PLAYING_BIT = 0x01;             // Bit representing whether AnimationClip is a running clip in AnimationController
+    static const unsigned char CLIP_IS_STARTED_BIT = 0x02;             // Bit representing whether the AnimationClip has actually been started (ie: received first call to update())
+    static const unsigned char CLIP_IS_FADING_OUT_STARTED_BIT = 0x04;  // Bit representing that a cross fade has started.
+    static const unsigned char CLIP_IS_FADING_OUT_BIT = 0x08;          // Bit representing whether the clip is fading out.
+    static const unsigned char CLIP_IS_FADING_IN_BIT = 0x10;           // Bit representing whether the clip is fading out.
+    static const unsigned char CLIP_IS_MARKED_FOR_REMOVAL_BIT = 0x20;  // Bit representing whether the clip has ended and should be removed from the AnimationController.
+    static const unsigned char CLIP_IS_RESTARTED_BIT = 0x40;           // Bit representing if the clip should be restarted by the AnimationController.
+    static const unsigned char CLIP_IS_PAUSED_BIT = 0x80;              // Bit representing if the clip is currently paused.
+    static const unsigned char CLIP_ALL_BITS = 0xFF;                   // Bit mask for all the state bits.
+
+    /**
+     * ListenerEvent.
+     *
+     * Internal structure used for storing the event time at which an AnimationClip::Listener should be called back.
+     */
+    struct ListenerEvent
+    {
+        /** 
+         * Constructor.
+         */
+        ListenerEvent(Listener* listener, unsigned long eventTime);
+
+        /**
+         * Destructor.
+         */
+        ~ListenerEvent();
+
+        Listener* _listener;        // This listener to call back when this event is triggered.
+        unsigned long _eventTime;   // The time at which the listener will be called back at during the playback of the AnimationClip.
+    };
 
     /**
      * Constructor.
@@ -227,32 +295,42 @@ private:
      */
     void onEnd();
 
-    std::string _id;                          // AnimationClip ID.
-    Animation* _animation;                    // The Animation this clip is created from.
-    unsigned long _startTime;                 // Start time of the clip.
-    unsigned long _endTime;                   // End time of the clip.
-    unsigned long _duration;                  // The total duration.
-    float _repeatCount;                       // The clip's repeat count.
-    unsigned long _activeDuration;            // The active duration of the clip.
-    float _speed;                             // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
-    bool _isPlaying;                          // A flag to indicate whether the clip is playing.
-    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.
-    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.
-    unsigned long _crossFadeOutDuration;      // The duration of the cross fade.
-    float _blendWeight;                       // The clip's blendweight
-    bool _isFadingOutStarted;                 // Flag to indicate if the cross fade started
-    bool _isFadingOut;                        // Flag to indicate if the clip is fading out
-    bool _isFadingIn;                         // Flag to indicate if the clip is fading in.
-    std::vector<AnimationValue*> _values;     // AnimationValue holder.
-    std::vector<Listener*>* _beginListeners;  // Collection of begin listeners on the clip
-    std::vector<Listener*>* _endListeners;    // Collection of end listeners on the clip
+    /**
+     * Determines whether the given bit is set in the AnimationClip's state.
+     */
+    bool isClipStateBitSet(unsigned char bit) const;
 
+    /**
+     * Sets the given bit in the AnimationClip's state.
+     */
+    void setClipStateBit(unsigned char bit);
+
+    /**
+     * Resets the given bit in the AnimationClip's state.
+     */
+    void resetClipStateBit(unsigned char bit);
+
+    std::string _id;                                    // AnimationClip ID.
+    Animation* _animation;                              // The Animation this clip is created from.
+    unsigned long _startTime;                           // Start time of the clip.
+    unsigned long _endTime;                             // End time of the clip.
+    unsigned long _duration;                            // The total duration.
+    unsigned char _stateBits;                           // Bit flag used to keep track of the clip's current state.
+    float _repeatCount;                                 // The clip's repeat count.
+    unsigned long _activeDuration;                      // The active duration of the clip.
+    float _speed;                                       // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
+    unsigned long _timeStarted;                         // The game time when this clip was actually started.
+    long _elapsedTime;                                  // Time elapsed while the clip is running.
+    AnimationClip* _crossFadeToClip;                    // The clip to cross fade to.
+    unsigned long _crossFadeOutElapsed;                 // The amount of time that has elapsed for the crossfade.
+    unsigned long _crossFadeOutDuration;                // The duration of the cross fade.
+    float _blendWeight;                                 // The clip's blendweight.
+    std::vector<AnimationValue*> _values;               // AnimationValue holder.
+    std::vector<Listener*>* _beginListeners;            // Collection of begin listeners on the clip.
+    std::vector<Listener*>* _endListeners;              // Collection of end listeners on the clip.
+    std::list<ListenerEvent*>* _listeners;              // Ordered collection of listeners on the clip.
+    std::list<ListenerEvent*>::iterator* _listenerItr;  // Iterator that points to the next listener event to be triggered.
 };
 
 }
-
 #endif

+ 19 - 284
gameplay/src/AnimationController.cpp

@@ -7,102 +7,12 @@ namespace gameplay
 {
 
 AnimationController::AnimationController()
-    : _state(STOPPED), _animations(NULL)
+    : _state(STOPPED)
 {
 }
 
 AnimationController::~AnimationController()
 {
-    destroyAllAnimations();
-}
-
-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(keyCount >= 2 && keyTimes && keyValues && target);
-
-    Animation* animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, type);
-
-    addAnimation(animation);
-    
-    return animation;
-}
-
-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(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, const char* animationFile)
-{
-    assert(target && animationFile);
-    
-    Properties* p = Properties::create(animationFile);
-    assert(p);
-
-    Animation* animation = createAnimation(id, target, p->getNextNamespace());
-
-    SAFE_DELETE(p);
-
-    return animation;
-}
-
-Animation* AnimationController::createAnimationFromTo(const char* id, AnimationTarget* target, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration)
-{
-    const unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
-    float* keyValues = new float[2 * propertyComponentCount];
-
-    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
-    memcpy(keyValues + propertyComponentCount, to, sizeof(float) * propertyComponentCount);
-
-    unsigned long* keyTimes = new unsigned long[2];
-    keyTimes[0] = 0;
-    keyTimes[1] = duration;
-
-    Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
-
-    SAFE_DELETE_ARRAY(keyValues);
-    SAFE_DELETE_ARRAY(keyTimes);
-    
-    return animation;
-}
-
-Animation* AnimationController::createAnimationFromBy(const char* id, AnimationTarget* target, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration)
-{
-    const unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
-    float* keyValues = new float[2 * propertyComponentCount];
-
-    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
-    memcpy(keyValues + propertyComponentCount, by, sizeof(float) * propertyComponentCount);
-
-    unsigned long* keyTimes = new unsigned long[2];
-    keyTimes[0] = 0;
-    keyTimes[1] = duration;
-
-    Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
-
-    SAFE_DELETE_ARRAY(keyValues);
-    SAFE_DELETE_ARRAY(keyTimes);
-
-    return animation;
-}
-
-Animation* AnimationController::getAnimation(const char* id) const
-{
-    unsigned int animationCount = _animations.size();
-    for (unsigned int i = 0; i < animationCount; i++)
-    {
-        if (_animations.at(i)->_id.compare(id) == 0)
-        {
-            return _animations.at(i);
-        }
-    }
-    return NULL;
 }
 
 void AnimationController::stopAllAnimations() 
@@ -111,152 +21,9 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = *clipIter;
-        clip->_isPlaying = false;
-        clip->onEnd();
-        SAFE_RELEASE(clip);
+        clip->stop();
         clipIter++;
     }
-    _runningClips.clear();
-
-    _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
@@ -271,7 +38,13 @@ void AnimationController::initialize()
 
 void AnimationController::finalize()
 {
-    stopAllAnimations();
+    std::list<AnimationClip*>::iterator itr = _runningClips.begin();
+    for ( ; itr != _runningClips.end(); itr++)
+    {
+        AnimationClip* clip = *itr;
+        SAFE_RELEASE(clip);
+    }
+    _runningClips.clear();
     _state = STOPPED;
 }
 
@@ -294,18 +67,8 @@ void AnimationController::schedule(AnimationClip* clip)
     {
         _state = RUNNING;
     }
-    
-    if (clip->_isPlaying)
-    {
-        _runningClips.remove(clip);
-        clip->_isPlaying = false;
-        clip->onEnd();
-    }
-    else
-    {
-        clip->addRef();
-    }
 
+    clip->addRef();
     _runningClips.push_back(clip);
 }
 
@@ -338,7 +101,15 @@ void AnimationController::update(long elapsedTime)
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = (*clipIter);
-        if (clip->update(elapsedTime, &_activeTargets))
+        if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_RESTARTED_BIT))
+        {   // If the CLIP_IS_RESTARTED_BIT is set, we should end the clip and 
+            // move it from where it is in the running clips list to the back.
+            clip->onEnd();
+            clip->setClipStateBit(AnimationClip::CLIP_IS_PLAYING_BIT);
+            _runningClips.push_back(clip);
+            clipIter = _runningClips.erase(clipIter);
+        }
+        else if (clip->update(elapsedTime, &_activeTargets))
         {
             SAFE_RELEASE(clip);
             clipIter = _runningClips.erase(clipIter);
@@ -363,40 +134,4 @@ void AnimationController::update(long elapsedTime)
         _state = IDLE;
 }
 
-void AnimationController::addAnimation(Animation* animation)
-{
-    _animations.push_back(animation);
-}
-
-void AnimationController::destroyAnimation(Animation* animation)
-{
-    std::vector<Animation*>::iterator itr = _animations.begin();
-
-    while (itr != _animations.end())
-    {
-        if (animation == *itr)
-        {
-            Animation* animation = *itr;
-            _animations.erase(itr);
-            SAFE_RELEASE(animation);
-            return;
-        }
-        itr++;
-    }
-}
-
-void AnimationController::destroyAllAnimations()
-{
-    std::vector<Animation*>::iterator itr = _animations.begin();
-    
-    while (itr != _animations.end())
-    {
-        Animation* animation = *itr;
-        SAFE_RELEASE(animation);
-        itr++;
-    }
-
-    _animations.clear();
-}
-
 }

+ 5 - 114
gameplay/src/AnimationController.h

@@ -21,91 +21,6 @@ class AnimationController
 
 public:
 
-    /**
-     * Creates an animation on this target from a set of key value and key time pairs. 
-     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
-     * 
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param keyCount The number of keyframes in the animation. Must be greater than one.
-     * @param keyTimes The list of key times for the animation (in milliseconds).
-     * @param keyValues The list of key values for the animation.
-     * @param type The curve interpolation type.
-     *
-     * @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);
-
-    /**
-     * Creates an animation on this target from a set of key value and key time pairs.
-     * 
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param keyCount The number of keyframes in the animation. Must be greater than one.
-     * @param keyTimes The list of key times for the animation (in milliseconds).
-     * @param keyValues The list of key values for the animation.
-     * @param keyInValue The list of key in values for the animation.
-     * @param keyOutValue The list of key out values for the animation.
-     * @param type The curve interpolation type.
-     *
-     * @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);
-
-    /**
-     * 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 animationFile The animation file defining the animation data.
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimation(const char* id, AnimationTarget* target, const char* animationFile);
-
-    /**
-     * Creates a simple two keyframe from-to animation.
-     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
-     *
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param from The values to animate from.
-     * @param to The values to animate to.
-     * @param type The curve interpolation type.
-     * @param duration The duration of the animation (in milliseconds).
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimationFromTo(const char* id, AnimationTarget* target, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration);
-
-    /**
-     * Creates a simple two keyframe from-by animation.
-     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
-     *
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param from The values to animate from.
-     * @param by The values to animate by.
-     * @param type The curve interpolation type.
-     * @param duration The duration of the animation (in milliseconds).
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimationFromBy(const char* id, AnimationTarget* target, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration);
-
-    /**
-     * Finds the animation with the given ID.
-     *
-     * @param id The ID of the animation to get. NULL if the Animation is not found.
-     * 
-     * @return The animation, or NULL if not found.
-     */
-    Animation* getAnimation(const char* id) const;
-
     /** 
      * Stops all AnimationClips currently playing on the AnimationController.
      */
@@ -113,6 +28,9 @@ public:
        
 private:
 
+    /**
+     * The states that the AnimationController may be in.
+     */
     enum State
     {
         RUNNING,
@@ -135,17 +53,6 @@ private:
      * Destructor.
      */
     ~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.
@@ -188,26 +95,10 @@ private:
      * Callback for when the controller receives a frame update event.
      */
     void update(long elapsedTime);
-
-    /**
-     * Adds an animation on this AnimationTarget.
-     */ 
-    void addAnimation(Animation* animation);
-
-    /**
-     * Removes the given animation from this AnimationTarget.
-     */
-    void destroyAnimation(Animation* animation);
-
-    /**
-     * Removes all animations from the AnimationTarget.
-     */ 
-    void destroyAllAnimations();
     
-    State _state;                               // The current state of the AnimationController.
-    std::list<AnimationClip*> _runningClips;    // A list of running AnimationClips.
+    State _state;                                 // The current state of the AnimationController.
+    std::list<AnimationClip*> _runningClips;      // A list of running AnimationClips.
     std::list<AnimationTarget*> _activeTargets;   // A list of animating AnimationTargets.
-    std::vector<Animation*> _animations;        // A list of animations registered with the AnimationController
 };
 
 }

+ 322 - 5
gameplay/src/AnimationTarget.cpp

@@ -2,7 +2,7 @@
 #include "AnimationTarget.h"
 #include "Animation.h"
 #include "Game.h"
-#include "Transform.h"
+#include "Node.h"
 
 namespace gameplay
 {
@@ -20,6 +20,7 @@ AnimationTarget::~AnimationTarget()
         while (itr != _animationChannels->end())
         {
             Animation::Channel* channel = (*itr);
+            channel->_animation->removeChannel(channel);
             SAFE_DELETE(channel);
             itr++;
         }
@@ -28,12 +29,251 @@ AnimationTarget::~AnimationTarget()
     }
 }
 
-void AnimationTarget::addChannel(Animation::Channel* channel)
+Animation* AnimationTarget::createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type)
 {
-    if (_animationChannels == NULL)
-        _animationChannels = new std::vector<Animation::Channel*>;
+    assert(type != Curve::BEZIER && type != Curve::HERMITE);
+    assert(keyCount >= 1 && keyTimes && keyValues);
 
-    _animationChannels->push_back(channel);
+    Animation* animation = new Animation(id, this, propertyId, keyCount, keyTimes, keyValues, type);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type)
+{
+    assert(keyCount >= 1 && keyTimes && keyValues && keyInValue && keyOutValue);
+    Animation* animation = new Animation(id, this, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimation(const char* id, const char* animationFile)
+{
+    assert(animationFile);
+    
+    Properties* p = Properties::create(animationFile);
+    assert(p);
+
+    Animation* animation = createAnimation(id, p->getNextNamespace());
+
+    SAFE_DELETE(p);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimationFromTo(const char* id, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration)
+{
+    const unsigned int propertyComponentCount = getAnimationPropertyComponentCount(propertyId);
+    float* keyValues = new float[2 * propertyComponentCount];
+
+    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
+    memcpy(keyValues + propertyComponentCount, to, sizeof(float) * propertyComponentCount);
+
+    unsigned long* keyTimes = new unsigned long[2];
+    keyTimes[0] = 0;
+    keyTimes[1] = duration;
+
+    Animation* animation = createAnimation(id, propertyId, 2, keyTimes, keyValues, type);
+
+    SAFE_DELETE_ARRAY(keyValues);
+    SAFE_DELETE_ARRAY(keyTimes);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimationFromBy(const char* id, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration)
+{
+    const unsigned int propertyComponentCount = getAnimationPropertyComponentCount(propertyId);
+    float* keyValues = new float[2 * propertyComponentCount];
+
+    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
+    memcpy(keyValues + propertyComponentCount, by, sizeof(float) * propertyComponentCount);
+
+    unsigned long* keyTimes = new unsigned long[2];
+    keyTimes[0] = 0;
+    keyTimes[1] = duration;
+
+    Animation* animation = createAnimation(id, propertyId, 2, keyTimes, keyValues, type);
+
+    SAFE_DELETE_ARRAY(keyValues);
+    SAFE_DELETE_ARRAY(keyTimes);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimation(const char* id, Properties* animationProperties)
+{
+    assert(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(_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 = (unsigned int)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 = (unsigned int)std::string::npos;
+    
+    int componentCount = 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 = (unsigned int)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 = (unsigned int)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, propertyId, keyCount, keyTimes, keyValues, keyIn, keyOut, (Curve::InterpolationType)curve);
+    }
+    else
+    {
+        animation = createAnimation(id, 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;
+}
+
+void AnimationTarget::destroyAnimation(const char* id)
+{
+    // Find the animation with the specified ID.
+    Animation::Channel* channel = getChannel(id);
+    if (channel == NULL)
+        return;
+
+    // Remove this target's channel from animation, and from the target's list of channels.
+    channel->_animation->removeChannel(channel);
+    removeChannel(channel);
+
+    SAFE_DELETE(channel);
+}
+
+Animation* AnimationTarget::getAnimation(const char* id) const
+{
+    if (_animationChannels)
+    {
+        std::vector<Animation::Channel*>::iterator itr = _animationChannels->begin();
+
+        if (id == NULL)
+            return (*itr)->_animation;
+
+        Animation::Channel* channel = NULL;
+        for (; itr != _animationChannels->end(); itr++)
+        {
+            channel = (Animation::Channel*)(*itr);
+            if (channel->_animation->_id.compare(id) == 0)
+            {
+                return channel->_animation;
+            }
+        }
+    }
+
+    return NULL;
 }
 
 int AnimationTarget::getPropertyId(TargetType type, const char* propertyIdStr)
@@ -96,6 +336,83 @@ int AnimationTarget::getPropertyId(TargetType type, const char* propertyIdStr)
     return -1;
 }
 
+void AnimationTarget::addChannel(Animation::Channel* channel)
+{
+    if (_animationChannels == NULL)
+        _animationChannels = new std::vector<Animation::Channel*>;
+
+    _animationChannels->push_back(channel);
+}
+
+void AnimationTarget::removeChannel(Animation::Channel* channel)
+{
+    if (_animationChannels)
+    {
+        std::vector<Animation::Channel*>::iterator itr = _animationChannels->begin();
+        for ( ; itr != _animationChannels->end(); itr++)
+        {
+            Animation::Channel* temp = *itr;
+            if (channel == temp)
+            {
+                _animationChannels->erase(itr);
+
+                if (_animationChannels->empty())
+                    SAFE_DELETE(_animationChannels);
+
+                return;
+            }
+        }
+    }
+}
+
+Animation::Channel* AnimationTarget::getChannel(const char* id) const
+{
+    if (_animationChannels)
+    {
+        std::vector<Animation::Channel*>::iterator itr = _animationChannels->begin();
+
+        if (id == NULL)
+            return (*itr);
+
+        Animation::Channel* channel = NULL;
+        for (; itr != _animationChannels->end(); itr++)
+        {
+            channel = (Animation::Channel*)(*itr);
+            if (channel->_animation->_id.compare(id) == 0)
+            {
+                return channel;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+void AnimationTarget::cloneInto(AnimationTarget* target, NodeCloneContext &context) const
+{
+    if (_animationChannels)
+    {
+        for (std::vector<Animation::Channel*>::const_iterator it = _animationChannels->begin(); it != _animationChannels->end(); ++it)
+        {
+            Animation::Channel* channel = *it;
+            assert(channel->_animation);
+
+            Animation* animation = context.findClonedAnimation(channel->_animation);
+            if (animation != NULL)
+            {
+                Animation::Channel* channelCopy = new Animation::Channel(*channel, animation, target);
+                animation->addChannel(channelCopy);
+            }
+            else
+            {
+                // Clone the animation and register it with the context so that it only gets cloned once.
+                animation = channel->_animation->clone(channel, target);
+                context.registerClonedAnimation(channel->_animation, animation);
+            }
+        }
+    }
+}
+
 }
 
 

+ 139 - 3
gameplay/src/AnimationTarget.h

@@ -9,6 +9,7 @@ namespace gameplay
 
 class Animation;
 class AnimationValue;
+class NodeCloneContext;
 
 /**
  * Defines an interface allowing animation to target
@@ -22,6 +23,94 @@ class AnimationTarget
 
 public:
 
+    /**
+     * Creates an animation on this target from a set of key value and key time pairs. 
+     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
+     * 
+     * @param id The ID of the animation.
+     * @param propertyId The property on this target to animate.
+     * @param keyCount The number of keyframes in the animation. Must be greater than one.
+     * @param keyTimes The list of key times for the animation (in milliseconds).
+     * @param keyValues The list of key values for the animation.
+     * @param type The curve interpolation type.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type);
+
+    /**
+     * Creates an animation on this target from a set of key value and key time pairs.
+     * 
+     * @param id The ID of the animation.
+     * @param propertyId The property on this target to animate.
+     * @param keyCount The number of keyframes in the animation. Must be greater than one.
+     * @param keyTimes The list of key times for the animation (in milliseconds).
+     * @param keyValues The list of key values for the animation.
+     * @param keyInValue The list of key in values for the animation.
+     * @param keyOutValue The list of key out values for the animation.
+     * @param type The curve interpolation type.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type);
+
+    /**
+     * Creates an animation on this target using the data from the given properties object. 
+     * 
+     * @param id The ID of the animation.
+     * @param animationFile The animation file defining the animation data.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, const char* animationFile);
+
+    /**
+     * Creates an animation on this target using the data from the given properties object. 
+     * 
+     * @param id The ID of the animation.
+     * @param animationProperties The properties object defining the animation data.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, Properties* animationProperties);
+
+    /**
+     * Creates a simple two keyframe from-to animation.
+     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
+     *
+     * @param id The ID of the animation.
+     * @param propertyId The property on this target to animate.
+     * @param from The values to animate from.
+     * @param to The values to animate to.
+     * @param type The curve interpolation type.
+     * @param duration The duration of the animation (in milliseconds).
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimationFromTo(const char* id, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration);
+
+    /**
+     * Creates a simple two keyframe from-by animation.
+     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
+     *
+     * @param id The ID of the animation.
+     * @param propertyId The property on this target to animate.
+     * @param from The values to animate from.
+     * @param by The values to animate by.
+     * @param type The curve interpolation type.
+     * @param duration The duration of the animation (in milliseconds).
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimationFromBy(const char* id, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration);
+
+    /**
+     * Destroys the animation with the specified ID. Destroys the first animation if ID is NULL.
+     *
+     * @param id The ID of the animation to destroy.
+     */ 
+    void destroyAnimation(const char* id = NULL);
+
     /**
      * Abstract method to return the property component count of the given property ID on the AnimationTarget.
      * 
@@ -44,11 +133,22 @@ public:
      * 
      * @param propertyId The ID of the property on the AnimationTarget to set the animation property value on.
      * @param value The container to set the animation property value in.
+     * @param blendWeight The blend weight.
      */
     virtual void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f) = 0;
 
+    /** 
+     * Gets the animation with the specified ID. If the ID is NULL, this function will return the first animation it finds.
+     *
+     * @param id The name of the animation to get.
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
 protected:
     
+    /**
+     * The type of animation target. 
+     */
     enum TargetType
     {
         SCALAR,
@@ -65,11 +165,47 @@ protected:
      */
     virtual ~AnimationTarget();
 
-    void addChannel(Animation::Channel* animation);
+    /**
+     * Adds the given animation channel to this animation target.
+     * 
+     * @param channel The animation channel to add.
+     */
+    void addChannel(Animation::Channel* channel);
+
+    /**
+     * Removes the given animation channel from this animation target.
+     * 
+     * @param channel The animation channel to delete.
+     */
+    void removeChannel(Animation::Channel* channel);
+
+    /**
+     * Gets the Animation::Channel that belongs to the Animation with the specified ID.
+     *
+     * @param id The ID of the Animation the Channel belongs to.
+     */
+    Animation::Channel* getChannel(const char* id) const;
+
+    /**
+     * Copies data from this animation target into the given target for the purpose of cloning.
+     * 
+     * @param target The target to copy into.
+     * @param context The clone context.
+     */
+    void cloneInto(AnimationTarget* target, NodeCloneContext &context) const;
 
-    TargetType _targetType;             // The type of target this is.
+    /**
+     * The target's type. 
+     *
+     * @see TargetType::SCALAR
+     * @see TargetType::TRANSFORM
+     */
+    TargetType _targetType;
 
-    char _animationPropertyBitFlag;     // Bit flag used to indicate which properties on the AnimationTarget are currently animating.
+    /**
+     * Bit flag used to indicate which properties on the AnimationTarget are currently animating.
+     */ 
+    unsigned char _animationPropertyBitFlag;
 
 private:
 

+ 136 - 24
gameplay/src/AudioBuffer.cpp

@@ -2,24 +2,47 @@
 #include "AudioBuffer.h"
 #include "FileSystem.h"
 
+#ifdef __ANDROID__
+extern AAssetManager* __assetManager;
+#endif
+
 namespace gameplay
 {
 
 // Audio buffer cache
 static std::vector<AudioBuffer*> __buffers;
 
+#ifndef __ANDROID__
 AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
     : _filePath(path), _alBuffer(buffer)
 {
 }
+#else
+AudioBuffer::AudioBuffer(const char* path) : _filePath(path)
+{
+}
+#endif
 
 AudioBuffer::~AudioBuffer()
 {
+    // Remove the buffer from the cache.
+    unsigned int bufferCount = (unsigned int)__buffers.size();
+    for (unsigned int i = 0; i < bufferCount; i++)
+    {
+        if (this == __buffers[i])
+        {
+            __buffers.erase(__buffers.begin() + i);
+            break;
+        }
+    }
+
+#ifndef __ANDROID__
     if (_alBuffer)
     {
         alDeleteBuffers(1, &_alBuffer);
         _alBuffer = 0;
     }
+#endif
 }
 
 AudioBuffer* AudioBuffer::create(const char* path)
@@ -39,6 +62,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
         }
     }
 
+#ifndef __ANDROID__
     ALuint alBuffer;
     ALCenum al_error;
 
@@ -106,8 +130,58 @@ cleanup:
     if (alBuffer)
         alDeleteBuffers(1, &alBuffer);
     return NULL;
+#else
+    // Get the file header in order to determine the type.
+    AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
+    char header[12];
+    if (AAsset_read(asset, header, 12) != 12)
+    {
+        LOG_ERROR_VARG("Invalid audio buffer file: %s", path);
+        return NULL;
+    }
+
+    // Get the file descriptor for the audio file.
+    off_t start, length;
+    int fd = AAsset_openFileDescriptor(asset, &start, &length);
+    if (fd < 0)
+    {
+        LOG_ERROR_VARG("Failed to open file descriptor for asset: %s", path);
+        return NULL;
+    }
+    AAsset_close(asset);
+    SLDataLocator_AndroidFD data = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};
+
+    // Set the appropriate mime type information.
+    SLDataFormat_MIME mime;
+    mime.formatType = SL_DATAFORMAT_MIME;
+    std::string pathStr = path;
+    if (memcmp(header, "RIFF", 4) == 0)
+    {
+        mime.mimeType = (SLchar*)"audio/x-wav";
+        mime.containerType = SL_CONTAINERTYPE_WAV;
+    }
+    else if (memcmp(header, "OggS", 4) == 0)
+    {
+        mime.mimeType = (SLchar*)"application/ogg";
+        mime.containerType = SL_CONTAINERTYPE_OGG;
+    }
+    else
+    {
+        LOG_ERROR_VARG("Unsupported audio file: %s", path);
+    }
+
+    buffer = new AudioBuffer(path);
+    buffer->_data = data;
+    buffer->_mime = mime;
+
+    // Add the buffer to the cache.
+    __buffers.push_back(buffer);
+
+    return buffer;
+#endif
 }
-    
+
+#ifndef __ANDROID__
 bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
 {
     unsigned char stream[12];
@@ -116,6 +190,12 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
         return false;
     
+    unsigned int section_size;
+    section_size  = stream[7]<<24;
+    section_size |= stream[6]<<16;
+    section_size |= stream[5]<<8;
+    section_size |= stream[4];
+
     // Check for a valid pcm format.
     if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
     {
@@ -153,7 +233,6 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     bits  = stream[1]<<8;
     bits |= stream[0];
     
-
     // Now convert the given channel count and bit depth into an OpenAL format. 
     ALuint format = 0;
     if (bits == 8)
@@ -176,13 +255,45 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         return false;
     }
     
-    // Read the data chunk, which will hold the decoded sample data 
-    if (fread(stream, 1, 4, file) != 4 || memcmp(stream, "data", 4) != 0)
+    // Check against the size of the format header as there may be more data that we need to read
+    if (section_size > 16)
+    {
+        unsigned int length = section_size - 16;
+
+        // extension size is 2 bytes
+        if (fread(stream, 1, length, file) != length)
+            return false;
+    }
+
+    if (fread(stream, 1, 4, file) != 4)
+        return false;
+
+    // read the next chunk, could be fact section or the data section
+    if (memcmp(stream, "fact", 4) == 0)
+    {
+        if (fread(stream, 1, 4, file) != 4)
+            return false;
+
+        section_size  = stream[3]<<24;
+        section_size |= stream[2]<<16;
+        section_size |= stream[1]<<8;
+        section_size |= stream[0];
+
+        // read in the rest of the fact section
+        if (fread(stream, 1, section_size, file) != section_size)
+            return false;
+
+        if (fread(stream, 1, 4, file) != 4)
+            return false;
+    }
+
+    // should now be the data section which holds the decoded sample data
+    if (memcmp(stream, "data", 4) != 0)
     {
         LOG_ERROR("WAV file has no data.");
         return false;
     }
-    
+
     // Read how much data is remaining and buffer it up.
     unsigned int dataSize;
     fread(&dataSize, sizeof(int), 1, file);
@@ -225,34 +336,34 @@ bool AudioBuffer::loadOgg(FILE* file, ALuint buffer)
     else
         format = AL_FORMAT_STEREO16;
 
-	// size = #samples * #channels * 2 (for 16 bit)
+    // size = #samples * #channels * 2 (for 16 bit)
     unsigned int data_size = ov_pcm_total(&ogg_file, -1) * info->channels * 2;
     char* data = new char[data_size];
 
     while (size < data_size)
     {
-    	result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, &section);
-    	if (result > 0)
-    	{
-    		size += result;
-    	}
-    	else if (result < 0)
-    	{
-    		SAFE_DELETE_ARRAY(data);
-    		LOG_ERROR("OGG file missing data.");
-    		return false;
-    	}
-    	else
-    	{
-    		break;
-    	}
+        result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, &section);
+        if (result > 0)
+        {
+            size += result;
+        }
+        else if (result < 0)
+        {
+            SAFE_DELETE_ARRAY(data);
+            LOG_ERROR("OGG file missing data.");
+            return false;
+        }
+        else
+        {
+            break;
+        }
     }
     
     if (size == 0)
     {
-    	SAFE_DELETE_ARRAY(data);
-    	LOG_ERROR("Unable to read OGG data.");
-    	return false;
+        SAFE_DELETE_ARRAY(data);
+        LOG_ERROR("Unable to read OGG data.");
+        return false;
     }
 
     alBufferData(buffer, format, data, data_size, info->rate);
@@ -265,5 +376,6 @@ bool AudioBuffer::loadOgg(FILE* file, ALuint buffer)
 
     return true;
 }
+#endif
 
 }

+ 16 - 2
gameplay/src/AudioBuffer.h

@@ -11,18 +11,25 @@ class AudioSource;
 /**
  * The actual audio buffer data.
  *
- * Currently only supports OpenAL supported formats: .wav, .au and .raw files.
+ * Currently only supports supported formats: .wav, .au and .raw files.
  */
 class AudioBuffer : public Ref
 {
     friend class AudioSource;
 
 private:
-
+    
+#ifndef __ANDROID__
     /**
      * Constructor.
      */
     AudioBuffer(const char* path, ALuint buffer);
+#else
+    /**
+     * Constructor.
+     */
+    AudioBuffer(const char* path);
+#endif
 
     /**
      * Destructor.
@@ -38,12 +45,19 @@ private:
      */
     static AudioBuffer* create(const char* path);
     
+#ifndef __ANDROID__
     static bool loadWav(FILE* file, ALuint buffer);
     
     static bool loadOgg(FILE* file, ALuint buffer);
+#endif
 
     std::string _filePath;
+#ifndef __ANDROID__
     ALuint _alBuffer;
+#else
+    SLDataLocator_AndroidFD _data;
+    SLDataFormat_MIME _mime;
+#endif
 };
 
 }

+ 144 - 4
gameplay/src/AudioController.cpp

@@ -10,17 +10,27 @@ namespace gameplay
 
 std::list<AudioSource*> AudioController::_playingSources;
 
+
+#ifndef __ANDROID__
 AudioController::AudioController() 
     : _alcDevice(NULL), _alcContext(NULL)
 {
 }
+#else
+AudioController::AudioController() 
+    : _engineObject(NULL), _engineEngine(NULL), _outputMixObject(NULL), _listenerObject(NULL),
+    _listenerDoppler(NULL), _listenerLocation(NULL)
+{
+}
+#endif
 
 AudioController::~AudioController()
 {
 }
 
 void AudioController::initialize()
-{    
+{
+#ifndef __ANDROID__
     _alcDevice = alcOpenDevice (NULL);
     if (!_alcDevice)
     {
@@ -28,9 +38,9 @@ void AudioController::initialize()
         return;  
     }
         
-	_alcContext = alcCreateContext(_alcDevice, NULL);
+    _alcContext = alcCreateContext(_alcDevice, NULL);
     ALCenum alcErr = alcGetError(_alcDevice);
-	if (!_alcContext || alcErr != ALC_NO_ERROR)
+    if (!_alcContext || alcErr != ALC_NO_ERROR)
     {
         alcCloseDevice (_alcDevice);
         LOG_ERROR_VARG("AudioController::initialize() error. Unable to create OpenAL context. Error: %d\n", alcErr);
@@ -43,10 +53,52 @@ void AudioController::initialize()
     {
         LOG_ERROR_VARG("AudioController::initialize() error. Unable to make OpenAL context current. Error: %d\n", alcErr);
     }
+#else
+    // Create the engine.
+    SLresult result = slCreateEngine(&_engineObject, 0, NULL, 0, NULL, NULL);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to create OpenSL engine.");
+        return;
+    }
+
+    // Realize the engine.
+    result = (*_engineObject)->Realize(_engineObject, SL_BOOLEAN_FALSE);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to realize OpenSL engine.");
+        return;
+    }
+
+    // Get the engine interface in order to create other objects later on.
+    result = (*_engineObject)->GetInterface(_engineObject, SL_IID_ENGINE, &_engineEngine);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to retrieve OpenSL engine interface.");
+        return;
+    }
+
+    // Create the output mix.
+    result = (*_engineEngine)->CreateOutputMix(_engineEngine, &_outputMixObject, 0, NULL, NULL);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to create OpenSL output mix.");
+        return;
+    }
+
+    // Realize the output mix.
+    result = (*_outputMixObject)->Realize(_outputMixObject, SL_BOOLEAN_FALSE);
+    if (result != SL_RESULT_SUCCESS)
+    {
+        LOG_ERROR("AudioController::initialize() error. Unable to realize OpenSL output mix.");
+        return;
+    }
+#endif
 }
 
 void AudioController::finalize()
 {
+#ifndef __ANDROID__
     alcMakeContextCurrent(NULL);
     if (_alcContext)
     {
@@ -58,6 +110,20 @@ void AudioController::finalize()
         alcCloseDevice(_alcDevice);
         _alcDevice = NULL;
     }
+#else
+    if (_outputMixObject != NULL)
+    {
+        (*_outputMixObject)->Destroy(_outputMixObject);
+        _outputMixObject = NULL;
+    }
+
+    if (_engineObject != NULL)
+    {
+        (*_engineObject)->Destroy(_engineObject);
+        _engineObject = NULL;
+        _engineEngine = NULL;
+    }
+#endif
 }
 
 void AudioController::pause()
@@ -79,6 +145,9 @@ void AudioController::pause()
 
 void AudioController::resume()
 {
+#ifndef __ANDROID__    
+    alcMakeContextCurrent(_alcContext);
+#endif
     std::list<AudioSource*>::iterator itr = _playingSources.begin();
 
     // For each source that is playing, resume it.
@@ -99,10 +168,81 @@ void AudioController::update(long elapsedTime)
     AudioListener* listener = AudioListener::getInstance();
     if (listener)
     {
+#ifndef __ANDROID__
         alListenerf(AL_GAIN, listener->getGain());
-        alListenerfv(AL_ORIENTATION, (ALfloat*)&listener->getOrientationForward());
+        alListenerfv(AL_ORIENTATION, (ALfloat*)listener->getOrientation());
         alListenerfv(AL_VELOCITY, (ALfloat*)&listener->getVelocity());
         alListenerfv(AL_POSITION, (ALfloat*)&listener->getPosition());
+#else
+        if (!_listenerObject)
+        {
+            const SLInterfaceID interfaces[3] = {SL_IID_3DDOPPLER, SL_IID_3DLOCATION};
+            const SLboolean required[3] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};
+            SLresult result = (*_engineEngine)->CreateListener(_engineEngine, &_listenerObject, 2, interfaces, required);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN_VARG("AudioController: failed to create listener (%u).", result);
+                return;
+            }
+
+            result = (*_listenerObject)->Realize(_listenerObject, SL_BOOLEAN_FALSE);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: failed to realize listener.");
+                return;
+            }
+
+            // Get the doppler interface in order to set the listener's velocity.
+            result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DDOPPLER, &_listenerDoppler);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: Unable to retrieve listener doppler interface.");
+                return;
+            }
+
+            // Get the location interface in order to set the listener's position and orientation.
+            result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DLOCATION, &_listenerLocation);
+            if (result != SL_RESULT_SUCCESS)
+            {
+                WARN("AudioController: Unable to retrieve listener location interface.");
+                return;
+            }
+        }
+        
+        SLVec3D f;
+        f.x = listener->getOrientationForward().x;
+        f.y = listener->getOrientationForward().y;
+        f.z = listener->getOrientationForward().z;
+        SLVec3D a;
+        a.x = listener->getOrientationUp().x;
+        a.y = listener->getOrientationUp().y;
+        a.z = listener->getOrientationUp().z;
+        SLresult result = (*_listenerLocation)->SetOrientationVectors(_listenerLocation, &f, &a);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to set listener orientation.");
+        }
+
+        SLVec3D p;
+        p.x = listener->getPosition().x;
+        p.y = listener->getPosition().y;
+        p.z = listener->getPosition().z;
+        result = (*_listenerLocation)->SetLocationCartesian(_listenerLocation, &p);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to set listener location.");
+        }
+
+        SLVec3D v;
+        v.x = listener->getVelocity().x;
+        v.y = listener->getVelocity().y;
+        v.z = listener->getVelocity().z;
+        result = (*_listenerDoppler)->SetVelocityCartesian(_listenerDoppler, &v);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to set listener velocity.");
+        }
+#endif
     }
 }
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff