ソースを参照

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

Conflicts:
	gameplay-samples/sample03-character/src/CharacterGame.cpp
	gameplay-samples/sample03-character/src/CharacterGame.h
	gameplay/src/PhysicsCharacter.cpp
	gameplay/src/PhysicsCollisionObject.cpp
	gameplay/src/PhysicsGhostObject.cpp
Steve Grenier 13 年 前
コミット
8201d7d83e
91 ファイル変更5296 行追加3023 行削除
  1. 3 2
      gameplay-encoder/gameplay-encoder.vcxproj
  2. 9 6
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  3. 18 24
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  4. 1 0
      gameplay-encoder/src/Camera.h
  5. 1346 0
      gameplay-encoder/src/Curve.cpp
  6. 484 0
      gameplay-encoder/src/Curve.h
  7. 36 0
      gameplay-encoder/src/Curve.inl
  8. 1 0
      gameplay-encoder/src/DAEChannelTarget.h
  9. 1 0
      gameplay-encoder/src/DAESceneEncoder.h
  10. 1 0
      gameplay-encoder/src/Effect.h
  11. 3 0
      gameplay-encoder/src/FileIO.h
  12. 15 13
      gameplay-encoder/src/MeshSkin.cpp
  13. 2 2
      gameplay-encoder/src/Reference.h
  14. 3 0
      gameplay/gameplay.vcxproj
  15. 9 0
      gameplay/gameplay.vcxproj.filters
  16. 30 12
      gameplay/gameplay.xcodeproj/project.pbxproj
  17. 3 0
      gameplay/src/AbsoluteLayout.h
  18. 10 39
      gameplay/src/Animation.cpp
  19. 4 26
      gameplay/src/Animation.h
  20. 1 303
      gameplay/src/AnimationController.cpp
  21. 2 119
      gameplay/src/AnimationController.h
  22. 275 6
      gameplay/src/AnimationTarget.cpp
  23. 110 2
      gameplay/src/AnimationTarget.h
  24. 2 2
      gameplay/src/AudioController.cpp
  25. 1 1
      gameplay/src/AudioSource.cpp
  26. 3 3
      gameplay/src/BoundingBox.cpp
  27. 1 1
      gameplay/src/BoundingBox.h
  28. 1 1
      gameplay/src/Button.cpp
  29. 14 5
      gameplay/src/Button.h
  30. 8 8
      gameplay/src/CheckBox.cpp
  31. 13 5
      gameplay/src/CheckBox.h
  32. 26 2
      gameplay/src/Container.cpp
  33. 23 4
      gameplay/src/Container.h
  34. 104 136
      gameplay/src/Control.cpp
  35. 131 63
      gameplay/src/Control.h
  36. 7 1
      gameplay/src/Curve.cpp
  37. 26 11
      gameplay/src/Curve.h
  38. 19 19
      gameplay/src/FileSystem.cpp
  39. 2 2
      gameplay/src/Font.h
  40. 24 31
      gameplay/src/Form.cpp
  41. 20 15
      gameplay/src/Form.h
  42. 6 6
      gameplay/src/Game.cpp
  43. 18 61
      gameplay/src/Game.h
  44. 1 15
      gameplay/src/Game.inl
  45. 7 10
      gameplay/src/Label.cpp
  46. 11 1
      gameplay/src/Label.h
  47. 1 0
      gameplay/src/Material.h
  48. 86 23
      gameplay/src/Node.cpp
  49. 58 49
      gameplay/src/Node.h
  50. 2 1
      gameplay/src/Package.cpp
  51. 1 1
      gameplay/src/ParticleEmitter.cpp
  52. 165 161
      gameplay/src/PhysicsCharacter.cpp
  53. 6 4
      gameplay/src/PhysicsCharacter.h
  54. 14 15
      gameplay/src/PhysicsCollisionObject.cpp
  55. 31 31
      gameplay/src/PhysicsCollisionObject.h
  56. 23 23
      gameplay/src/PhysicsCollisionShape.cpp
  57. 33 33
      gameplay/src/PhysicsCollisionShape.h
  58. 1 1
      gameplay/src/PhysicsConstraint.cpp
  59. 240 240
      gameplay/src/PhysicsController.cpp
  60. 11 11
      gameplay/src/PhysicsController.h
  61. 1 1
      gameplay/src/PhysicsGhostObject.cpp
  62. 1 1
      gameplay/src/PhysicsMotionState.cpp
  63. 4 4
      gameplay/src/PhysicsMotionState.h
  64. 2 2
      gameplay/src/PhysicsRigidBody.cpp
  65. 83 83
      gameplay/src/PhysicsRigidBody.h
  66. 2 2
      gameplay/src/PhysicsRigidBody.inl
  67. 101 102
      gameplay/src/PlatformMacOS.mm
  68. 59 59
      gameplay/src/PlatformQNX.cpp
  69. 4 4
      gameplay/src/PlatformWin32.cpp
  70. 14 8
      gameplay/src/RadioButton.cpp
  71. 39 2
      gameplay/src/RadioButton.h
  72. 11 11
      gameplay/src/Rectangle.cpp
  73. 7 7
      gameplay/src/Rectangle.h
  74. 145 145
      gameplay/src/Scene.cpp
  75. 16 16
      gameplay/src/Scene.h
  76. 11 11
      gameplay/src/SceneLoader.cpp
  77. 2 2
      gameplay/src/SceneLoader.h
  78. 69 0
      gameplay/src/ScreenDisplayer.h
  79. 15 15
      gameplay/src/Slider.cpp
  80. 46 0
      gameplay/src/Slider.h
  81. 80 70
      gameplay/src/TextBox.cpp
  82. 60 4
      gameplay/src/TextBox.h
  83. 127 127
      gameplay/src/Texture.cpp
  84. 4 4
      gameplay/src/Texture.h
  85. 2 466
      gameplay/src/Theme.cpp
  86. 158 315
      gameplay/src/Theme.h
  87. 471 0
      gameplay/src/ThemeStyle.cpp
  88. 223 0
      gameplay/src/ThemeStyle.h
  89. 6 12
      gameplay/src/VerticalLayout.cpp
  90. 23 0
      gameplay/src/VerticalLayout.h
  91. 3 0
      gameplay/src/gameplay.h

+ 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">

+ 18 - 24
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,7 +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 */; };
-		42DDE88515191CDA00D9B550 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42DDE88415191CDA00D9B550 /* libpng.a */; };
+		5BCD0643152CFC3C0071FAB5 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BCD0642152CFC3C0071FAB5 /* libpng.a */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -75,6 +75,10 @@
 /* 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>"; };
+		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; };
@@ -82,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; };
@@ -169,7 +171,7 @@
 		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>"; };
-		42DDE88415191CDA00D9B550 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
+		5BCD0642152CFC3C0071FAB5 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -177,7 +179,6 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				42DDE88515191CDA00D9B550 /* libpng.a in Frameworks */,
 				42D277591472EFA700D867A4 /* libpcre.a in Frameworks */,
 				42D2775A1472EFA700D867A4 /* libpcrecpp.a in Frameworks */,
 				42C8EE351472B60100E43619 /* libfreetype.a in Frameworks */,
@@ -185,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;
 		};
@@ -194,7 +196,6 @@
 		42475CDB147208A000610A6A = {
 			isa = PBXGroup;
 			children = (
-				4283906414896F3000E2B2F5 /* gameplay */,
 				42475CE9147208A000610A6A /* src */,
 				427D4F44147DC9080076760E /* Libraries */,
 				42475CE7147208A000610A6A /* Products */,
@@ -224,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 */,
@@ -273,6 +277,7 @@
 				42C8EDF114724CD700E43619 /* Object.h */,
 				42C8EDF214724CD700E43619 /* Quaternion.cpp */,
 				42C8EDF314724CD700E43619 /* Quaternion.h */,
+				4251B12B152D044B002F6199 /* Quaternion.inl */,
 				42C8EDF414724CD700E43619 /* Reference.cpp */,
 				42C8EDF514724CD700E43619 /* Reference.h */,
 				42C8EDF614724CD700E43619 /* ReferenceTable.cpp */,
@@ -306,6 +311,7 @@
 		427D4F44147DC9080076760E /* Libraries */ = {
 			isa = PBXGroup;
 			children = (
+				5BCD0642152CFC3C0071FAB5 /* libpng.a */,
 				42D277571472EFA700D867A4 /* libpcre.a */,
 				42D277581472EFA700D867A4 /* libpcrecpp.a */,
 				42C8EE3A1472DAAE00E43619 /* libbz2.dylib */,
@@ -313,20 +319,10 @@
 				42C8EE361472D7E700E43619 /* libxml2.dylib */,
 				42C8EE341472B60100E43619 /* libfreetype.a */,
 				42475D7B14720ECE00610A6A /* libdom.a */,
-				42DDE88415191CDA00D9B550 /* libpng.a */,
 			);
 			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 */
@@ -418,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;
 		};
@@ -503,7 +499,7 @@
 		42475CF1147208A100610A6A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
 				CLANG_CXX_LIBRARY = "compiler-default";
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
@@ -523,9 +519,8 @@
 					"\"$(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/libpng/lib/macos\"",
+					"\"$(SRCROOT)\"",
 				);
 				MACH_O_TYPE = mh_execute;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -536,7 +531,7 @@
 		42475CF2147208A100610A6A /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
 				CLANG_CXX_LIBRARY = "compiler-default";
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
@@ -556,9 +551,8 @@
 					"\"$(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/libpng/lib/macos\"",
+					"\"$(SRCROOT)\"",
 				);
 				MACH_O_TYPE = mh_execute;
 				PRODUCT_NAME = "$(TARGET_NAME)";

+ 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.
      */

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

@@ -190,6 +190,7 @@ private:
     static int getVertexUsageType(const std::string& semantic);
     
 private:
+    
     DAE* _collada;        // Collada datastore in memory to read from.
     domCOLLADA* _dom;
     FILE* file;        // Output file to write to.

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

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

+ 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"

+ 15 - 13
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
@@ -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");

+ 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"
 

+ 3 - 0
gameplay/gameplay.vcxproj

@@ -94,6 +94,7 @@
     <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" />
@@ -176,12 +177,14 @@
     <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" />

+ 9 - 0
gameplay/gameplay.vcxproj.filters

@@ -273,6 +273,9 @@
     <ClCompile Include="src\PhysicsCollisionShape.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\ThemeStyle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -539,6 +542,12 @@
     <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>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">

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

@@ -14,6 +14,16 @@
 		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
 		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.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 */; };
 		428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
 		42CCD556146EC1EB00353661 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
@@ -149,8 +159,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 */; };
@@ -212,7 +220,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 */; };
@@ -286,7 +293,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 */; };
@@ -387,6 +393,11 @@
 		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.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; };
 		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; };
 		42C932AF14919FD10098216A /* Game.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Game.inl; path = src/Game.inl; sourceTree = SOURCE_ROOT; };
@@ -541,8 +552,6 @@
 		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; };
@@ -784,6 +793,8 @@
 				5BD5266C150F8257004C9099 /* PhysicsCharacter.h */,
 				5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */,
 				5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */,
+				42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */,
+				42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */,
 				42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */,
 				42CD0E00147D8FF50000361E /* PhysicsConstraint.h */,
 				42CD0E01147D8FF50000361E /* PhysicsConstraint.inl */,
@@ -837,6 +848,7 @@
 				42CD0E2E147D8FF50000361E /* Scene.h */,
 				428390971489D6E800E2B2F5 /* SceneLoader.cpp */,
 				428390981489D6E800E2B2F5 /* SceneLoader.h */,
+				4251B12E152D049B002F6199 /* ScreenDisplayer.h */,
 				5BD52646150F822A004C9099 /* Slider.cpp */,
 				5BD52647150F822A004C9099 /* Slider.h */,
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
@@ -850,6 +862,8 @@
 				5BD5264C150F822A004C9099 /* TimeListener.h */,
 				5BD5264A150F822A004C9099 /* Theme.cpp */,
 				5BD5264B150F822A004C9099 /* Theme.h */,
+				4251B12F152D049B002F6199 /* ThemeStyle.cpp */,
+				4251B130152D049B002F6199 /* ThemeStyle.h */,
 				4208DEED14A407D500D3C511 /* Touch.h */,
 				42CD0E35147D8FF50000361E /* Transform.cpp */,
 				42CD0E36147D8FF50000361E /* Transform.h */,
@@ -868,8 +882,6 @@
 				42CD0E43147D8FF50000361E /* VertexFormat.h */,
 				5BD5264D150F822A004C9099 /* VerticalLayout.cpp */,
 				5BD5264E150F822A004C9099 /* VerticalLayout.h */,
-				42CD0E44147D8FF50000361E /* Viewport.cpp */,
-				42CD0E45147D8FF50000361E /* Viewport.h */,
 			);
 			name = src;
 			path = gameplay;
@@ -1019,7 +1031,6 @@
 				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 */,
@@ -1044,6 +1055,9 @@
 				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 */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1115,7 +1129,6 @@
 				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 */,
@@ -1139,6 +1152,9 @@
 				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 */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1273,7 +1289,6 @@
 				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 */,
@@ -1292,6 +1307,8 @@
 				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 */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1360,7 +1377,6 @@
 				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 */,
@@ -1381,6 +1397,8 @@
 				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 */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 3 - 0
gameplay/src/AbsoluteLayout.h

@@ -16,6 +16,7 @@ class AbsoluteLayout : public Layout
     friend class Container;
 
 public:
+
     /**
      * Get the type of this Layout.
      *
@@ -24,6 +25,7 @@ public:
     Layout::Type getType();
 
 protected:
+
     /**
      * Create an AbsoluteLayout.
      *
@@ -42,6 +44,7 @@ protected:
     void update(const Container* container);
 
 private:
+
     AbsoluteLayout();
     AbsoluteLayout(const AbsoluteLayout& copy);
     virtual ~AbsoluteLayout();

+ 10 - 39
gameplay/src/Animation.cpp

@@ -34,6 +34,8 @@ Animation::Animation(const char* id)
 
 Animation::~Animation()
 {
+    _channels.clear();
+
     if (_defaultClip)
     {
         if (_defaultClip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
@@ -59,58 +61,31 @@ Animation::~Animation()
 }
 
 Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
-    : _animation(animation), _target(target), _propertyId(propertyId), _duration(duration)
+    : _animation(animation), _target(target), _propertyId(propertyId), _curve(curve), _duration(duration)
 {
-    _curveRef = Animation::CurveRef::create(curve);
     // get property component count, and ensure the property exists on the AnimationTarget by getting the property component count.
     assert(_target->getAnimationPropertyComponentCount(propertyId));
 
-    _animation->addRef();
-
     _target->addChannel(this);
 }
 
 Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
-    : _animation(animation), _target(target), _propertyId(copy._propertyId), _duration(copy._duration)
-{
-    _curveRef = copy._curveRef;
-    _curveRef->addRef();
-
-    _animation->addRef();
+    : _animation(animation), _target(target), _propertyId(copy._propertyId), _curve(copy._curve), _duration(copy._duration)
+{
     _target->addChannel(this);
 }
 
 Animation::Channel::~Channel()
 {
-    SAFE_RELEASE(_curveRef);
+    SAFE_RELEASE(_curve);
     SAFE_RELEASE(_animation);
 }
 
 Curve* Animation::Channel::getCurve() const
-{
-    return _curveRef->getCurve();
-}
-
-Animation::CurveRef* Animation::CurveRef::create(Curve* curve)
-{
-    return new CurveRef(curve);
-}
-
-Curve* Animation::CurveRef::getCurve() const
 {
     return _curve;
 }
 
-Animation::CurveRef::CurveRef(Curve* curve)
-    : _curve(curve)
-{
-}
-
-Animation::CurveRef::~CurveRef()
-{
-    SAFE_DELETE(_curve);
-}
-
 const char* Animation::getId() const
 {
     return _id.c_str();
@@ -231,7 +206,7 @@ void Animation::createDefaultClip()
 }
 
 void Animation::createClips(Properties* animationProperties, unsigned int frameCount)
-{   
+{
     assert(animationProperties);
     
     Properties* pClip = animationProperties->getNextNamespace();
@@ -301,7 +276,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);
 
@@ -337,7 +312,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);
     
@@ -385,16 +360,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)
@@ -416,7 +388,6 @@ void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId
 Animation* Animation::clone()
 {
     Animation* animation = new Animation(getId());
-    _controller->addAnimation(animation);
     return animation;
 }
 

+ 4 - 26
gameplay/src/Animation.h

@@ -22,7 +22,6 @@ class AnimationClip;
  */
 class Animation : public Ref
 {
-    friend class AnimationController;
     friend class AnimationClip;
     friend class AnimationTarget;
     friend class Package;
@@ -93,29 +92,9 @@ public:
      * Returns true if this animation targets the given AnimationTarget.
      */
     bool targets(AnimationTarget* target) const;
-
+    
 private:
 
-    /**
-     * Defines a reference counted Curve wrapper.
-     * 
-     * Multiple channels can share the same Curve.
-     */
-    class CurveRef : public Ref
-    {
-    public:
-        static CurveRef* create(Curve* curve);
-        Curve* getCurve() const;
-
-    private:
-        CurveRef(Curve* curve);
-        CurveRef(const CurveRef&); // Hidden copy constructor.
-        ~CurveRef();
-        CurveRef& operator=(const CurveRef&); // Hidden copy assignment operator.
-
-        Curve* _curve;
-    };
-
     /**
      * Defines a channel which holds the target, target property, curve values, and duration.
      *
@@ -124,7 +103,6 @@ private:
      */
     class Channel
     {
-        friend class AnimationController;
         friend class AnimationClip;
         friend class Animation;
         friend class AnimationTarget;
@@ -141,7 +119,7 @@ private:
         Animation* _animation;                // Reference to the animation this channel belongs to.
         AnimationTarget* _target;             // The target of this channel.
         int _propertyId;                      // The target property this channel targets.
-        CurveRef* _curveRef;                  // The curve used to represent the animation data.
+        Curve* _curve;                        // The curve used to represent the animation data.
         unsigned long _duration;              // The length of the animation (in milliseconds).
     };
 
@@ -169,12 +147,12 @@ private:
      * Destructor.
      */
     ~Animation();
-
+    
     /**
      * Hidden copy assignment operator.
      */
     Animation& operator=(const Animation&);
-
+    
     /**
      * Creates the default clip.
      */

+ 1 - 303
gameplay/src/AnimationController.cpp

@@ -7,125 +7,12 @@ namespace gameplay
 {
 
 AnimationController::AnimationController()
-    : _state(STOPPED), _animations(NULL)
+    : _state(STOPPED)
 {
 }
 
 AnimationController::~AnimationController()
 {
-    std::vector<Animation*>::iterator itr = _animations.begin();
-    for ( ; itr != _animations.end(); itr++)
-    {
-        Animation* temp = *itr;
-        SAFE_RELEASE(temp);
-    }
-
-    _animations.clear();
-}
-
-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;
-}
-
-Animation* AnimationController::getAnimation(AnimationTarget* target) const
-{
-    if (!target)
-        return NULL;
-    const unsigned int animationCount = _animations.size();
-    for (unsigned int i = 0; i < animationCount; ++i)
-    {
-        Animation* animation = _animations[i];
-        if (animation->targets(target))
-        {
-            return animation;
-        }
-    }
-    return NULL;
 }
 
 void AnimationController::stopAllAnimations() 
@@ -139,144 +26,6 @@ void AnimationController::stopAllAnimations()
     }
 }
 
-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 = (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 = 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 = (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, target, propertyId, keyCount, keyTimes, keyValues, keyIn, keyOut, (Curve::InterpolationType)curve);
-    }
-    else
-    {
-        animation = createAnimation(id, target, propertyId, keyCount, keyTimes, keyValues, (Curve::InterpolationType) curve);
-    }
-
-    SAFE_DELETE(keyOut);
-    SAFE_DELETE(keyIn);
-    SAFE_DELETE(keyValues);
-    SAFE_DELETE(keyTimes);
-
-    Properties* pClip = animationProperties->getNextNamespace();
-    if (pClip && std::strcmp(pClip->getNamespace(), "clip") == 0)
-    {
-        int frameCount = animationProperties->getInt("frameCount");
-        assert(frameCount > 0);
-        animation->createClips(animationProperties, (unsigned int) frameCount);
-    }
-
-    return animation;
-}
-
 AnimationController::State AnimationController::getState() const
 {
     return _state;
@@ -385,55 +134,4 @@ void AnimationController::update(long elapsedTime)
         _state = IDLE;
 }
 
-void AnimationController::addAnimation(Animation* animation)
-{
-    _animations.push_back(animation);
-}
-
-void AnimationController::destroyAnimation(Animation* animation)
-{
-    assert(animation);
-
-    std::vector<Animation::Channel*>::iterator cItr = animation->_channels.begin();
-    for (; cItr != animation->_channels.end(); cItr++)
-    {
-        Animation::Channel* channel = *cItr;
-        channel->_target->deleteChannel(channel);
-    }
-
-    std::vector<Animation*>::iterator aItr = _animations.begin();
-    while (aItr != _animations.end())
-    {
-        if (animation == *aItr)
-        {
-            Animation* temp = *aItr;
-            SAFE_RELEASE(temp);
-            _animations.erase(aItr);
-            return;
-        }
-        aItr++;
-    }
-}
-
-void AnimationController::destroyAllAnimations()
-{
-    std::vector<Animation*>::iterator aItr = _animations.begin();
-    
-    while (aItr != _animations.end())
-    {
-        Animation* animation = *aItr;
-        std::vector<Animation::Channel*>::iterator cItr = animation->_channels.begin();
-        for (; cItr != animation->_channels.end(); cItr++)
-        {
-            Animation::Channel* channel = *cItr;
-            channel->_target->deleteChannel(channel);
-        }
-
-        SAFE_RELEASE(animation);
-        aItr++;
-    }
-
-    _animations.clear();
-}
-
 }

+ 2 - 119
gameplay/src/AnimationController.h

@@ -21,110 +21,10 @@ 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;
-
-    /**
-     * Returns the first animation that targets the given AnimationTarget.
-     */
-    Animation* getAnimation(AnimationTarget* target) const;
-
     /** 
      * Stops all AnimationClips currently playing on the AnimationController.
      */
     void stopAllAnimations();
-
-    /**
-     * Removes the given animation from this AnimationTarget.
-     */
-    void destroyAnimation(Animation* animation);
-
-    /**
-     * Removes all animations from the AnimationTarget.
-     */ 
-    void destroyAllAnimations();
        
 private:
 
@@ -150,17 +50,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.
@@ -203,16 +92,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);
     
-    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
 };
 
 }

+ 275 - 6
gameplay/src/AnimationTarget.cpp

@@ -29,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)
@@ -97,7 +336,15 @@ int AnimationTarget::getPropertyId(TargetType type, const char* propertyIdStr)
     return -1;
 }
 
-void AnimationTarget::deleteChannel(Animation::Channel* channel)
+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)
     {
@@ -107,7 +354,6 @@ void AnimationTarget::deleteChannel(Animation::Channel* channel)
             Animation::Channel* temp = *itr;
             if (channel == temp)
             {
-                SAFE_DELETE(channel);
                 _animationChannels->erase(itr);
 
                 if (_animationChannels->empty())
@@ -119,6 +365,29 @@ void AnimationTarget::deleteChannel(Animation::Channel* channel)
     }
 }
 
+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)

+ 110 - 2
gameplay/src/AnimationTarget.h

@@ -23,6 +23,100 @@ 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 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, 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, 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, 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 target The animation target.
+     * @param properties 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 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, 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, 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 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.
      * 
@@ -49,6 +143,13 @@ public:
      */
     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:
     
     enum TargetType
@@ -75,11 +176,18 @@ protected:
     void addChannel(Animation::Channel* channel);
 
     /**
-     * Deletes the given animation channel from this animation target.
+     * Removes the given animation channel from this animation target.
      * 
      * @param channel The animation channel to delete.
      */
-    void deleteChannel(Animation::Channel* channel);
+    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.

+ 2 - 2
gameplay/src/AudioController.cpp

@@ -38,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);

+ 1 - 1
gameplay/src/AudioSource.cpp

@@ -466,7 +466,7 @@ void AudioSource::transformChanged(Transform* transform, long cookie)
 #ifndef __ANDROID__
     if (_node)
     {
-    	Vector3 translation = _node->getTranslationWorld();
+        Vector3 translation = _node->getTranslationWorld();
         alSourcefv(_alSource, AL_POSITION, (const ALfloat*)&translation.x);
     }
 #else

+ 3 - 3
gameplay/src/BoundingBox.cpp

@@ -57,9 +57,9 @@ void BoundingBox::getCorners(Vector3* dst) const
 
 Vector3 BoundingBox::getCenter() const
 {
-	Vector3 center;
-	getCenter(&center);
-	return center;
+    Vector3 center;
+    getCenter(&center);
+    return center;
 }
 
 void BoundingBox::getCenter(Vector3* dst) const

+ 1 - 1
gameplay/src/BoundingBox.h

@@ -53,7 +53,7 @@ public:
      */
     static const BoundingBox& empty();
 
-	/**
+    /**
      * Gets the center point of the bounding box.
      *
      * This method computes the center point of the box from its min and max.

+ 1 - 1
gameplay/src/Button.cpp

@@ -14,7 +14,7 @@ namespace gameplay
     Button* Button::create(Theme::Style* style, Properties* properties)
     {
         Button* button = new Button();
-        button->init(style, properties);
+        button->initialize(style, properties);
 
         return button;
     }

+ 14 - 5
gameplay/src/Button.h

@@ -14,9 +14,9 @@ namespace gameplay
  *
  * The following properties are available for buttons:
  *
- * button <Button ID>
+ * button <buttonID>
  * {
- *      style       = <Style ID>
+ *      style       = <styleID>
  *      position    = <x, y>
  *      size        = <width, height>
  *      text        = <string>
@@ -27,6 +27,17 @@ class Button : public Label
     friend class Container;
 
 protected:
+
+    /**
+     * Constructor.
+     */
+    Button();
+
+    /**
+     * Destructor.
+     */
+    virtual ~Button();
+
     /**
      * Create a button with a given style and properties.
      *
@@ -51,10 +62,8 @@ protected:
      */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
-    Button();
-    virtual ~Button();
-
 private:
+
     Button(const Button& copy);
 };
 

+ 8 - 8
gameplay/src/CheckBox.cpp

@@ -22,7 +22,7 @@ CheckBox::~CheckBox()
 CheckBox* CheckBox::create(Theme::Style* style, Properties* properties)
 {
     CheckBox* checkBox = new CheckBox();
-    checkBox->init(style, properties);
+    checkBox->initialize(style, properties);
     properties->getVector2("iconSize", &checkBox->_imageSize);
     checkBox->_checked = properties->getBool("checked");
 
@@ -68,8 +68,8 @@ bool CheckBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int cont
         {
             if (_state == Control::ACTIVE)
             {
-                if (x > 0 && x <= _bounds.width &&
-                    y > 0 && y <= _bounds.height)
+                if (x > 0 && x <= _clipBounds.width &&
+                    y > 0 && y <= _clipBounds.height)
                 {
                     _checked = !_checked;
                     notifyListeners(Control::Listener::VALUE_CHANGED);
@@ -123,7 +123,7 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     // Left, v-center.
     // TODO: Set an alignment for icons.
     const Theme::Border border = getBorder(_state);
-    const Theme::Padding padding = _style->getPadding();
+    const Theme::Padding padding = getPadding();
     float opacity = getOpacity(_state);
 
     if (_checked)
@@ -143,8 +143,8 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             size.set(_imageSize);
         }
 
-        Vector2 pos(clip.x + _position.x + border.left + padding.left,
-            clip.y + _position.y + (_bounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
+        Vector2 pos(clip.x + _bounds.x + border.left + padding.left,
+            clip.y + _bounds.y + (_clipBounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
 
         spriteBatch->draw(pos.x, pos.y, size.x, size.y, selected.u1, selected.v1, selected.u2, selected.v2, selectedColor, _clip);
     }
@@ -165,8 +165,8 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             size.set(_imageSize);
         }
 
-        Vector2 pos(clip.x + _position.x + border.left + padding.left,
-            clip.y + _position.y + (_bounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
+        Vector2 pos(clip.x + _bounds.x + border.left + padding.left,
+            clip.y + _bounds.y + (_clipBounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
 
         spriteBatch->draw(pos.x, pos.y, size.x, size.y, unselected.u1, unselected.v1, unselected.u2, unselected.v2, unselectedColor, _clip);
     }

+ 13 - 5
gameplay/src/CheckBox.h

@@ -14,7 +14,7 @@ namespace gameplay
  *
  * The following properties are available for checkboxes:
  *
- * checkBox <CheckBox ID>
+ * checkBox <checkBoxID>
  * {
  *      style       = <Style ID>
  *      position    = <x, y>
@@ -24,11 +24,12 @@ namespace gameplay
  *      iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.
  * }
  */
-class CheckBox : public Button //, public AnimationClip::Listener
+class CheckBox : public Button
 {
     friend class Container;
 
 public:
+
     /**
      * Gets whether this checkbox is checked.
      *
@@ -63,10 +64,16 @@ public:
      */
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
-  //  virtual void animationEvent(AnimationClip* clip, EventType type);
-
 protected:
+
+    /**
+     * Constructor.
+     */
     CheckBox();
+
+    /**
+     * Destructor.
+     */
     ~CheckBox();
 
     /**
@@ -97,7 +104,7 @@ protected:
      * Called when a control's properties change.  Updates this control's internal rendering
      * properties, such as its text viewport.
      *
-     * @param position The control's position within its container.
+     * @param clip The clipping rectangle of this control's parent container.
      */
     void update(const Rectangle& clip);
 
@@ -113,6 +120,7 @@ protected:
     Vector2 _imageSize;  // The size to draw the checkbox icon, if different from its size in the texture.
 
 private:
+
     CheckBox(const CheckBox& copy);
 };
 

+ 26 - 2
gameplay/src/Container.cpp

@@ -56,7 +56,7 @@ namespace gameplay
     {
         const char* layoutString = properties->getString("layout");
         Container* container = Container::create(getLayoutType(layoutString));
-        container->init(style, properties);
+        container->initialize(style, properties);
         container->addControls(theme, properties);
 
         return container;
@@ -202,6 +202,30 @@ namespace gameplay
         return _controls;
     }
 
+    Animation* Container::getAnimation(const char* id) const
+    {
+        std::vector<Control*>::const_iterator itr = _controls.begin();
+        std::vector<Control*>::const_iterator end = _controls.end();
+        
+        Control* control = NULL;
+        for (; itr != end; itr++)
+        {
+            control = *itr;
+            Animation* animation = control->getAnimation(id);
+            if (animation)
+                return animation;
+
+            if (control->isContainer())
+            {
+                animation = ((Container*)control)->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+
+        return NULL;
+    }
+
     void Container::update(const Rectangle& clip)
     {
         // Update this container's viewport.
@@ -295,7 +319,7 @@ namespace gameplay
                 continue;
             }
 
-            const Rectangle& bounds = control->getBounds();
+            const Rectangle& bounds = control->getClipBounds();
             if (control->getState() != Control::NORMAL ||
                 (evt == Touch::TOUCH_PRESS &&
                  x >= xPos + bounds.x &&

+ 23 - 4
gameplay/src/Container.h

@@ -20,10 +20,11 @@ namespace gameplay
  *      position = <x, y>               // Position of the container on-screen, measured in pixels.
  *      size     = <width, height>      // Size of the container, measured in pixels.
  *   
- *      // All the controls within this container.
- *      container{}
- *      label{}
- *      textBox{}
+ *      // All the nested controls within this container.
+ *      container { }
+
+ *      label { }
+ *      textBox { }
  *      button{}
  *      checkBox{}
  *      radioButton{}
@@ -33,6 +34,7 @@ namespace gameplay
 class Container : public Control
 {
 public:
+
     /**
      * Get this container's layout.
      *
@@ -102,8 +104,24 @@ public:
      */
     std::vector<Control*> getControls() const;
 
+    /**
+     * Gets the first animation in the control with the specified ID.
+     *
+     * @param id The ID of the animation to get. Returns the first animation if ID is NULL.
+     * @return The first animation with the specified ID.
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
 protected:
+
+    /**
+     * Constructor.
+     */
     Container();
+
+    /**
+     * Destructor.
+     */
     virtual ~Container();
 
     /**
@@ -207,6 +225,7 @@ protected:
     std::vector<Control*> _controls;    // List of controls within this container.
 
 private:
+
     Container(const Container& copy);
 };
 

+ 104 - 136
gameplay/src/Control.cpp

@@ -5,8 +5,8 @@
 namespace gameplay
 {
     Control::Control()
-        : _id(""), _state(Control::NORMAL), _position(Vector2::zero()), _size(Vector2::zero()), _bounds(Rectangle::empty()), _clip(Rectangle::empty()),
-            _autoWidth(true), _autoHeight(true), _dirty(true), _consumeTouchEvents(true), _listeners(NULL), _styleOverridden(false)
+        : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _clip(Rectangle::empty()),
+            _dirty(true), _consumeTouchEvents(true), _listeners(NULL), _styleOverridden(false)
     {
     }
 
@@ -18,7 +18,7 @@ namespace gameplay
     {
         if (_listeners)
         {
-            for (ListenerMap::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
+            for (std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
             {
                 std::list<Listener*>* list = itr->second;
                 SAFE_DELETE(list);
@@ -32,14 +32,17 @@ namespace gameplay
         }
     }
 
-    void Control::init(Theme::Style* style, Properties* properties)
+    void Control::initialize(Theme::Style* style, Properties* properties)
     {
         _style = style;
 
-        properties->getVector2("position", &_position);
-        properties->getVector2("size", &_size);
+        Vector2 position;
+        Vector2 size;
+        properties->getVector2("position", &position);
+        properties->getVector2("size", &size);
+        _bounds.set(position.x, position.y, size.x, size.y);
 
-        _state = Control::getStateFromString(properties->getString("state"));
+        _state = Control::getState(properties->getString("state"));
 
         const char* id = properties->getId();
         if (id)
@@ -51,87 +54,59 @@ namespace gameplay
         return _id.c_str();
     }
 
-    void Control::setPosition(float x, float y, unsigned long duration)
+    void Control::setPosition(float x, float y)
     {
-        if (duration > 0L)
-        {
-            AnimationController* animationController = Game::getInstance()->getAnimationController();
-            float from[2] = { _position.x, _position.y };
-            float to[2] = { x, y };
-            Animation* moveAnimation = animationController->createAnimationFromTo("Control::setPosition", this, Control::ANIMATE_POSITION,
-                from, to, gameplay::Curve::QUADRATIC_IN_OUT, duration);
-            AnimationClip* clip = moveAnimation->getClip();
-            clip->play();
-        }
-        else
-        {
-            _position.set(x, y);
-        }
+        _bounds.x = x;
+        _bounds.y = y;
+        _dirty = true;
+    }
 
+    void Control::setSize(float width, float height)
+    {
+        _bounds.width = width;
+        _bounds.height = height;
         _dirty = true;
     }
 
-    const Vector2& Control::getPosition() const
+    void Control::setBounds(const Rectangle& bounds)
     {
-        return _position;
+        _bounds.set(bounds);
     }
 
-    void Control::setSize(float width, float height, unsigned long duration)
+    const Rectangle& Control::getBounds() const
     {
-        if (duration > 0L)
-        {
-            AnimationController* animationController = Game::getInstance()->getAnimationController();
-            float from[2] = { _size.x, _size.y };
-            float to[2] = { width, height };
-            Animation* resizeAnimation = animationController->createAnimationFromTo("Control::setSize", this, Control::ANIMATE_SIZE,
-                from, to, gameplay::Curve::QUADRATIC_IN_OUT, duration);
-            AnimationClip* clip = resizeAnimation->getClip();
-            clip->play();
-        }
-        else
-        {
-            _size.set(width, height);
-        }
+        return _bounds;
+    }
 
-        _dirty = true;
+    float Control::getX() const
+    {
+        return _bounds.x;
     }
 
-    const Vector2& Control::getSize() const
+    float Control::getY() const
     {
-        return _size;
+        return _bounds.y;
     }
 
-    void Control::setOpacity(float opacity, unsigned char states, unsigned long duration)
+    float Control::getWidth() const
+    {
+        return _bounds.width;
+    }
+
+    float Control::getHeight() const
+    {
+        return _bounds.height;
+    }
+
+    void Control::setOpacity(float opacity, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
-            if (duration > 0L)
-            {
-                float from[1] = { overlays[i]->getOpacity() };
-                float to[1] = { opacity };
-
-                // Fun with chaining.
-                Game::getInstance()->getAnimationController()->createAnimationFromTo("Overlay::setOpacity", overlays[i], Theme::Style::Overlay::ANIMATE_OPACITY,
-                    from, to, gameplay::Curve::QUADRATIC_IN_OUT, duration)->getClip()->play();
-            }
-            else
-            {
-                overlays[i]->setOpacity(opacity);
-            }
-        }
-        
-        if (duration > 0L)
-        {
-            // All this animation does is make sure this control sets its dirty flag during the animation.
-            float from[1] = { 0.0f };
-            float to[1] = { 1.0f };
-
-            Game::getInstance()->getAnimationController()->createAnimationFromTo("Control::setOpacity", this, Control::ANIMATE_OPACITY,
-                from, to, gameplay::Curve::QUADRATIC_IN_OUT, duration)->getClip()->play();
+            overlays[i]->setOpacity(opacity);
         }
         
         _dirty = true;
@@ -145,10 +120,10 @@ namespace gameplay
     void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setBorder(top, bottom, left, right);
         }
@@ -164,10 +139,10 @@ namespace gameplay
     void Control::setSkinRegion(const Rectangle& region, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setSkinRegion(region, _style->_tw, _style->_th);
         }
@@ -188,10 +163,10 @@ namespace gameplay
     void Control::setSkinColor(const Vector4& color, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setSkinColor(color);
         }
@@ -229,10 +204,10 @@ namespace gameplay
     void Control::setImageRegion(const char* id, const Rectangle& region, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setImageRegion(id, region, _style->_tw, _style->_th);
         }
@@ -248,10 +223,10 @@ namespace gameplay
     void Control::setImageColor(const char* id, const Vector4& color, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setImageColor(id, color);
         }
@@ -272,10 +247,10 @@ namespace gameplay
     void Control::setCursorRegion(const Rectangle& region, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setCursorRegion(region, _style->_tw, _style->_th);
         }
@@ -291,10 +266,10 @@ namespace gameplay
     void Control::setCursorColor(const Vector4& color, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setCursorColor(color);
         }
@@ -315,10 +290,10 @@ namespace gameplay
     void Control::setFont(Font* font, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setFont(font);
         }
@@ -334,10 +309,10 @@ namespace gameplay
     void Control::setFontSize(unsigned int fontSize, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setFontSize(fontSize);
         }
@@ -353,10 +328,10 @@ namespace gameplay
     void Control::setTextColor(const Vector4& color, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setTextColor(color);
         }
@@ -372,10 +347,10 @@ namespace gameplay
     void Control::setTextAlignment(Font::Justify alignment, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setTextAlignment(alignment);
         }
@@ -391,10 +366,10 @@ namespace gameplay
     void Control::setTextRightToLeft(bool rightToLeft, unsigned char states)
     {
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
 
-        for (int i = 0; i < MAX_OVERLAYS - 1 && overlays[i]; ++i)
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
         {
             overlays[i]->setTextRightToLeft(rightToLeft);
         }
@@ -407,9 +382,9 @@ namespace gameplay
         return getOverlay(state)->getTextRightToLeft();
     }
 
-    const Rectangle& Control::getBounds() const
+    const Rectangle& Control::getClipBounds() const
     {
-        return _bounds;
+        return _clipBounds;
     }
 
     const Rectangle& Control::getClip() const
@@ -417,13 +392,6 @@ namespace gameplay
         return _clip;
     }
 
-    void Control::setAutoSize(bool width, bool height)
-    {
-        _autoWidth = width;
-        _autoHeight = height;
-        _dirty = true;
-    }
-
     void Control::setStyle(Theme::Style* style)
     {
         if (style != _style)
@@ -529,7 +497,7 @@ namespace gameplay
             _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
         }
 
-        ListenerMap::const_iterator itr = _listeners->find(eventType);
+        std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
         if (itr == _listeners->end())
         {
             _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
@@ -558,8 +526,8 @@ namespace gameplay
             notifyListeners(Listener::RELEASE);
 
             // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
-            if (x > 0 && x <= _bounds.width &&
-                y > 0 && y <= _bounds.height)
+            if (x > 0 && x <= _clipBounds.width &&
+                y > 0 && y <= _clipBounds.height)
             {
                 notifyListeners(Listener::CLICK);
             }
@@ -577,7 +545,7 @@ namespace gameplay
     {
         if (_listeners)
         {
-            ListenerMap::const_iterator itr = _listeners->find(eventType);
+            std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
             if (itr != _listeners->end())
             {
                 std::list<Listener*>* listenerList = itr->second;
@@ -592,10 +560,10 @@ namespace gameplay
     void Control::update(const Rectangle& clip)
     {
         // Calculate the bounds.
-        float x = clip.x + _position.x;
-        float y = clip.y + _position.y;
-        float width = _size.x;
-        float height = _size.y;
+        float x = clip.x + _bounds.x;
+        float y = clip.y + _bounds.y;
+        float width = _bounds.width;
+        float height = _bounds.height;
 
         float clipX2 = clip.x + clip.width;
         float x2 = x + width;
@@ -611,7 +579,7 @@ namespace gameplay
             height = clipY2 - y;
         }
 
-        _bounds.set(_position.x, _position.y, width, height);
+        _clipBounds.set(_bounds.x, _bounds.y, width, height);
 
         // Calculate the clipping viewport.
         const Theme::Border& border = getBorder(_state);
@@ -619,8 +587,8 @@ namespace gameplay
 
         x +=  border.left + padding.left;
         y +=  border.top + padding.top;
-        width = _size.x - border.left - padding.left - border.right - padding.right;
-        height = _size.y - border.top - padding.top - border.bottom - padding.bottom;
+        width = _bounds.width - border.left - padding.left - border.right - padding.right;
+        height = _bounds.height - border.top - padding.top - border.bottom - padding.bottom;
 
         _textBounds.set(x, y, width, height);
 
@@ -653,7 +621,7 @@ namespace gameplay
 
     void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
     {
-        Vector2 pos(clip.x + _position.x, clip.y + _position.y);
+        Vector2 pos(clip.x + _bounds.x, clip.y + _bounds.y);
 
         // Get the border and background images for this control's current state.
         //Theme::UVs topLeft, top, topRight, left, center, right, bottomLeft, bottom, bottomRight;
@@ -673,18 +641,18 @@ namespace gameplay
         Vector4 skinColor = getSkinColor(_state);
         skinColor.w *= getOpacity(_state);
 
-        float midWidth = _size.x - border.left - border.right;
-        float midHeight = _size.y - border.top - border.bottom;
+        float midWidth = _bounds.width - border.left - border.right;
+        float midHeight = _bounds.height - border.top - border.bottom;
         float midX = pos.x + border.left;
         float midY = pos.y + border.top;
-        float rightX = pos.x + _size.x - border.right;
-        float bottomY = pos.y + _size.y - border.bottom;
+        float rightX = pos.x + _bounds.width - border.right;
+        float bottomY = pos.y + _bounds.height - border.bottom;
 
         // Draw themed border sprites.
         if (!border.left && !border.right && !border.top && !border.bottom)
         {
             // No border, just draw the image.
-            spriteBatch->draw(pos.x, pos.y, _size.x, _size.y, center.u1, center.v1, center.u2, center.v2, skinColor, clip);
+            spriteBatch->draw(pos.x, pos.y, _bounds.width, _bounds.height, center.u1, center.v1, center.u2, center.v2, skinColor, clip);
         }
         else
         {
@@ -697,7 +665,7 @@ namespace gameplay
             if (border.left)
                 spriteBatch->draw(pos.x, midY, border.left, midHeight, left.u1, left.v1, left.u2, left.v2, skinColor, clip);
             if (border.left && border.right && border.top && border.bottom)
-                spriteBatch->draw(pos.x + border.left, pos.y + border.top, _size.x - border.left - border.right, _size.y - border.top - border.bottom,
+                spriteBatch->draw(pos.x + border.left, pos.y + border.top, _bounds.width - border.left - border.right, _bounds.height - border.top - border.bottom,
                     center.u1, center.v1, center.u2, center.v2, skinColor, clip);
             if (border.right)
                 spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, skinColor, clip);
@@ -728,7 +696,7 @@ namespace gameplay
         return false;
     }
 
-    Control::State Control::getStateFromString(const char* state)
+    Control::State Control::getState(const char* state)
     {
         if (!state)
         {
@@ -781,24 +749,24 @@ namespace gameplay
         switch(propertyId)
         {
         case ANIMATE_POSITION:
-            value->setFloat(0, _position.x);
-            value->setFloat(1, _position.y);
+            value->setFloat(0, _bounds.x);
+            value->setFloat(1, _bounds.y);
             break;
         case ANIMATE_SIZE:
-            value->setFloat(0, _size.x);
-            value->setFloat(1, _size.y);
+            value->setFloat(0, _clipBounds.width);
+            value->setFloat(1, _clipBounds.height);
             break;
         case ANIMATE_POSITION_X:
-            value->setFloat(0, _position.x);
+            value->setFloat(0, _bounds.x);
             break;
         case ANIMATE_POSITION_Y:
-            value->setFloat(0, _position.y);
+            value->setFloat(0, _bounds.y);
             break;
         case ANIMATE_SIZE_WIDTH:
-            value->setFloat(0, _size.x);
+            value->setFloat(0, _clipBounds.width);
             break;
         case ANIMATE_SIZE_HEIGHT:
-            value->setFloat(0, _size.y);
+            value->setFloat(0, _clipBounds.height);
             break;
         case ANIMATE_OPACITY:
         default:
@@ -845,9 +813,9 @@ namespace gameplay
         }
         else
         {
-            x = Curve::lerp(blendWeight, _position.x, x);
+            x = Curve::lerp(blendWeight, _bounds.x, x);
         }
-        _position.x = x;
+        _bounds.x = x;
         _dirty = true;
     }
     
@@ -859,9 +827,9 @@ namespace gameplay
         }
         else
         {
-            y = Curve::lerp(blendWeight, _position.y, y);
+            y = Curve::lerp(blendWeight, _bounds.y, y);
         }
-        _position.y = y;
+        _bounds.y = y;
         _dirty = true;
     }
     
@@ -873,9 +841,9 @@ namespace gameplay
         }
         else
         {
-            width = Curve::lerp(blendWeight, _size.x, width);
+            width = Curve::lerp(blendWeight, _clipBounds.width, width);
         }
-        _size.x = width;
+        _clipBounds.width = width;
         _dirty = true;
     }
 
@@ -887,9 +855,9 @@ namespace gameplay
         }
         else
         {
-            height = Curve::lerp(blendWeight, _size.y, height);
+            height = Curve::lerp(blendWeight, _clipBounds.height, height);
         }
-        _size.y = height;
+        _clipBounds.height = height;
         _dirty = true;
     }
 

+ 131 - 63
gameplay/src/Control.h

@@ -6,14 +6,10 @@
 #include "Vector2.h"
 #include "SpriteBatch.h"
 #include "Theme.h"
+#include "ThemeStyle.h"
 #include "Touch.h"
 #include "Keyboard.h"
 
-/**
- * Default duration of UI animations.
- */
-#define DEFAULT_UI_ANIMATION_DURATION 200L
-
 namespace gameplay
 {
 
@@ -29,32 +25,82 @@ class Control : public Ref, public AnimationTarget
     friend class VerticalLayout;
 
 public:
+
     /**
      * The possible states a control can be in.
      */
     enum State
     {
+        /**
+         * State of an enabled but inactive control.
+         */
         NORMAL = 0x01,
+
+        /**
+         * State of a control currently in focus.
+         */
         FOCUS = 0x02,
+
+        /**
+         * State of a control that is currently being acted on,
+         * e.g. through touch or mouse-click events.
+         */
         ACTIVE = 0x04,
+
+        /**
+         * State of a control that has been disabled.
+         */
         DISABLED = 0x08,
     };
 
-    // Only for setting control states
+    /**
+     * A constant used for setting themed attributes on all control states simultaneously.
+     */
     static const unsigned char STATE_ALL = NORMAL | FOCUS | ACTIVE | DISABLED;
 
+    /**
+     * Implement Control::Listener and call Control::addListener()
+     * in order to listen for events on controls.
+     */
     class Listener
     {
     public:
         enum EventType
         {
+            /**
+             * Mouse-down or touch-press event.
+             */
             PRESS           = 0x01,
+
+            /**
+             * Mouse-up or touch-release event.
+             */
             RELEASE         = 0x02,
+
+            /**
+             * Event triggered after consecutive PRESS and RELEASE events take place
+             * within the bounds of a control.
+             */
             CLICK           = 0x04,
+
+            /**
+             * Event triggered when the value of a slider, check box, or radio button
+             * changes.
+             */
             VALUE_CHANGED   = 0x08,
+
+            /**
+             * Event triggered when the contents of a text box are modified.
+             */
             TEXT_CHANGED    = 0x10
         };
 
+        /**
+         * Method called by controls when an event is triggered.
+         * 
+         * @param control The control triggering the event.
+         * @param evt The event triggered.
+         */
         virtual void controlEvent(Control* control, EventType evt) = 0;
     };
 
@@ -106,33 +152,60 @@ public:
      * @param x The x coordinate.
      * @param y The y coordinate.
      */
-    void setPosition(float x, float y, unsigned long duration = DEFAULT_UI_ANIMATION_DURATION);
+    void setPosition(float x, float y);
 
     /**
-     * Get the position of this control relative to its parent container.
+     * Set the desired size of this control, including its border and padding, before clipping.
      *
-     * @return The position of this control relative to its parent container.
+     * @param width The width.
+     * @param height The height.
      */
-    const Vector2& getPosition() const;
+    void setSize(float width, float height);
 
     /**
-     * Set the desired size of this control, including its border and padding, before clipping.
+     * Set the bounds of this control, relative to its parent container and including its
+     * border and padding, before clipping.
      *
-     * @param width The width.
-     * @param height The height.
+     * @param bounds The new bounds to set.
      */
-    void setSize(float width, float height, unsigned long duration = DEFAULT_UI_ANIMATION_DURATION);
+    void setBounds(const Rectangle& bounds);
 
     /**
-     * Get the desired size of this control, including its border and padding, before clipping.
+     * Get the bounds of this control, relative to its parent container and including its
+     * border and padding, before clipping.
      *
-     * @return The size of this control.
+     * @return The bounds of this control.
      */
-    const Vector2& getSize() const;
+    const Rectangle& getBounds() const;
 
-    // Themed properties.
+    /**
+     * Get the x coordinate of this control's bounds.
+     *
+     * @return The x coordinate of this control's bounds.
+     */
+    float getX() const;
     
-    //void setBorder(const Theme::Border& border, unsigned char states = STATE_ALL);
+    /**
+     * Get the y coordinate of this control's bounds.
+     *
+     * @return The y coordinate of this control's bounds.
+     */
+    float getY() const;
+
+    /**
+     * Get the width of this control's bounds.
+     *
+     * @return The width of this control's bounds.
+     */
+    float getWidth() const;
+
+    /**
+     * Get the height of this control's bounds.
+     *
+     * @return The height of this control's bounds.
+     */
+    float getHeight() const;
+
     /**
      * Set the size of this control's border.
      *
@@ -420,9 +493,8 @@ public:
      * @param opacity The new opacity.
      * @param states The states to set this property on.
      *               One or more members of the Control::State enum, ORed together.
-     * @param duration The duration to animate opacity by.
      */
-    void setOpacity(float opacity, unsigned char states = STATE_ALL, unsigned long duration = DEFAULT_UI_ANIMATION_DURATION);
+    void setOpacity(float opacity, unsigned char states = STATE_ALL);
 
     /**
      * Get the opacity of this control for a given state. 
@@ -433,17 +505,12 @@ public:
      */
     float getOpacity(State state = NORMAL) const;
 
-    // TODO
-    // Controls must state the names of the images they use, for the purposes of a future UI editor.
-    //virtual std::vector<std::string> getImageNames() = 0;
-
-    // Control state.
     /**
      * Get the bounds of this control, relative to its parent container, after clipping.
      *
      * @return The bounds of this control.
      */
-    const Rectangle& getBounds() const;
+    const Rectangle& getClipBounds() const;
 
     /**
      * Get the content area of this control, in screen coordinates, after clipping.
@@ -452,18 +519,6 @@ public:
      */
     const Rectangle& getClip() const;
 
-    /**
-     * Set width and/or height to auto-size to size a Control to tightly fit
-     * its text and themed visual elements (CheckBox / RadioButton toggle etc.).
-     *
-     * Similarly set this on the width and/or height of a Container to tightly fit
-     * the Container around STATE_ALL its children.
-     *
-     * @param width Whether to automatically determine this Control's width.
-     * @param height Whether to automatically determine this Control's height.
-     */
-    void setAutoSize(bool width, bool height);
-
     /**
      * Change this control's state.
      *
@@ -552,7 +607,15 @@ public:
     void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     Control();
+
+    /**
+     * Destructor.
+     */
     virtual ~Control();
 
     /**
@@ -596,16 +659,6 @@ protected:
      */
     virtual void update(const Rectangle& clip);
 
-private:
-    /**
-     * Draws the themed border and background of a control.
-     *
-     * @param spriteBatch The sprite batch containing this control's border images.
-     * @param clip The clipping rectangle of this control's parent container.
-     */
-    virtual void drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-protected:
     /**
      * Draw the images associated with this control.
      *
@@ -624,46 +677,51 @@ protected:
     /**
      * Initialize properties common to STATE_ALL Controls.
      */
-    virtual void init(Theme::Style* style, Properties* properties);
+    virtual void initialize(Theme::Style* style, Properties* properties);
 
     /**
      * Container and classes that extend it should implement this and return true.
+     *
+     * @return true if this object is of class Container, false otherwise.
      */
     virtual bool isContainer();
 
     /**
      * Returns whether this control has been modified and requires an update.
+     *
+     * @return Whether this control has been modified and requires an update.
      */
     virtual bool isDirty();
 
     /**
      * Get a Control::State enum from a matching string.
+     *
+     * @param state The string to match.
+     *
+     * @return The Control::State enum that matches the given string.
      */
-    static State getStateFromString(const char* state);
+    static State getState(const char* state);
 
     /**
-     * Notify STATE_ALL listeners of a specific event.
+     * Notify this control's listeners of a specific event.
+     *
+     * @param eventType The event to trigger.
      */
     void notifyListeners(Listener::EventType eventType);
 
-    void addSpecificListener(Control::Listener* listener, Listener::EventType eventType);
-
     std::string _id;
     State _state;           // Determines overlay used during draw().
-    Vector2 _position;      // Position, relative to parent container's clipping window.
-    Vector2 _size;          // Desired size.  Will be clipped.
-    Rectangle _bounds;      // The position and size of this control, relative to parent container's bounds, including border and padding, after clipping.
+    Rectangle _bounds;      // Position, relative to parent container's clipping window, and desired size.
+    Rectangle _clipBounds;  // The position and size of this control, relative to parent container's bounds, including border and padding, after clipping.
     Rectangle _textBounds;  // The position and size of this control's text area, before clipping.  Used for text alignment.
     Rectangle _clip;        // Clipping window of this control's content, after clipping.
-    bool _autoWidth;
-    bool _autoHeight;
     bool _dirty;
     bool _consumeTouchEvents;
     Theme::Style* _style;
-    typedef std::map<Listener::EventType, std::list<Listener*>*> ListenerMap;
-    ListenerMap* _listeners;
+    std::map<Listener::EventType, std::list<Listener*>*>* _listeners;
 
 private:
+
     // Animation blending bits.
     static const char ANIMATION_POSITION_X_BIT = 0x01;
     static const char ANIMATION_POSITION_Y_BIT = 0x02;
@@ -679,6 +737,18 @@ private:
     void applyAnimationValueSizeHeight(float height, float blendWeight);
     void applyAnimationValueOpacity();
 
+    Control(const Control& copy);
+
+    /**
+     * Draws the themed border and background of a control.
+     *
+     * @param spriteBatch The sprite batch containing this control's border images.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
+    virtual void drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    void addSpecificListener(Control::Listener* listener, Listener::EventType eventType);
+
     // Gets the overlays requested in the overlayTypes bitflag.
     Theme::Style::Overlay** getOverlays(unsigned char overlayTypes, Theme::Style::Overlay** overlays);
 
@@ -689,8 +759,6 @@ private:
 
     // Ensures that this control has a copy of its style so that it can override it without affecting other controls.
     void overrideStyle();
-
-    Control(const Control& copy);
 };
 
 }

+ 7 - 1
gameplay/src/Curve.cpp

@@ -54,6 +54,11 @@ using std::strcmp;
 namespace gameplay
 {
 
+Curve* Curve::create(unsigned int pointCount, unsigned int componentCount)
+{
+    return new Curve(pointCount, componentCount);
+}
+
 Curve::Curve(unsigned int pointCount, unsigned int componentCount)
     : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
 {
@@ -146,8 +151,9 @@ void Curve::evaluate(float time, float* dst) const
 {
     assert(dst && time >= 0 && time <= 1.0f);
 
+    // Check if the point count is 1.
     // Check if we are at or beyond the bounds of the curve.
-    if (time <= _points[0].time)
+    if (_pointCount == 1 || time <= _points[0].time)
     {
         memcpy(dst, _points[0].value, _componentSize);
         return;

+ 26 - 11
gameplay/src/Curve.h

@@ -1,14 +1,17 @@
 #ifndef CURVE_H_
 #define CURVE_H_
 
+#include "Ref.h"
+
 namespace gameplay
 {
 
 /**
  * Represents an n-dimensional curve.
  */
-class Curve
+class Curve : public Ref
 {
+    friend class AnimationTarget;
     friend class Animation;
     friend class AnimationClip;
     friend class AnimationController;
@@ -272,19 +275,13 @@ public:
         BOUNCE_OUT_IN
     };
 
-
     /**
-     * Constructs a new curve and the specified parameters.
-     *
+     * Creates a new curve.
+     * 
      * @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();
+    static Curve* create(unsigned int pointCount, unsigned int componentCount);
 
     /**
      * Gets the number of points in the curve.
@@ -396,10 +393,28 @@ private:
     Curve();
 
     /**
-     * Constructor.
+     * 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);
+
+    /**
+     * Hidden copy constructor.
      */
     Curve(const Curve& copy);
 
+    /**
+     * Destructor.
+     */
+    ~Curve();
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    Curve& operator=(const Curve&);
+
     /**
      * Bezier interpolation function.
      */

+ 19 - 19
gameplay/src/FileSystem.cpp

@@ -117,9 +117,9 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
 #else
     std::string path(FileSystem::getResourcePath());
     if (dirPath && strlen(dirPath) > 0)
-	{
-		path.append(dirPath);
-	}
+    {
+        path.append(dirPath);
+    }
     path.append("/.");
     struct dirent* dp;
     DIR* dir = opendir(path.c_str());
@@ -127,23 +127,23 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
     {
         return false;
     }
-	while ((dp = readdir(dir)) != NULL)
-	{
-		std::string filepath(path);
-		filepath.append("/");
-		filepath.append(dp->d_name);
-
-		struct stat buf;
-		if (!stat(filepath.c_str(), &buf))
-		{
+    while ((dp = readdir(dir)) != NULL)
+    {
+        std::string filepath(path);
+        filepath.append("/");
+        filepath.append(dp->d_name);
+
+        struct stat buf;
+        if (!stat(filepath.c_str(), &buf))
+        {
             // Add to the list if this is not a directory
-			if (!S_ISDIR(buf.st_mode))
-			{
-				files.push_back(dp->d_name);
-			}
-		}
-	}
-	closedir(dir);
+            if (!S_ISDIR(buf.st_mode))
+            {
+                files.push_back(dp->d_name);
+            }
+        }
+    }
+    closedir(dir);
     return true;
 #endif
 }

+ 2 - 2
gameplay/src/Font.h

@@ -150,7 +150,7 @@ public:
      * @param clip A region to clip text within after applying justification to the viewport area.
      */
     void drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size = 0, 
-				  Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false, const Rectangle* clip = NULL);
+                  Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false, const Rectangle* clip = NULL);
 
     /**
      * Measures a string's width and height without alignment, wrapping or clipping.
@@ -237,7 +237,7 @@ private:
     unsigned int _glyphCount;
     Texture* _texture;
     SpriteBatch* _batch;
-	Rectangle _viewport;
+    Rectangle _viewport;
 };
 
 }

+ 24 - 31
gameplay/src/Form.cpp

@@ -58,24 +58,9 @@ namespace gameplay
         // Create new form with given ID, theme and layout.
         const char* themeFile = formProperties->getString("theme");
         const char* layoutString = formProperties->getString("layout");
-        Form* form = Form::create(themeFile, getLayoutType(layoutString));
-
-        Theme* theme = form->_theme;
-        const char* styleName = formProperties->getString("style");
-        form->init(theme->getStyle(styleName), formProperties);
-
-        // Add all the controls to the form.
-        form->addControls(theme, formProperties);
-
-        SAFE_DELETE(properties);
-
-        return form;
-    }
-
-    Form* Form::create(const char* themeFile, Layout::Type type)
-    {
+        
         Layout* layout;
-        switch (type)
+        switch (getLayoutType(layoutString))
         {
         case Layout::LAYOUT_ABSOLUTE:
             layout = AbsoluteLayout::create();
@@ -95,6 +80,15 @@ namespace gameplay
         form->_layout = layout;
         form->_theme = theme;
 
+        //Theme* theme = form->_theme;
+        const char* styleName = formProperties->getString("style");
+        form->initialize(theme->getStyle(styleName), formProperties);
+
+        // Add all the controls to the form.
+        form->addControls(theme, formProperties);
+
+        SAFE_DELETE(properties);
+
         __forms.push_back(form);
 
         return form;
@@ -136,9 +130,9 @@ namespace gameplay
         if (_node && !_quad)
         {
             // Set this Form up to be 3D by initializing a quad, projection matrix and viewport.
-            setQuad(0.0f, 0.0f, _size.x, _size.y);
+            setQuad(0.0f, 0.0f, _bounds.width, _bounds.height);
 
-            Matrix::createOrthographicOffCenter(0, _size.x, _size.y, 0, 0, 1, &_projectionMatrix);
+            Matrix::createOrthographicOffCenter(0, _bounds.width, _bounds.height, 0, 0, 1, &_projectionMatrix);
             _theme->setProjectionMatrix(_projectionMatrix);
             
             _node->setModel(_quad);
@@ -147,7 +141,7 @@ namespace gameplay
 
     void Form::update()
     {
-        Container::update(Rectangle(0, 0, _size.x, _size.y));
+        Container::update(Rectangle(0, 0, _bounds.width, _bounds.height));
     }
 
     void Form::draw()
@@ -168,18 +162,18 @@ namespace gameplay
             {
                 _frameBuffer->bind();
 
-				Game* game = Game::getInstance();
-				Rectangle prevViewport = game->getViewport();
+                Game* game = Game::getInstance();
+                Rectangle prevViewport = game->getViewport();
                 
-				game->setViewport(Rectangle(_position.x, _position.y, _size.x, _size.y));
+                game->setViewport(Rectangle(_bounds.x, _bounds.y, _bounds.width, _bounds.height));
 
                 draw(_theme->getSpriteBatch(), _clip);
 
                 // Rebind the default framebuffer and game viewport.
                 FrameBuffer::bindDefault();
 
-				// restore the previous game viewport
-				game->setViewport(prevViewport);
+                // restore the previous game viewport
+                game->setViewport(prevViewport);
             }
 
             _quad->draw();
@@ -199,7 +193,7 @@ namespace gameplay
 
         // Draw the form's border and background.
         // We don't pass the form's position to itself or it will be applied twice!
-        Control::drawBorder(spriteBatch, Rectangle(0, 0, _size.x, _size.y));
+        Control::drawBorder(spriteBatch, Rectangle(0, 0, _bounds.width, _bounds.height));
 
         // Draw each control's border and background.
         for (it = _controls.begin(); it < _controls.end(); it++)
@@ -244,7 +238,6 @@ namespace gameplay
         // Set the common render state block for the material
         RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
         stateBlock->setDepthWrite(true);
-        //material->setStateBlock(_theme->getSpriteBatch()->getStateBlock());
         material->setStateBlock(stateBlock);
 
         // Bind the WorldViewProjection matrix
@@ -259,7 +252,7 @@ namespace gameplay
         // Use the FrameBuffer to texture the quad.
         if (!_frameBuffer->getRenderTarget())
         {
-            RenderTarget* rt = RenderTarget::create(_id.c_str(), _size.x, _size.y);
+            RenderTarget* rt = RenderTarget::create(_id.c_str(), _bounds.width, _bounds.height);
             _frameBuffer->setRenderTarget(rt);
             SAFE_RELEASE(rt);
         }
@@ -299,7 +292,7 @@ namespace gameplay
 
                         // Unproject point into world space.
                         Ray ray;
-						camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
+                        camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
 
                         // Find the quad's plane.
                         // We know its normal is the quad's forward vector.
@@ -327,7 +320,7 @@ namespace gameplay
                             m.transformPoint(&point);
 
                             // Pass the touch event on.
-                            const Rectangle& bounds = form->getBounds();
+                            const Rectangle& bounds = form->getClipBounds();
                             if (form->getState() == Control::FOCUS ||
                                 (evt == Touch::TOUCH_PRESS &&
                                  point.x >= bounds.x &&
@@ -346,7 +339,7 @@ namespace gameplay
                 else
                 {
                     // Simply compare with the form's bounds.
-                    const Rectangle& bounds = form->getBounds();
+                    const Rectangle& bounds = form->getClipBounds();
                     if (form->getState() == Control::FOCUS ||
                         (evt == Touch::TOUCH_PRESS &&
                          x >= bounds.x &&

+ 20 - 15
gameplay/src/Form.h

@@ -37,13 +37,13 @@ public:
      *      size     = <width, height>      // Size of the form, measured in pixels.
      *   
      *      // All the controls within this form.
-     *      container{}
-     *      label{}
-     *      textBox{}
-     *      button{}
-     *      checkBox{}
-     *      radioButton{}
-     *      slider{}
+     *      container { }
+     *      label { }
+     *      textBox { }
+     *      button { }
+     *      checkBox { }
+     *      radioButton { }
+     *      slider { }
      * }
      *
      * @param path Path to the properties file to create a new form from.
@@ -105,13 +105,22 @@ public:
      */
     void draw();
 
-protected:
+private:
     
-	Form();
+    /**
+     * Constructor.
+     */
+    Form();
 
-    virtual ~Form();
+    /**
+     * Constructor.
+     */
+    Form(const Form& copy);
 
-    static Form* create(const char* textureFile, Layout::Type type);
+    /**
+     * Destructor.
+     */
+    virtual ~Form();
 
     /**
      * Initialize a quad for this form in order to draw it in 3D.
@@ -145,10 +154,6 @@ protected:
     Node* _node;                // Node for transforming this Form in world-space.
     FrameBuffer* _frameBuffer;  // FBO the Form is rendered into for texturing the quad.
     Matrix _projectionMatrix;   // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
-
-private:
-
-    Form(const Form& copy);
 };
 
 }

+ 6 - 6
gameplay/src/Game.cpp

@@ -93,7 +93,7 @@ bool Game::startup()
     if (_state != UNINITIALIZED)
         return false;
 
-	setViewport(Rectangle(0.0f, 0.0f, (float)_width, (float)_height));
+    setViewport(Rectangle(0.0f, 0.0f, (float)_width, (float)_height));
 
     RenderState::initialize();
 
@@ -130,9 +130,9 @@ void Game::shutdown()
         SAFE_DELETE(_audioListener);
 
         RenderState::finalize();
+        
+        _state = UNINITIALIZED;
     }
-
-    _state = UNINITIALIZED;
 }
 
 void Game::pause()
@@ -159,7 +159,7 @@ void Game::resume()
     }
 }
 
-void Game::exit()
+void Game::end()
 {
     shutdown();
 }
@@ -217,8 +217,8 @@ void Game::frame()
 
 void Game::setViewport(const Rectangle& viewport)
 {
-	_viewport = viewport;
-	glViewport((GLuint)viewport.x, (GLuint)viewport.y, (GLuint)viewport.width, (GLuint)viewport.height); 
+    _viewport = viewport;
+    glViewport((GLuint)viewport.x, (GLuint)viewport.y, (GLuint)viewport.width, (GLuint)viewport.height); 
 }
 
 void Game::clear(ClearFlags flags, const Vector4& clearColor, float clearDepth, int clearStencil)

+ 18 - 61
gameplay/src/Game.h

@@ -119,9 +119,9 @@ public:
     void resume();
 
     /**
-     * Exits the game.
+     * Ends the game.
      */
-    void exit();
+    void end();
 
     /**
      * Platform frame delagate.
@@ -152,21 +152,21 @@ public:
      */
     inline unsigned int getHeight() const;
 
-	/**
-	 * Gets the game current viewport.
-	 *
-	 * The default viewport is Rectangle(0, 0, Game::getWidth(), Game::getHeight()).
-	 */
-	inline const Rectangle& getViewport() const;
+    /**
+     * Gets the game current viewport.
+     *
+     * The default viewport is Rectangle(0, 0, Game::getWidth(), Game::getHeight()).
+     */
+    inline const Rectangle& getViewport() const;
 
-	/**
-	 * Set the game current viewport.
-	 *
-	 * The x, y, width and height of the viewport must all be positive.
-	 *
-	 * viewport The custom viewport to be set on the game.
-	 */
-	void setViewport(const Rectangle& viewport);
+    /**
+     * Set the game current viewport.
+     *
+     * The x, y, width and height of the viewport must all be positive.
+     *
+     * viewport The custom viewport to be set on the game.
+     */
+    void setViewport(const Rectangle& viewport);
 
     /**
      * Clears the specified resource buffers to the specified clear values. 
@@ -402,7 +402,7 @@ private:
     unsigned int _frameRate;                    // The current frame rate.
     unsigned int _width;                        // The game's display width.
     unsigned int _height;                       // The game's display height.
-	Rectangle _viewport;						// the games's current viewport.
+    Rectangle _viewport;                        // the games's current viewport.
     Vector4 _clearColor;                        // The clear color value last used for clearing the color buffer.
     float _clearDepth;                          // The clear depth value last used for clearing the depth buffer.
     int _clearStencil;                          // The clear stencil value last used for clearing the stencil buffer.
@@ -414,52 +414,9 @@ private:
 
     // Note: Do not add STL object member variables on the stack; this will cause false memory leaks to be reported.
 
-    friend class SplashDisplayer;
+    friend class ScreenDisplayer;
 };
 
-/**
- * Used for displaying splash screens.
- */
-class SplashDisplayer
-{
-public:
-
-    /**
-     * Displays a splash screen using the {@link Game#renderOnce} mechanism for at least the given amount of time.
-     * 
-     * @param instance See {@link Game#renderOnce}.
-     * @param method See {@link Game#renderOnce}.
-     * @param cookie See {@link Game#renderOnce}.
-     * @param time The minimum amount of time to display the splash screen (in milliseconds).
-     */
-    template <typename T> void run(T* instance, void (T::*method) (void*), void* cookie, long time);
-
-    /**
-     * Destructor.
-     */
-    ~SplashDisplayer();
-
-private:
-
-    long _time;
-    long _startTime;
-};
-
-/**
- * Displays a splash screen using the {@link Game#renderOnce} mechanism for at least the given amount
- * of time. This function is intended to be called at the beginning of a block of code that is be 
- * executed while the splash screen is displayed (i.e. Game#initialize). This function will block 
- * at the end of the block of code in which it is called for the amount of time that has not yet elapsed.
- * 
- * @param instance See {@link Game#renderOnce}.
- * @param method See {@link Game#renderOnce}.
- * @param cookie See {@link Game#renderOnce}.
- * @param time The minimum amount of time to display the splash screen (in milliseconds).
- */
-#define displaySplash(instance, method, cookie, time) \
-    SplashDisplayer __##instance##SplashDisplayer; \
-    __##instance##SplashDisplayer.run(instance, method, cookie, time)
-
 }
 
 #include "Game.inl"

+ 1 - 15
gameplay/src/Game.inl

@@ -26,7 +26,7 @@ inline unsigned int Game::getHeight() const
 
 inline const Rectangle& Game::getViewport() const
 {
-	return _viewport;
+    return _viewport;
 }
 
 inline AnimationController* Game::getAnimationController() const
@@ -71,18 +71,4 @@ inline void Game::displayKeyboard(bool display)
     Platform::displayKeyboard(display);
 }
 
-template <typename T> void SplashDisplayer::run(T* instance, void (T::*method) (void*), void* cookie, long time)
-{
-    _time = time;
-    Game::getInstance()->renderOnce(instance, method, cookie);
-    _startTime = Game::getInstance()->getGameTime();
-}
-
-inline SplashDisplayer::~SplashDisplayer()
-{
-    long elapsedTime = Game::getInstance()->getGameTime() - _startTime;
-    if (elapsedTime < _time)
-        Platform::sleep(_time - (Game::getInstance()->getGameTime() - _startTime));
-}
-
 }

+ 7 - 10
gameplay/src/Label.cpp

@@ -18,14 +18,14 @@ namespace gameplay
     Label* Label::create(Theme::Style* style, Properties* properties)
     {
         Label* label = new Label();
-        label->init(style, properties);
+        label->initialize(style, properties);
 
         return label;
     }
 
-    void Label::init(Theme::Style* style, Properties* properties)
+    void Label::initialize(Theme::Style* style, Properties* properties)
     {
-        Control::init(style, properties);
+        Control::initialize(style, properties);
 
         const char* text = properties->getString("text");
         if (text)
@@ -69,16 +69,13 @@ namespace gameplay
         if (_text.size() <= 0)
             return;
 
-        // TODO: Batch all labels that use the same font.
-        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-        Font* font = overlay->getFont();
-
-        Vector4 textColor = overlay->getTextColor();
-        textColor.w *= overlay->getOpacity();
+        Font* font = getFont(_state);
+        Vector4 textColor = getTextColor(_state);
+        textColor.w *= getOpacity(_state);
 
         // Draw the text.
         font->begin();
-        font->drawText(_text.c_str(), _textBounds, textColor, overlay->getFontSize(), overlay->getTextAlignment(), true, overlay->getTextRightToLeft(), &_clip);
+        font->drawText(_text.c_str(), _textBounds, textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_clip);
         font->end();
 
         _dirty = false;

+ 11 - 1
gameplay/src/Label.h

@@ -25,6 +25,7 @@ class Label : public Control
     friend class Container;
 
 public:
+
     /**
      * Set the text for this label to display.
      *
@@ -52,7 +53,15 @@ public:
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     Label();
+
+    /**
+     * Destructor.
+     */
     virtual ~Label();
 
     /**
@@ -68,7 +77,7 @@ protected:
     /**
      * Initialize this label.
      */
-    virtual void init(Theme::Style* style, Properties* properties);
+    virtual void initialize(Theme::Style* style, Properties* properties);
 
     /**
      * Draw this label's text.
@@ -80,6 +89,7 @@ protected:
     std::string _text;      // The text displayed by this label.
 
 private:
+
     Label(const Label& copy);
 };
 

+ 1 - 0
gameplay/src/Material.h

@@ -23,6 +23,7 @@ class Material : public RenderState
     friend class Technique;
     friend class Pass;
     friend class RenderState;
+    friend class Node;
 
 public:
 

+ 86 - 23
gameplay/src/Node.cpp

@@ -22,7 +22,7 @@ namespace gameplay
 Node::Node(const char* id)
     : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(NULL),
     _nodeFlags(NODE_FLAG_VISIBLE), _camera(NULL), _light(NULL), _model(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL),
-	_collisionObject(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
+    _collisionObject(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
 {
     if (id)
     {
@@ -363,7 +363,7 @@ const Matrix& Node::getWorldMatrix() const
         // If we have a parent, multiply our parent world transform by our local
         // transform to obtain our final resolved world transform.
         Node* parent = getParent();
-		if (parent && (!_collisionObject || _collisionObject->isKinematic()))
+        if (parent && (!_collisionObject || _collisionObject->isKinematic()))
         {
             Matrix::multiply(parent->getWorldMatrix(), getMatrix(), &_world);
         }
@@ -594,6 +594,69 @@ void Node::setBoundsDirty()
         _parent->setBoundsDirty();
 }
 
+Animation* Node::getAnimation(const char* id) const
+{
+    Animation* animation = ((AnimationTarget*)this)->getAnimation(id);
+    if (animation)
+        return animation;
+    
+    // See if this node has a model, then drill down.
+    Model* model = this->getModel();
+    if (model)
+    {
+        // Check to see if there's any animations with the ID on the joints.
+        MeshSkin* skin = model->getSkin();
+        if (skin)
+        {
+            Joint* rootJoint = skin->getRootJoint();
+            if (rootJoint)
+            {
+                animation = rootJoint->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+
+        // Check to see if any of the model's material parameter's has an animation
+        // with the given ID.
+        Material* material = model->getMaterial();
+        if (material)
+        {
+            // How to access material parameters? hidden on the Material::RenderState.
+            std::vector<MaterialParameter*>::iterator itr = material->_parameters.begin();
+            for (; itr != material->_parameters.end(); itr++)
+            {
+                animation = ((MaterialParameter*)(*itr))->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+    }
+
+    // look through form for animations.
+    Form* form = this->getForm();
+    if (form)
+    {
+        animation = form->getAnimation(id);
+        if (animation)
+            return animation;
+    }
+
+    // Look through this node's children for an animation with the specified ID.
+    unsigned int childCount = this->getChildCount();
+    Node* child = this->getFirstChild();
+    for (unsigned int i = 0; i < childCount; i++)
+    {
+        animation = child->getAnimation(id);
+        if (animation)
+            return animation;
+
+        child = child->getNextSibling();
+    }
+    
+    return NULL;
+}
+
 Camera* Node::getCamera() const
 {
     return _camera;
@@ -891,30 +954,30 @@ PhysicsCollisionObject* Node::getCollisionObject() const
 
 PhysicsCollisionObject* Node::setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters)
 {
-	SAFE_DELETE(_collisionObject);
+    SAFE_DELETE(_collisionObject);
 
-	switch (type)
-	{
-	case PhysicsCollisionObject::RIGID_BODY:
-		{
-			_collisionObject = new PhysicsRigidBody(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
-		}
-		break;
+    switch (type)
+    {
+    case PhysicsCollisionObject::RIGID_BODY:
+        {
+            _collisionObject = new PhysicsRigidBody(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
+        }
+        break;
 
-	case PhysicsCollisionObject::GHOST_OBJECT:
-		{
-			_collisionObject = new PhysicsGhostObject(this, shape);
-		}
-		break;
+    case PhysicsCollisionObject::GHOST_OBJECT:
+        {
+            _collisionObject = new PhysicsGhostObject(this, shape);
+        }
+        break;
 
-	case PhysicsCollisionObject::CHARACTER:
-		{
-			_collisionObject = new PhysicsCharacter(this, shape);
-		}
-		break;
-	}
+    case PhysicsCollisionObject::CHARACTER:
+        {
+            _collisionObject = new PhysicsCharacter(this, shape, rigidBodyParameters ? rigidBodyParameters->mass : 1.0f);
+        }
+        break;
+    }
 
-	return _collisionObject;
+    return _collisionObject;
 }
 
 PhysicsCollisionObject* Node::setCollisionObject(const char* filePath)
@@ -960,7 +1023,7 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
     {
         _collisionObject = PhysicsRigidBody::create(this, properties);
     }
-	return _collisionObject;
+    return _collisionObject;
 }
 
 NodeCloneContext::NodeCloneContext()

+ 58 - 49
gameplay/src/Node.h

@@ -343,6 +343,14 @@ public:
      */
     Vector3 getActiveCameraTranslationView() const;
 
+    /**
+     * Gets the first animation in the node hierarchy with the specified ID.
+     *
+     * @param id The ID of the animation to get. Returns the first animation if ID is NULL.
+     * @return The first animation with the specified ID.
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
     /**
      * Returns the pointer to this node's camera.
      *
@@ -431,59 +439,59 @@ public:
      */
     void setParticleEmitter(ParticleEmitter* emitter);
 
-	/**
-	 * Returns the pointer to this node's physics collision object.
-	 *
-	 * The type of the returned collision object can be queried using
-	 * the PhysicsCollisionObject::getType() method.
-	 *
-	 * @return The pointer to this node's physics collision object.
-	 */
-	PhysicsCollisionObject* getCollisionObject() const;
-
-	/**
-	 * Sets (or disables) the physics collision object for this node.
-	 *
-	 * The supported collision object types include rigid bodies, ghost objects and 
-	 * characters.
-	 *
-	 * Rigid bodies are used to represent most physical objects in a game. The important
-	 * feature of rigid bodies is that they can be simulated by the physics system as other
-	 * rigid bodies or collision objects collide with them. To support this physics simulation,
-	 * rigid bodies require additional parameters, such as mass, friction and restitution to
-	 * define their physical features. These parameters can be passed into the
-	 * 'rigidBodyParameters' parameter.
-	 *
-	 * Ghost objects are a simple type of collision object that are not simulated. By default
-	 * they pass through other objects in the scene without affecting them. Ghost objects do
-	 * receive collision events however, which makes them useful for representing non-simulated
-	 * entities in a game that still require collision events, such as volumetric triggers, 
-	 * power-ups, etc.
-	 *
-	 * Characters are an extention of ghost objects which provide a number of additional features
-	 * for animating and moving characters within a game. Characters are represented as ghost
-	 * objects instead of rigid bodies to allow more direct control over character movement,
-	 * since attempting to model a physics character with a simulated rigid body usually results
-	 * in unresponse and unpredictable character movement. Unlike normal ghost objects,
-	 * characters to react to other characters and rigid bodies in the world. Characters react
-	 * to gravity and collide (and respond) with rigid bodies to allow them to walk on the ground,
-	 * slide along walls and walk up/down slopes and stairs.
-	 *
-	 * @param type The type of the collision object to set; to disable the physics
-	 *		collision object, pass PhysicsCollisionObject::NONE.
-	 * @param shape Definition of a physics collision shape to be used for this collision object.
-	 *		Use the static shape methods on the PhysicsCollisionShape class to specificy a shape
-	 *		definition, such as PhysicsCollisionShape::box().
-	 * @param rigidBodyParameters If type is PhysicsCollisionObject::RIGID_BODY, this
-	 *		must point to a valid rigid body parameters object containing information
-	 *		about the rigid body; otherwise, this parmater may be NULL.
-	 */
-	PhysicsCollisionObject* setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters = NULL);
+    /**
+     * Returns the pointer to this node's physics collision object.
+     *
+     * The type of the returned collision object can be queried using
+     * the PhysicsCollisionObject::getType() method.
+     *
+     * @return The pointer to this node's physics collision object.
+     */
+    PhysicsCollisionObject* getCollisionObject() const;
+
+    /**
+     * Sets (or disables) the physics collision object for this node.
+     *
+     * The supported collision object types include rigid bodies, ghost objects and 
+     * characters.
+     *
+     * Rigid bodies are used to represent most physical objects in a game. The important
+     * feature of rigid bodies is that they can be simulated by the physics system as other
+     * rigid bodies or collision objects collide with them. To support this physics simulation,
+     * rigid bodies require additional parameters, such as mass, friction and restitution to
+     * define their physical features. These parameters can be passed into the
+     * 'rigidBodyParameters' parameter.
+     *
+     * Ghost objects are a simple type of collision object that are not simulated. By default
+     * they pass through other objects in the scene without affecting them. Ghost objects do
+     * receive collision events however, which makes them useful for representing non-simulated
+     * entities in a game that still require collision events, such as volumetric triggers, 
+     * power-ups, etc.
+     *
+     * Characters are an extention of ghost objects which provide a number of additional features
+     * for animating and moving characters within a game. Characters are represented as ghost
+     * objects instead of rigid bodies to allow more direct control over character movement,
+     * since attempting to model a physics character with a simulated rigid body usually results
+     * in unresponse and unpredictable character movement. Unlike normal ghost objects,
+     * characters to react to other characters and rigid bodies in the world. Characters react
+     * to gravity and collide (and respond) with rigid bodies to allow them to walk on the ground,
+     * slide along walls and walk up/down slopes and stairs.
+     *
+     * @param type The type of the collision object to set; to disable the physics
+     *        collision object, pass PhysicsCollisionObject::NONE.
+     * @param shape Definition of a physics collision shape to be used for this collision object.
+     *        Use the static shape methods on the PhysicsCollisionShape class to specificy a shape
+     *        definition, such as PhysicsCollisionShape::box().
+     * @param rigidBodyParameters If type is PhysicsCollisionObject::RIGID_BODY, this
+     *        must point to a valid rigid body parameters object containing information
+     *        about the rigid body; otherwise, this parmater may be NULL.
+     */
+    PhysicsCollisionObject* setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters = NULL);
 
     /**
      * Sets the physics collision object for this node using the definition in the given file.
      * 
-     * @param filePath The path to the file that contains the collision object definition.
+     * @param filePath The path to the file that set the collision object definition.
      */
     PhysicsCollisionObject* setCollisionObject(const char* filePath);
 
@@ -596,6 +604,7 @@ protected:
 
     struct UserData
     {
+        UserData() : pointer(NULL), cleanupCallback(NULL) {}
         void* pointer;
         void (*cleanupCallback)(void*);
     };

+ 2 - 1
gameplay/src/Package.cpp

@@ -964,11 +964,12 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
         if (animation == NULL)
         {
             // TODO: This code currently assumes LINEAR only
-            animation = controller->createAnimation(animationId, target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
+            animation = target->createAnimation(animationId, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
         }
         else
         {
             animation->createChannel(target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
+            animation->addRef();
         }
     }
 

+ 1 - 1
gameplay/src/ParticleEmitter.cpp

@@ -50,7 +50,7 @@ ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlendin
     Texture* texture = NULL;
     texture = Texture::create(textureFile, true);    
 
-	if (!texture)
+    if (!texture)
     {
         LOG_ERROR_VARG("Error creating ParticleEmitter: Could not read texture file: %s", textureFile);
         return NULL;

+ 165 - 161
gameplay/src/PhysicsCharacter.cpp

@@ -17,53 +17,53 @@ class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexR
 {
 public:
 
-	ClosestNotMeConvexResultCallback(PhysicsCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
+    ClosestNotMeConvexResultCallback(PhysicsCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
         : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), _me(me), _up(up), _minSlopeDot(minSlopeDot)
-	{
-	}
+    {
+    }
 
-	btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
-	{
+    btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
+    {
         PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(convexResult.m_hitCollisionObject->getUserPointer());
 
-		if (object == _me || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
+        if (object == _me || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
             return 1.0f;
 
         /*
-		btVector3 hitNormalWorld;
-		if (normalInWorldSpace)
-		{
-			hitNormalWorld = convexResult.m_hitNormalLocal;
-		} else
-		{
-			// transform normal into worldspace
-			hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
-		}
-
-		btScalar dotUp = _up.dot(hitNormalWorld);
-		if (dotUp < _minSlopeDot)
+        btVector3 hitNormalWorld;
+        if (normalInWorldSpace)
         {
-			return btScalar(1.0);
-		}
+            hitNormalWorld = convexResult.m_hitNormalLocal;
+        } else
+        {
+            // transform normal into worldspace
+            hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal;
+        }
+
+        btScalar dotUp = _up.dot(hitNormalWorld);
+        if (dotUp < _minSlopeDot)
+        {
+            return btScalar(1.0);
+        }
         */
 
-		return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
-	}
+        return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
+    }
 
 protected:
 
-	PhysicsCollisionObject* _me;
-	const btVector3 _up;
-	btScalar _minSlopeDot;
+    PhysicsCollisionObject* _me;
+    const btVector3 _up;
+    btScalar _minSlopeDot;
 };
 
-PhysicsCharacter::PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape)
+PhysicsCharacter::PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape, float mass)
     : PhysicsGhostObject(node, shape), _moveVelocity(0,0,0), _forwardVelocity(0.0f), _rightVelocity(0.0f),
     _fallVelocity(0, 0, 0), _currentVelocity(0,0,0), _normalizedVelocity(0,0,0),
     _colliding(false), _collisionNormal(0,0,0), _currentPosition(0,0,0),
-    _stepHeight(0.1f), _slopeAngle(0.0f), _cosSlopeAngle(0.0f), _physicsEnabled(true)
+    _stepHeight(0.1f), _slopeAngle(0.0f), _cosSlopeAngle(0.0f), _physicsEnabled(true), _mass(mass)
 {
-	setMaxSlopeAngle(45.0f);
+    setMaxSlopeAngle(45.0f);
 
     // Set the collision flags on the ghost object to indicate it's a character
     _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
@@ -96,8 +96,20 @@ PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
         return NULL;
     }
 
+    // Load the character's parameters.
+    properties->rewind();
+    float mass = 1.0f;
+    const char* name = NULL;
+    while ((name = properties->getNextProperty()) != NULL)
+    {
+        if (strcmp(name, "mass") == 0)
+        {
+            mass = properties->getFloat();
+        }
+    }
+
     // Create the physics character.
-    PhysicsCharacter* character = new PhysicsCharacter(node, *shape);
+    PhysicsCharacter* character = new PhysicsCharacter(node, *shape, mass);
     SAFE_DELETE(shape);
 
     return character;
@@ -357,21 +369,21 @@ void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar d
     {
         _colliding = false;
         int stepCount = 0;
-	    while (fixCollision(collisionWorld))
-	    {
+        while (fixCollision(collisionWorld))
+        {
             _colliding = true;
 
             if (++stepCount > 4)
-		    {
+            {
                 // Most likely we are wedged between a number of different collision objects
-			    break;
-		    }
-	    }
+                break;
+            }
+        }
     }
 
     // Update current and target world positions
-	btVector3 startPosition = _ghostObject->getWorldTransform().getOrigin();
-	_currentPosition = startPosition;
+    btVector3 startPosition = _ghostObject->getWorldTransform().getOrigin();
+    _currentPosition = startPosition;
 
     // Process movement in the up direction
     if (_physicsEnabled)
@@ -381,12 +393,12 @@ void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar d
     stepForwardAndStrafe(collisionWorld, deltaTimeStep);
 
     // Process movement in the down direction
-	if (_physicsEnabled)
-		stepDown(collisionWorld, deltaTimeStep);
+    if (_physicsEnabled)
+        stepDown(collisionWorld, deltaTimeStep);
 
     // Set new position
-	btVector3 translation = _currentPosition - startPosition;
-	_node->translate(translation.x(), translation.y(), translation.z());
+    btVector3 translation = _currentPosition - startPosition;
+    _node->translate(translation.x(), translation.y(), translation.z());
 }
 
 void PhysicsCharacter::stepUp(btCollisionWorld* collisionWorld, btScalar time)
@@ -399,7 +411,7 @@ void PhysicsCharacter::stepUp(btCollisionWorld* collisionWorld, btScalar time)
     // 
     // Note that stepDown() will be called right after this, so the character will move back
     // down to collide with the ground so that he smoothly steps up stairs.
-	_currentPosition += btVector3(0, _stepHeight, 0);
+    _currentPosition += btVector3(0, _stepHeight, 0);
 }
 
 void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, float time)
@@ -449,7 +461,7 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
     {
         // No velocity, so we aren't moving
         return;
-	}
+    }
 
     // Translate the target position by the velocity vector (already scaled by t)
     btVector3 targetPosition = _currentPosition + velocity;
@@ -463,60 +475,60 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
 
     // Check for collisions by performing a bullet convex sweep test
     btTransform start;
-	btTransform end;
-	start.setIdentity();
-	end.setIdentity();
+    btTransform end;
+    start.setIdentity();
+    end.setIdentity();
 
-	btScalar fraction = 1.0;
-	btScalar distance2;
+    btScalar fraction = 1.0;
+    btScalar distance2;
 
-	if (_colliding && (_normalizedVelocity.dot(_collisionNormal) > btScalar(0.0)))
-	{
+    if (_colliding && (_normalizedVelocity.dot(_collisionNormal) > btScalar(0.0)))
+    {
         updateTargetPositionFromCollision(targetPosition, _collisionNormal);
-	}
+    }
 
-	int maxIter = 10;
+    int maxIter = 10;
 
-	while (fraction > btScalar(0.01) && maxIter-- > 0)
-	{
-		start.setOrigin(_currentPosition);
-		end.setOrigin(targetPosition);
+    while (fraction > btScalar(0.01) && maxIter-- > 0)
+    {
+        start.setOrigin(_currentPosition);
+        end.setOrigin(targetPosition);
 
-		btVector3 sweepDirNegative(_currentPosition - targetPosition);
+        btVector3 sweepDirNegative(_currentPosition - targetPosition);
 
-		ClosestNotMeConvexResultCallback callback(this, sweepDirNegative, btScalar(0.0));
-		callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
-		callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
+        ClosestNotMeConvexResultCallback callback(this, sweepDirNegative, btScalar(0.0));
+        callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
+        callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
-		_ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+        _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
 
-		fraction -= callback.m_closestHitFraction;
+        fraction -= callback.m_closestHitFraction;
 
-		if (callback.hasHit())
+        if (callback.hasHit())
         {
-			/*Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
-			PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
-			if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
-			{
-				PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
-				normal.normalize();
-				rb->applyImpulse(-normal);
-			}*/
+            Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
+            PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
+            if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
+            {
+                PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
+                normal.normalize();
+                rb->applyImpulse(_mass * -normal * velocity.length());
+            }
 
             updateTargetPositionFromCollision(targetPosition, callback.m_hitNormalWorld);
 
-			btVector3 currentDir = targetPosition - _currentPosition;
-			distance2 = currentDir.length2();
-			if (distance2 > FLT_EPSILON)
-			{
-				currentDir.normalize();
-
-				// If velocity is against original velocity, stop to avoid tiny oscilations in sloping corners.
-				if (currentDir.dot(_normalizedVelocity) <= btScalar(0.0))
-				{
-					break;
-				}
-			}
+            btVector3 currentDir = targetPosition - _currentPosition;
+            distance2 = currentDir.length2();
+            if (distance2 > FLT_EPSILON)
+            {
+                currentDir.normalize();
+
+                // If velocity is against original velocity, stop to avoid tiny oscilations in sloping corners.
+                if (currentDir.dot(_normalizedVelocity) <= btScalar(0.0))
+                {
+                    break;
+                }
+            }
         }
         else
         {
@@ -531,39 +543,39 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
 void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
 {
     // Contribute basic gravity to fall velocity.
-	btVector3 gravity = Game::getInstance()->getPhysicsController()->_world->getGravity();
+    btVector3 gravity = Game::getInstance()->getPhysicsController()->_world->getGravity();
     _fallVelocity += (gravity * time);
 
     btVector3 targetPosition = _currentPosition + (_fallVelocity * time);
-	targetPosition -= btVector3(0, _stepHeight, 0);
+    targetPosition -= btVector3(0, _stepHeight, 0);
 
     // Perform a convex sweep test between current and target position
-	btTransform start;
-	btTransform end;
-	start.setIdentity();
-	end.setIdentity();
-	start.setOrigin(_currentPosition);
-	end.setOrigin(targetPosition);
+    btTransform start;
+    btTransform end;
+    start.setIdentity();
+    end.setIdentity();
+    start.setOrigin(_currentPosition);
+    end.setOrigin(targetPosition);
 
     ClosestNotMeConvexResultCallback callback(this, btVector3(0, 1, 0), _cosSlopeAngle);
-	callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
-	callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
+    callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
+    callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
-	_ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+    _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
 
-	if (callback.hasHit())
-	{
+    if (callback.hasHit())
+    {
         // Collision detected, fix it
-		_currentPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
+        _currentPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
 
         // Zero out fall velocity when we hit an object
         _fallVelocity.setZero();
-	}
+    }
     else
     {
         // We can move here
         _currentPosition = targetPosition;
-	}
+    }
 }
 
 /*
@@ -571,7 +583,7 @@ void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
  */
 btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal)
 {
-	return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
+    return direction - (btScalar(2.0) * direction.dot(normal)) * normal;
 }
 
 /*
@@ -579,8 +591,8 @@ btVector3 computeReflectionDirection(const btVector3& direction, const btVector3
  */
 btVector3 parallelComponent(const btVector3& direction, const btVector3& normal)
 {
-	btScalar magnitude = direction.dot(normal);
-	return normal * magnitude;
+    btScalar magnitude = direction.dot(normal);
+    return normal * magnitude;
 }
 
 /*
@@ -588,72 +600,64 @@ btVector3 parallelComponent(const btVector3& direction, const btVector3& normal)
  */
 btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal)
 {
-	return direction - parallelComponent(direction, normal);
+    return direction - parallelComponent(direction, normal);
 }
 
 void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPosition, const btVector3& collisionNormal)
 {
-    //btScalar tangentMag = 0.0;
-    //btScalar normalMag = 1.0;
-
-	btVector3 movementDirection = targetPosition - _currentPosition;
-	btScalar movementLength = movementDirection.length();
+    btVector3 movementDirection = targetPosition - _currentPosition;
+    btScalar movementLength = movementDirection.length();
 
-	if (movementLength > FLT_EPSILON)
-	{
-		movementDirection.normalize();
-
-		btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
-		reflectDir.normalize();
+    if (movementLength > FLT_EPSILON)
+    {
+        movementDirection.normalize();
 
-		//btVector3 parallelDir = parallelComponent(reflectDir, collisionNormal);
-		btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
+        btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
+        reflectDir.normalize();
 
-		targetPosition = _currentPosition;
-		/*if (tangentMag != 0.0)
-		{
-			btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
-			targetPosition +=  parComponent;
-		}*/
+        btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
+        targetPosition = _currentPosition;
 
-		//if (normalMag != 0.0)
-		//{
-			btVector3 perpComponent = perpindicularDir * btScalar (/*normalMag **/ movementLength);
-			targetPosition += perpComponent;
-		//}
-	}
+        // Disallow the character from moving up during collision recovery (using an arbitrary reasonable epsilon).
+        // Note that this will need to be generalized to allow for an arbitrary up axis.
+        if (perpindicularDir.y() < _stepHeight + 0.001)
+        {
+            btVector3 perpComponent = perpindicularDir * movementLength;
+            targetPosition += perpComponent;
+        }
+    }
 }
 
 bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
 {
-	bool collision = false;
+    bool collision = false;
 
     btOverlappingPairCache* pairCache = _ghostObject->getOverlappingPairCache();
 
     // Tell the world to dispatch collision events for our ghost object
-	world->getDispatcher()->dispatchAllCollisionPairs(pairCache, world->getDispatchInfo(), world->getDispatcher());
+    world->getDispatcher()->dispatchAllCollisionPairs(pairCache, world->getDispatchInfo(), world->getDispatcher());
 
     // Store our current world position
     Vector3 startPosition;
-	_node->getWorldMatrix().getTranslation(&startPosition);
-	btVector3 currentPosition = BV(startPosition);
+    _node->getWorldMatrix().getTranslation(&startPosition);
+    btVector3 currentPosition = BV(startPosition);
 
     // Handle all collisions/overlappign pairs
-	btScalar maxPenetration = btScalar(0.0);
-	for (int i = 0, count = pairCache->getNumOverlappingPairs(); i < count; ++i)
-	{
-		_manifoldArray.resize(0);
+    btScalar maxPenetration = btScalar(0.0);
+    for (int i = 0, count = pairCache->getNumOverlappingPairs(); i < count; ++i)
+    {
+        _manifoldArray.resize(0);
 
         // Query contacts between this overlapping pair (store in _manifoldArray)
-		btBroadphasePair* collisionPair = &pairCache->getOverlappingPairArray()[i];
-		if (collisionPair->m_algorithm)
+        btBroadphasePair* collisionPair = &pairCache->getOverlappingPairArray()[i];
+        if (collisionPair->m_algorithm)
         {
-			collisionPair->m_algorithm->getAllContactManifolds(_manifoldArray);
+            collisionPair->m_algorithm->getAllContactManifolds(_manifoldArray);
         }
 
-		for (int j = 0, manifoldCount = _manifoldArray.size(); j < manifoldCount; ++j)
-		{
-			btPersistentManifold* manifold = _manifoldArray[j];
+        for (int j = 0, manifoldCount = _manifoldArray.size(); j < manifoldCount; ++j)
+        {
+            btPersistentManifold* manifold = _manifoldArray[j];
 
             // Get the direction of the contact points (used to scale normal vector in the correct direction).
             btScalar directionSign = manifold->getBody0() == _ghostObject ? -1.0f : 1.0f;
@@ -664,35 +668,35 @@ bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
             if (!object || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
                 continue;
 
-			for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
-			{
-				const btManifoldPoint& pt = manifold->getContactPoint(p);
+            for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
+            {
+                const btManifoldPoint& pt = manifold->getContactPoint(p);
 
                 // Get penetration distance for this contact point
-				btScalar dist = pt.getDistance();
+                btScalar dist = pt.getDistance();
 
-				if (dist < 0.0)
-				{
+                if (dist < 0.0)
+                {
                     // A negative distance means the objects are overlapping
-					if (dist < maxPenetration)
-					{
+                    if (dist < maxPenetration)
+                    {
                         // Store collision normal for this point
-						maxPenetration = dist;
+                        maxPenetration = dist;
                         _collisionNormal = pt.m_normalWorldOnB * directionSign;
-					}
+                    }
 
                     // Calculate new position for object, which is translated back along the collision normal
-					currentPosition += pt.m_normalWorldOnB * directionSign * dist * 0.2f;
-					collision = true;
-				}
-			}
-		}
-	}
+                    currentPosition += pt.m_normalWorldOnB * directionSign * dist * 0.2f;
+                    collision = true;
+                }
+            }
+        }
+    }
 
-	// Set the new world transformation to apply to fix the collision
-	_node->translate(Vector3(currentPosition.x(), currentPosition.y(), currentPosition.z()) - startPosition);
+    // Set the new world transformation to apply to fix the collision
+    _node->translate(Vector3(currentPosition.x(), currentPosition.y(), currentPosition.z()) - startPosition);
 
-	return collision;
+    return collision;
 }
 
 void PhysicsCharacter::debugDraw(btIDebugDraw* debugDrawer)

+ 6 - 4
gameplay/src/PhysicsCharacter.h

@@ -258,7 +258,7 @@ public:
     /**
      * @see btActionInterface::debugDraw
      */
-	void debugDraw(btIDebugDraw* debugDrawer);
+    void debugDraw(btIDebugDraw* debugDrawer);
 
 protected:
 
@@ -287,9 +287,10 @@ private:
      * Use PhysicsController::createCharacter to create physics characters.
      *
      * @param node Scene node that represents the character.
-	 * @param shape Physis collision shape definition.
+     * @param shape Physis collision shape definition.
+     * @param mass The mass of the character.
      */
-	PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape);
+    PhysicsCharacter(Node* node, const PhysicsCollisionShape::Definition& shape, float mass);
 
     /**
      * Destructor.
@@ -333,11 +334,12 @@ private:
     btVector3 _currentPosition;
     std::map<const char*, CharacterAnimation> _animations;
     std::map<unsigned int, CharacterAnimation*> _layers;
-    btManifoldArray	_manifoldArray;
+    btManifoldArray _manifoldArray;
     float _stepHeight;
     float _slopeAngle;
     float _cosSlopeAngle;
     bool _physicsEnabled;
+    float _mass;
 };
 
 }

+ 14 - 15
gameplay/src/PhysicsCollisionObject.cpp

@@ -10,46 +10,46 @@ namespace gameplay
 struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
 {
     btScalar addSingleResult(btManifoldPoint& cp, 
-		const btCollisionObject* a, int partIdA, int indexA, 
-		const btCollisionObject* b, int partIdB, int indexB)
-	{
-		result = true;
-		return 0.0f;
-	}
+        const btCollisionObject* a, int partIdA, int indexA, 
+        const btCollisionObject* b, int partIdB, int indexB)
+    {
+        result = true;
+        return 0.0f;
+    }
 
     bool result;
 };
 
 PhysicsCollisionObject::PhysicsCollisionObject(Node* node)
-	: _node(node), _motionState(NULL), _collisionShape(NULL)
+    : _node(node), _motionState(NULL), _collisionShape(NULL)
 {
 }
 
 PhysicsCollisionObject::~PhysicsCollisionObject()
 {
-	SAFE_DELETE(_motionState);
+    SAFE_DELETE(_motionState);
 
-	Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
+    Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
 }
 
 PhysicsCollisionShape::Type PhysicsCollisionObject::getShapeType() const
 {
-	return getCollisionShape()->getType();
+    return getCollisionShape()->getType();
 }
 
 Node* PhysicsCollisionObject::getNode() const
 {
-	return _node;
+    return _node;
 }
 
 PhysicsCollisionShape* PhysicsCollisionObject::getCollisionShape() const
 {
-	return _collisionShape;
+    return _collisionShape;
 }
 
 PhysicsMotionState* PhysicsCollisionObject::getMotionState() const
 {
-	return _motionState;
+    return _motionState;
 }
 
 bool PhysicsCollisionObject::isKinematic() const
@@ -62,12 +62,11 @@ bool PhysicsCollisionObject::isKinematic() const
     default:
         return getCollisionObject()->isKinematicObject();
     }
-	
 }
 
 bool PhysicsCollisionObject::isDynamic() const
 {
-	return !getCollisionObject()->isStaticOrKinematicObject();
+    return !getCollisionObject()->isStaticOrKinematicObject();
 }
 
 void PhysicsCollisionObject::addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)

+ 31 - 31
gameplay/src/PhysicsCollisionObject.h

@@ -16,7 +16,7 @@ class Node;
 class PhysicsCollisionObject
 {
     friend class PhysicsController;
-	friend class PhysicsConstraint;
+    friend class PhysicsConstraint;
 
 public:
 
@@ -40,10 +40,10 @@ public:
          */
         GHOST_OBJECT,
 
-		/**
-		 * No collision object.
-		 */
-		NONE
+        /**
+         * No collision object.
+         */
+        NONE
     };
 
     /** 
@@ -122,7 +122,7 @@ public:
                                     const Vector3& contactPointB = Vector3::zero()) = 0;
     };
 
-	/**
+    /**
      * Virtual destructor.
      */
     virtual ~PhysicsCollisionObject();
@@ -132,38 +132,38 @@ public:
      */
     virtual PhysicsCollisionObject::Type getType() const = 0;
 
-	/**
-	 * Returns the type of the shape for this collision object.
-	 */
-	PhysicsCollisionShape::Type getShapeType() const;
+    /**
+     * Returns the type of the shape for this collision object.
+     */
+    PhysicsCollisionShape::Type getShapeType() const;
 
     /**
      * Returns the node associated with this collision object.
      */
     Node* getNode() const;
 
-	/**
+    /**
      * Returns the collision shape.
      *
      * @return The collision shape.
      */
     PhysicsCollisionShape* getCollisionShape() const;
 
-	/**
-	 * Returns whether this collision object is kinematic.
-	 *
-	 * A kinematic collision object is an object that is not simulated by
-	 * the physics system and instead has its transform driven manually.
-	 *
-	 * @return Whether the collision object is kinematic.
-	 */
-	bool isKinematic() const;
+    /**
+     * Returns whether this collision object is kinematic.
+     *
+     * A kinematic collision object is an object that is not simulated by
+     * the physics system and instead has its transform driven manually.
+     *
+     * @return Whether the collision object is kinematic.
+     */
+    bool isKinematic() const;
 
     /**
      * Returns whether this collision object is dynamic.
-	 *
-	 * A dynamic collision object is simulated entirely by the physics system,
-	 * such as with dynamic rigid bodies. 
+     *
+     * A dynamic collision object is simulated entirely by the physics system,
+     * such as with dynamic rigid bodies. 
      *
      * @return Whether the collision object is dynamic.
      */
@@ -207,15 +207,15 @@ protected:
      */
     virtual btCollisionObject* getCollisionObject() const = 0;
 
-	/**
-	 * Returns the physics motion state.
-	 *
-	 * @return The motion state object.
-	 */
-	PhysicsMotionState* getMotionState() const;
+    /**
+     * Returns the physics motion state.
+     *
+     * @return The motion state object.
+     */
+    PhysicsMotionState* getMotionState() const;
 
-	// Common member variables
-	Node* _node;
+    // Common member variables
+    Node* _node;
     PhysicsMotionState* _motionState;
     PhysicsCollisionShape* _collisionShape;
 

+ 23 - 23
gameplay/src/PhysicsCollisionShape.cpp

@@ -14,7 +14,7 @@ PhysicsCollisionShape::PhysicsCollisionShape(Type type, btCollisionShape* shape)
 
 PhysicsCollisionShape::PhysicsCollisionShape(const PhysicsCollisionShape& copy)
 {
-	// hidden
+    // hidden
 }
 
 PhysicsCollisionShape::~PhysicsCollisionShape()
@@ -331,13 +331,13 @@ PhysicsCollisionShape::Definition PhysicsCollisionShape::box()
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::box(const Vector3& extents, const Vector3& center, bool absolute)
 {
-	Definition d;
-	d.type = SHAPE_BOX;
-	memcpy(d.data.box.extents, &extents.x, sizeof(float) * 3);
-	memcpy(d.data.box.center, &center.x, sizeof(float) * 3);
-	d.isExplicit = true;
-	d.centerAbsolute = absolute;
-	return d;
+    Definition d;
+    d.type = SHAPE_BOX;
+    memcpy(d.data.box.extents, &extents.x, sizeof(float) * 3);
+    memcpy(d.data.box.center, &center.x, sizeof(float) * 3);
+    d.isExplicit = true;
+    d.centerAbsolute = absolute;
+    return d;
 }
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
@@ -351,13 +351,13 @@ PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere()
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::sphere(float radius, const Vector3& center, bool absolute)
 {
-	Definition d;
-	d.type = SHAPE_SPHERE;
-	d.data.sphere.radius = radius;
-	memcpy(d.data.sphere.center, &center.x, sizeof(float) * 3);
-	d.isExplicit  = true;
-	d.centerAbsolute = absolute;
-	return d;
+    Definition d;
+    d.type = SHAPE_SPHERE;
+    d.data.sphere.radius = radius;
+    memcpy(d.data.sphere.center, &center.x, sizeof(float) * 3);
+    d.isExplicit  = true;
+    d.centerAbsolute = absolute;
+    return d;
 }
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
@@ -371,14 +371,14 @@ PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule()
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::capsule(float radius, float height, const Vector3& center, bool absolute)
 {
-	Definition d;
-	d.type = SHAPE_CAPSULE;
-	d.data.capsule.radius = radius;
-	d.data.capsule.height = height;
-	memcpy(d.data.capsule.center, &center.x, sizeof(float) * 3);
-	d.isExplicit = true;
-	d.centerAbsolute = absolute;
-	return d;
+    Definition d;
+    d.type = SHAPE_CAPSULE;
+    d.data.capsule.radius = radius;
+    d.data.capsule.height = height;
+    memcpy(d.data.capsule.center, &center.x, sizeof(float) * 3);
+    d.isExplicit = true;
+    d.centerAbsolute = absolute;
+    return d;
 }
 
 PhysicsCollisionShape::Definition PhysicsCollisionShape::heightfield(Image* image)

+ 33 - 33
gameplay/src/PhysicsCollisionShape.h

@@ -69,19 +69,19 @@ public:
         // Shape type.
         PhysicsCollisionShape::Type type;
 
-		// Shape data.
-		struct BoxData { float center[3], extents[3]; };
-		struct SphereData { float center[3]; float radius; };
-		struct CapsuleData { float center[3]; float radius, height; };
+        // Shape data.
+        struct BoxData { float center[3], extents[3]; };
+        struct SphereData { float center[3]; float radius; };
+        struct CapsuleData { float center[3]; float radius, height; };
 
         union
         {
-			BoxData box;
-			SphereData sphere;
-			CapsuleData capsule;
-			Image* heightfield;
-			Mesh* mesh;
-		} data;
+            BoxData box;
+            SphereData sphere;
+            CapsuleData capsule;
+            Image* heightfield;
+            Mesh* mesh;
+        } data;
 
         // Whether the shape definition is explicit, or if it is inherited from node bounds.
         bool isExplicit;
@@ -97,15 +97,15 @@ public:
      */
     PhysicsCollisionShape::Type getType() const;
 
-	/**
-	 * Returns the internal bullet physics shape object.
-	 *
-	 * @return The bullet shape object.
-	 */
-	btCollisionShape* getShape() const
-	{
-		return _shape;
-	}
+    /**
+     * Returns the internal bullet physics shape object.
+     *
+     * @return The bullet shape object.
+     */
+    btCollisionShape* getShape() const
+    {
+        return _shape;
+    }
 
     /**
      * Defines a box shape, using the bounding volume of the node it is attached to.
@@ -120,8 +120,8 @@ public:
      * @param extents Extents of the box shape along the x, y and z axes.
      * @param center Center point of the box.
      * @param absolute True to specifiy that the given center point is an absolute position.
-     *		By default the center point is treated as relative to the location of the node
-     *		that the shape is attached to.
+     *        By default the center point is treated as relative to the location of the node
+     *        that the shape is attached to.
      *
      * @return Definition of a box shape.
      */
@@ -140,8 +140,8 @@ public:
      * @param radius Radius of the sphere.
      * @param center Center point of the sphere.
      * @param absolute True to specifiy that the given center point is an absolute position.
-     *		By default the center point is treated as relative to the location of the node
-     *		that the shape is attached to.
+     *        By default the center point is treated as relative to the location of the node
+     *        that the shape is attached to.
      *
      * @return Definition of a sphere shape.
      */
@@ -161,8 +161,8 @@ public:
      * @param height Height of the capsule.
      * @param center Center point of the capsule.
      * @param absolute True to specifiy that the given center point is an absolute position.
-     *		By default the center point is treated as relative to the location of the node
-     *		that the shape is attached to.
+     *        By default the center point is treated as relative to the location of the node
+     *        that the shape is attached to.
      *
      * @return Definition of a capsule shape.
      */
@@ -204,15 +204,15 @@ private:
      */
     PhysicsCollisionShape(Type type, btCollisionShape* shape);
 
-	/** 
-	 * Hidden copy constructor.
-	 */
-	PhysicsCollisionShape(const PhysicsCollisionShape& copy);
+    /** 
+     * Hidden copy constructor.
+     */
+    PhysicsCollisionShape(const PhysicsCollisionShape& copy);
 
-	/**
-	 * Destructor.
-	 */
-	~PhysicsCollisionShape();
+    /**
+     * Destructor.
+     */
+    ~PhysicsCollisionShape();
 
     // Shape type
     Type _type;

+ 1 - 1
gameplay/src/PhysicsConstraint.cpp

@@ -155,7 +155,7 @@ Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)
 
 Vector3 PhysicsConstraint::offsetByCenterOfMass(const Node* node, const Vector3& v)
 {
-	btVector3 centerOfMassOffset = (node->getCollisionObject()->getMotionState())->_centerOfMassOffset.getOrigin();
+    btVector3 centerOfMassOffset = (node->getCollisionObject()->getMotionState())->_centerOfMassOffset.getOrigin();
     return Vector3(v.x + centerOfMassOffset.x(), v.y + centerOfMassOffset.y(), v.z + centerOfMassOffset.z());
 }
 

+ 240 - 240
gameplay/src/PhysicsController.cpp

@@ -313,7 +313,7 @@ void PhysicsController::initialize()
     _ghostPairCallback = bullet_new<btGhostPairCallback>();
     _world->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback);
 
-	_world->getDispatchInfo().m_allowedCcdPenetration = 0.0001f;
+    _world->getDispatchInfo().m_allowedCcdPenetration = 0.0001f;
 
     // Set up debug drawing.
     _debugDrawer = new DebugDrawer();
@@ -482,15 +482,15 @@ void PhysicsController::addCollisionObject(PhysicsCollisionObject* object)
     switch (object->getType())
     {
     case PhysicsCollisionObject::RIGID_BODY:
-		_world->addRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
+        _world->addRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
         break;
 
     case PhysicsCollisionObject::CHARACTER:
-		_world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
+        _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
         break;
 
     case PhysicsCollisionObject::GHOST_OBJECT:
-		_world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
+        _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
         break;
 
     default:
@@ -538,199 +538,199 @@ PhysicsCollisionObject* PhysicsController::getCollisionObject(const btCollisionO
 
 void getBoundingBox(Node* node, BoundingBox* out, bool merge = false)
 {
-	if (node->getModel())
-	{
-		if (merge)
-			out->merge(node->getModel()->getMesh()->getBoundingBox());
-		else
-		{
-			out->set(node->getModel()->getMesh()->getBoundingBox());
-			merge = true;
-		}
-	}
-
-	Node* child = node->getFirstChild();
-	while (child)
-	{
-		getBoundingBox(child, out, merge);
-		child = child->getNextSibling();
-	}
+    if (node->getModel())
+    {
+        if (merge)
+            out->merge(node->getModel()->getMesh()->getBoundingBox());
+        else
+        {
+            out->set(node->getModel()->getMesh()->getBoundingBox());
+            merge = true;
+        }
+    }
+
+    Node* child = node->getFirstChild();
+    while (child)
+    {
+        getBoundingBox(child, out, merge);
+        child = child->getNextSibling();
+    }
 }
 
 void getBoundingSphere(Node* node, BoundingSphere* out, bool merge = false)
 {
-	if (node->getModel())
-	{
-		if (merge)
-			out->merge(node->getModel()->getMesh()->getBoundingSphere());
-		else
-		{
-			out->set(node->getModel()->getMesh()->getBoundingSphere());
-			merge = true;
-		}
-	}
-
-	Node* child = node->getFirstChild();
-	while (child)
-	{
-		getBoundingSphere(child, out, merge);
-		child = child->getNextSibling();
-	}
+    if (node->getModel())
+    {
+        if (merge)
+            out->merge(node->getModel()->getMesh()->getBoundingSphere());
+        else
+        {
+            out->set(node->getModel()->getMesh()->getBoundingSphere());
+            merge = true;
+        }
+    }
+
+    Node* child = node->getFirstChild();
+    while (child)
+    {
+        getBoundingSphere(child, out, merge);
+        child = child->getNextSibling();
+    }
 }
 
 void computeCenterOfMass(const Vector3& center, const Vector3& scale, Vector3* centerOfMassOffset)
 {
-	// Update center of mass offset
-	*centerOfMassOffset = center;
-	centerOfMassOffset->x *= scale.x;
-	centerOfMassOffset->y *= scale.y;
-	centerOfMassOffset->z *= scale.z;
-	centerOfMassOffset->negate();
+    // Update center of mass offset
+    *centerOfMassOffset = center;
+    centerOfMassOffset->x *= scale.x;
+    centerOfMassOffset->y *= scale.y;
+    centerOfMassOffset->z *= scale.z;
+    centerOfMassOffset->negate();
 }
 
 PhysicsCollisionShape* PhysicsController::createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset)
 {
-	PhysicsCollisionShape* collisionShape = NULL;
+    PhysicsCollisionShape* collisionShape = NULL;
 
     // Get the node's world scale (we need to apply this during creation since rigid bodies don't scale dynamically).
     Vector3 scale;
     node->getWorldMatrix().getScale(&scale);
 
-	switch (shape.type)
+    switch (shape.type)
     {
-	case PhysicsCollisionShape::SHAPE_BOX:
+    case PhysicsCollisionShape::SHAPE_BOX:
         {
-			if (shape.isExplicit)
-			{
-				// Use the passed in box information
-				collisionShape = createBox(Vector3(shape.data.box.extents), Vector3::one());
-
-				if (shape.centerAbsolute)
-				{
-					computeCenterOfMass(Vector3(shape.data.box.center), Vector3::one(), centerOfMassOffset);
-				}
-				else
-				{
-					BoundingBox box;
-					getBoundingBox(node, &box);
-					computeCenterOfMass(box.getCenter() + Vector3(shape.data.box.center), scale, centerOfMassOffset);
-				}
-			}
-			else
-			{
-				// Automatically compute bounding box from mesh's bounding box
-				BoundingBox box;
-				getBoundingBox(node, &box);
-				collisionShape = createBox(Vector3(std::abs(box.max.x - box.min.x), std::abs(box.max.y - box.min.y), std::abs(box.max.z - box.min.z)), scale);
-
-				computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
-			}
+            if (shape.isExplicit)
+            {
+                // Use the passed in box information
+                collisionShape = createBox(Vector3(shape.data.box.extents), Vector3::one());
+
+                if (shape.centerAbsolute)
+                {
+                    computeCenterOfMass(Vector3(shape.data.box.center), Vector3::one(), centerOfMassOffset);
+                }
+                else
+                {
+                    BoundingBox box;
+                    getBoundingBox(node, &box);
+                    computeCenterOfMass(box.getCenter() + Vector3(shape.data.box.center), scale, centerOfMassOffset);
+                }
+            }
+            else
+            {
+                // Automatically compute bounding box from mesh's bounding box
+                BoundingBox box;
+                getBoundingBox(node, &box);
+                collisionShape = createBox(Vector3(std::abs(box.max.x - box.min.x), std::abs(box.max.y - box.min.y), std::abs(box.max.z - box.min.z)), scale);
+
+                computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
+            }
         }
-		break;
+        break;
 
-	case PhysicsCollisionShape::SHAPE_SPHERE:
+    case PhysicsCollisionShape::SHAPE_SPHERE:
         {
-			if (shape.isExplicit)
-			{
-				// Use the passed in sphere information
-				collisionShape = createSphere(shape.data.sphere.radius, Vector3::one());
-
-				if (shape.centerAbsolute)
-				{
-					computeCenterOfMass(Vector3(shape.data.sphere.center), Vector3::one(), centerOfMassOffset);
-				}
-				else
-				{
-					BoundingSphere sphere;
-					getBoundingSphere(node, &sphere);
-					computeCenterOfMass(sphere.center + Vector3(shape.data.sphere.center), scale, centerOfMassOffset);
-				}
-			}
-			else
-			{
-				// Automatically compute bounding sphere from mesh's bounding sphere
-				BoundingSphere sphere;
-				getBoundingSphere(node, &sphere);
-				collisionShape = createSphere(sphere.radius, scale);
-
-				computeCenterOfMass(sphere.center, scale, centerOfMassOffset);
-			}
+            if (shape.isExplicit)
+            {
+                // Use the passed in sphere information
+                collisionShape = createSphere(shape.data.sphere.radius, Vector3::one());
+
+                if (shape.centerAbsolute)
+                {
+                    computeCenterOfMass(Vector3(shape.data.sphere.center), Vector3::one(), centerOfMassOffset);
+                }
+                else
+                {
+                    BoundingSphere sphere;
+                    getBoundingSphere(node, &sphere);
+                    computeCenterOfMass(sphere.center + Vector3(shape.data.sphere.center), scale, centerOfMassOffset);
+                }
+            }
+            else
+            {
+                // Automatically compute bounding sphere from mesh's bounding sphere
+                BoundingSphere sphere;
+                getBoundingSphere(node, &sphere);
+                collisionShape = createSphere(sphere.radius, scale);
+
+                computeCenterOfMass(sphere.center, scale, centerOfMassOffset);
+            }
         }
-		break;
-
-	case PhysicsCollisionShape::SHAPE_CAPSULE:
-		{
-			if (shape.isExplicit)
-			{
-				// Use the passed in capsule information
-				collisionShape = createCapsule(shape.data.capsule.radius, shape.data.capsule.height, Vector3::one());
-
-				if (shape.centerAbsolute)
-				{
-					computeCenterOfMass(Vector3(shape.data.capsule.center), Vector3::one(), centerOfMassOffset);
-				}
-				else
-				{
-					BoundingBox box;
-					getBoundingBox(node, &box);
-					computeCenterOfMass(box.getCenter() + Vector3(shape.data.capsule.center), scale, centerOfMassOffset);
-				}
-			}
-			else
-			{
-				// Compute a capsule shape that roughly matches the bounding box of the mesh
-				BoundingBox box;
-				getBoundingBox(node, &box);
-				float radius = std::max((box.max.x - box.min.x) * 0.5f, (box.max.z - box.min.z) * 0.5f);
-				float height = box.max.y - box.min.y;
-				collisionShape = createCapsule(radius, height, scale);
-
-				computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
-			}
-		}
-		break;
-
-	case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
-		{
-			// Build heightfield rigid body from the passed in shape
-			collisionShape = createHeightfield(node, shape.data.heightfield, centerOfMassOffset);
-		}
-		break;
-
-	case PhysicsCollisionShape::SHAPE_MESH:
+        break;
+
+    case PhysicsCollisionShape::SHAPE_CAPSULE:
         {
-			// Build mesh from passed in shape
-			collisionShape = createMesh(shape.data.mesh, scale);
+            if (shape.isExplicit)
+            {
+                // Use the passed in capsule information
+                collisionShape = createCapsule(shape.data.capsule.radius, shape.data.capsule.height, Vector3::one());
+
+                if (shape.centerAbsolute)
+                {
+                    computeCenterOfMass(Vector3(shape.data.capsule.center), Vector3::one(), centerOfMassOffset);
+                }
+                else
+                {
+                    BoundingBox box;
+                    getBoundingBox(node, &box);
+                    computeCenterOfMass(box.getCenter() + Vector3(shape.data.capsule.center), scale, centerOfMassOffset);
+                }
+            }
+            else
+            {
+                // Compute a capsule shape that roughly matches the bounding box of the mesh
+                BoundingBox box;
+                getBoundingBox(node, &box);
+                float radius = std::max((box.max.x - box.min.x) * 0.5f, (box.max.z - box.min.z) * 0.5f);
+                float height = box.max.y - box.min.y;
+                collisionShape = createCapsule(radius, height, scale);
+
+                computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
+            }
         }
-		break;
+        break;
+
+    case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
+        {
+            // Build heightfield rigid body from the passed in shape
+            collisionShape = createHeightfield(node, shape.data.heightfield, centerOfMassOffset);
+        }
+        break;
+
+    case PhysicsCollisionShape::SHAPE_MESH:
+        {
+            // Build mesh from passed in shape
+            collisionShape = createMesh(shape.data.mesh, scale);
+        }
+        break;
     }
 
-	return collisionShape;
+    return collisionShape;
 }
 
 PhysicsCollisionShape* PhysicsController::createBox(const Vector3& extents, const Vector3& scale)
 {
     btVector3 halfExtents(scale.x * 0.5 * extents.x, scale.y * 0.5 * extents.y, scale.z * 0.5 * extents.z);
 
-	PhysicsCollisionShape* shape;
+    PhysicsCollisionShape* shape;
 
     // Return the box shape from the cache if it already exists.
     for (unsigned int i = 0; i < _shapes.size(); ++i)
     {
-		shape = _shapes[i];
-		if (shape->getType() == PhysicsCollisionShape::SHAPE_BOX)
+        shape = _shapes[i];
+        if (shape->getType() == PhysicsCollisionShape::SHAPE_BOX)
         {
-			btBoxShape* box = static_cast<btBoxShape*>(shape->_shape);
+            btBoxShape* box = static_cast<btBoxShape*>(shape->_shape);
             if (box->getHalfExtentsWithMargin() == halfExtents)
             {
-				shape->addRef();
+                shape->addRef();
                 return shape;
             }
         }
     }
 
     // Create the box shape and add it to the cache.
-	shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_BOX, bullet_new<btBoxShape>(halfExtents));
+    shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_BOX, bullet_new<btBoxShape>(halfExtents));
     _shapes.push_back(shape);
 
     return shape;
@@ -746,15 +746,15 @@ PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vecto
     if (uniformScale < scale.z)
         uniformScale = scale.z;
 
-	float scaledRadius = radius * uniformScale;
+    float scaledRadius = radius * uniformScale;
 
-	PhysicsCollisionShape* shape;
+    PhysicsCollisionShape* shape;
 
     // Return the sphere shape from the cache if it already exists.
     for (unsigned int i = 0; i < _shapes.size(); ++i)
     {
-		shape = _shapes[i];
-		if (shape->getType() == PhysicsCollisionShape::SHAPE_SPHERE)
+        shape = _shapes[i];
+        if (shape->getType() == PhysicsCollisionShape::SHAPE_SPHERE)
         {
             btSphereShape* sphere = static_cast<btSphereShape*>(shape->_shape);
             if (sphere->getRadius() == scaledRadius)
@@ -766,7 +766,7 @@ PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vecto
     }
 
     // Create the sphere shape and add it to the cache.
-	shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_SPHERE, bullet_new<btSphereShape>(scaledRadius));
+    shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_SPHERE, bullet_new<btSphereShape>(scaledRadius));
     _shapes.push_back(shape);
 
     return shape;
@@ -774,19 +774,19 @@ PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vecto
 
 PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float height, const Vector3& scale)
 {
-	float girthScale = scale.x;
-	if (girthScale < scale.z)
-		girthScale = scale.z;
-	float scaledRadius = radius * girthScale;
-	float scaledHeight = height * scale.y - radius * 2;
+    float girthScale = scale.x;
+    if (girthScale < scale.z)
+        girthScale = scale.z;
+    float scaledRadius = radius * girthScale;
+    float scaledHeight = height * scale.y - radius * 2;
 
-	PhysicsCollisionShape* shape;
+    PhysicsCollisionShape* shape;
 
     // Return the capsule shape from the cache if it already exists.
     for (unsigned int i = 0; i < _shapes.size(); i++)
     {
-		shape = _shapes[i];
-		if (shape->getType() == PhysicsCollisionShape::SHAPE_CAPSULE)
+        shape = _shapes[i];
+        if (shape->getType() == PhysicsCollisionShape::SHAPE_CAPSULE)
         {
             btCapsuleShape* capsule = static_cast<btCapsuleShape*>(shape->_shape);
             if (capsule->getRadius() == scaledRadius && capsule->getHalfHeight() == 0.5f * scaledHeight)
@@ -798,7 +798,7 @@ PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float heig
     }
 
     // Create the capsule shape and add it to the cache.
-	shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_CAPSULE, bullet_new<btCapsuleShape>(scaledRadius, scaledHeight));
+    shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_CAPSULE, bullet_new<btCapsuleShape>(scaledRadius, scaledHeight));
     _shapes.push_back(shape);
 
     return shape;
@@ -806,25 +806,25 @@ PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float heig
 
 PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* image, Vector3* centerOfMassOffset)
 {
-	// Get the dimensions of the heightfield.
-	// If the node has a mesh defined, use the dimensions of the bounding box for the mesh.
-	// Otherwise simply use the image dimensions (with a max height of 255).
-	float width, length, minHeight, maxHeight;
-	if (node->getModel() && node->getModel()->getMesh())
-	{
-		const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
-		width = box.max.x - box.min.x;
-		length = box.max.z - box.min.z;
-		minHeight = box.min.y;
-		maxHeight = box.max.y;
-	}
-	else
-	{
-		width = image->getWidth();
-		length = image->getHeight();
-		minHeight = 0.0f;
-		maxHeight = 255.0f;
-	}
+    // Get the dimensions of the heightfield.
+    // If the node has a mesh defined, use the dimensions of the bounding box for the mesh.
+    // Otherwise simply use the image dimensions (with a max height of 255).
+    float width, length, minHeight, maxHeight;
+    if (node->getModel() && node->getModel()->getMesh())
+    {
+        const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
+        width = box.max.x - box.min.x;
+        length = box.max.z - box.min.z;
+        minHeight = box.min.y;
+        maxHeight = box.max.y;
+    }
+    else
+    {
+        width = image->getWidth();
+        length = image->getHeight();
+        minHeight = 0.0f;
+        maxHeight = 255.0f;
+    }
 
     // Get the size in bytes of a pixel (we ensure that the image's
     // pixel format is actually supported before calling this constructor).
@@ -837,14 +837,14 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
         case Image::RGBA:
             pixelSize = 4;
             break;
-		default:
-			LOG_ERROR("Unsupported pixel format for heightmap image.");
-			return NULL;
+        default:
+            LOG_ERROR("Unsupported pixel format for heightmap image.");
+            return NULL;
     }
 
     // Calculate the heights for each pixel.
     float* heights = new float[image->getWidth() * image->getHeight()];
-	unsigned char* data = image->getData();
+    unsigned char* data = image->getData();
     for (unsigned int x = 0, w = image->getWidth(); x < w; ++x)
     {
         for (unsigned int y = 0, h = image->getHeight(); y < h; ++y)
@@ -855,16 +855,16 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
         }
     }
 
-	PhysicsCollisionShape::HeightfieldData* heightfieldData = new PhysicsCollisionShape::HeightfieldData();
-	heightfieldData->heightData = NULL;
-	heightfieldData->inverseIsDirty = true;
+    PhysicsCollisionShape::HeightfieldData* heightfieldData = new PhysicsCollisionShape::HeightfieldData();
+    heightfieldData->heightData = NULL;
+    heightfieldData->inverseIsDirty = true;
 
     // Generate the heightmap data needed for physics (one height per world unit).
     unsigned int sizeWidth = width;
     unsigned int sizeHeight = length;
-	heightfieldData->width = sizeWidth + 1;
+    heightfieldData->width = sizeWidth + 1;
     heightfieldData->height = sizeHeight + 1;
-	heightfieldData->heightData = new float[heightfieldData->width * heightfieldData->height];
+    heightfieldData->heightData = new float[heightfieldData->width * heightfieldData->height];
     unsigned int heightIndex = 0;
     float widthImageFactor = (float)(image->getWidth() - 1) / sizeWidth;
     float heightImageFactor = (float)(image->getHeight() - 1) / sizeHeight;
@@ -874,8 +874,8 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
     {
         for (unsigned int col = 0, x = 0.0f; col <= sizeWidth; col++, x += 1.0f)
         {
-			heightIndex = row * heightfieldData->width + col;
-			heightfieldData->heightData[heightIndex] = calculateHeight(heights, image->getWidth(), image->getHeight(), x * widthImageFactor, (sizeHeight - z) * heightImageFactor);
+            heightIndex = row * heightfieldData->width + col;
+            heightfieldData->heightData[heightIndex] = calculateHeight(heights, image->getWidth(), image->getHeight(), x * widthImageFactor, (sizeHeight - z) * heightImageFactor);
         }
     }
     SAFE_DELETE_ARRAY(heights);
@@ -884,15 +884,15 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
     // of its heightfield collision shape; see documentation for the btHeightfieldTerrainShape for more info.
     Vector3 s;
     node->getWorldMatrix().getScale(&s);
-	centerOfMassOffset->set(0.0f, -(maxHeight - (0.5f * (maxHeight - minHeight))) / s.y, 0.0f);
+    centerOfMassOffset->set(0.0f, -(maxHeight - (0.5f * (maxHeight - minHeight))) / s.y, 0.0f);
 
-	// Create the bullet terrain shape
-	btHeightfieldTerrainShape* terrainShape = bullet_new<btHeightfieldTerrainShape>(
-		heightfieldData->width, heightfieldData->height, heightfieldData->heightData, 1.0f, minHeight, maxHeight, 1, PHY_FLOAT, false);
+    // Create the bullet terrain shape
+    btHeightfieldTerrainShape* terrainShape = bullet_new<btHeightfieldTerrainShape>(
+        heightfieldData->width, heightfieldData->height, heightfieldData->heightData, 1.0f, minHeight, maxHeight, 1, PHY_FLOAT, false);
 
-	// Create our collision shape object and store heightfieldData in it
-	PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_HEIGHTFIELD, terrainShape);
-	shape->_shapeData.heightfieldData = heightfieldData;
+    // Create our collision shape object and store heightfieldData in it
+    PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_HEIGHTFIELD, terrainShape);
+    shape->_shapeData.heightfieldData = heightfieldData;
 
     _shapes.push_back(shape);
 
@@ -903,29 +903,29 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
 {
     assert(mesh);
 
-	// Only support meshes with triangle list primitive types
-	bool triMesh = true;
-	if (mesh->getPartCount() > 0)
-	{
-		for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
-		{
-			if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
-			{
-				triMesh = false;
-				break;
-			}
-		}
-	}
-	else
-	{
-		triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
-	}
-
-	if (!triMesh)
-	{
-		LOG_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
-		return NULL;
-	}
+    // Only support meshes with triangle list primitive types
+    bool triMesh = true;
+    if (mesh->getPartCount() > 0)
+    {
+        for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
+        {
+            if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
+            {
+                triMesh = false;
+                break;
+            }
+        }
+    }
+    else
+    {
+        triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
+    }
+
+    if (!triMesh)
+    {
+        LOG_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
+        return NULL;
+    }
 
     // The mesh must have a valid URL (i.e. it must have been loaded from a Package)
     // in order to fetch mesh data for computing mesh rigid body.
@@ -941,15 +941,15 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         return NULL;
     }
 
-	// Create mesh data to be populated and store in returned collision shape
-	PhysicsCollisionShape::MeshData* shapeMeshData = new PhysicsCollisionShape::MeshData();
-	shapeMeshData->vertexData = NULL;
+    // Create mesh data to be populated and store in returned collision shape
+    PhysicsCollisionShape::MeshData* shapeMeshData = new PhysicsCollisionShape::MeshData();
+    shapeMeshData->vertexData = NULL;
 
     // Copy the scaled vertex position data to the rigid body's local buffer.
     Matrix m;
     Matrix::createScale(scale, &m);
     unsigned int vertexCount = data->vertexCount;
-	shapeMeshData->vertexData = new float[vertexCount * 3];
+    shapeMeshData->vertexData = new float[vertexCount * 3];
     Vector3 v;
     int vertexStride = data->vertexFormat.getVertexSize();
     for (unsigned int i = 0; i < data->vertexCount; i++)
@@ -958,7 +958,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
               *((float*)&data->vertexData[i * vertexStride + 1 * sizeof(float)]),
               *((float*)&data->vertexData[i * vertexStride + 2 * sizeof(float)]));
         v *= m;
-		memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
+        memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
     }
 
     btTriangleIndexVertexArray* meshInterface = bullet_new<btTriangleIndexVertexArray>();
@@ -991,7 +991,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
 
             // Move the index data into the rigid body's local buffer.
             // Set it to NULL in the MeshPartData so it is not released when the data is freed.
-			shapeMeshData->indexData.push_back(meshPart->indexData);
+            shapeMeshData->indexData.push_back(meshPart->indexData);
             meshPart->indexData = NULL;
 
             // Create a btIndexedMesh object for the current mesh part.
@@ -999,9 +999,9 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
             indexedMesh.m_indexType = indexType;
             indexedMesh.m_numTriangles = meshPart->indexCount / 3; // assume TRIANGLES primitive type
             indexedMesh.m_numVertices = meshPart->indexCount;
-			indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
+            indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
             indexedMesh.m_triangleIndexStride = indexStride*3;
-			indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
+            indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
             indexedMesh.m_vertexStride = sizeof(float)*3;
             indexedMesh.m_vertexType = PHY_FLOAT;
 
@@ -1034,9 +1034,9 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         meshInterface->addIndexedMesh(indexedMesh, indexedMesh.m_indexType);
     }
 
-	// Create our collision shape object and store shapeMeshData in it
-	PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, bullet_new<btBvhTriangleMeshShape>(meshInterface, true));
-	shape->_shapeData.meshData = shapeMeshData;
+    // Create our collision shape object and store shapeMeshData in it
+    PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, bullet_new<btBvhTriangleMeshShape>(meshInterface, true));
+    shape->_shapeData.meshData = shapeMeshData;
 
     _shapes.push_back(shape);
 
@@ -1052,14 +1052,14 @@ void PhysicsController::destroyShape(PhysicsCollisionShape* shape)
     {
         if (shape->getRefCount() == 1)
         {
-			// Remove shape from shape cache
+            // Remove shape from shape cache
             std::vector<PhysicsCollisionShape*>::iterator shapeItr = std::find(_shapes.begin(), _shapes.end(), shape);
             if (shapeItr != _shapes.end())
                 _shapes.erase(shapeItr);
         }
 
-		// Release the shape
-		shape->release();
+        // Release the shape
+        shape->release();
     }
 }
 
@@ -1247,7 +1247,7 @@ void PhysicsController::DebugDrawer::setDebugMode(int mode)
     _mode = mode;
 }
 
-int	PhysicsController::DebugDrawer::getDebugMode() const
+int PhysicsController::DebugDrawer::getDebugMode() const
 {
     return _mode;
 }

+ 11 - 11
gameplay/src/PhysicsController.h

@@ -265,7 +265,7 @@ private:
         int _status;
     };
 
-	/**
+    /**
      * Constructor.
      */
     PhysicsController();
@@ -315,30 +315,30 @@ private:
     // Gets the corresponding GamePlay object for the given Bullet object.
     PhysicsCollisionObject* getCollisionObject(const btCollisionObject* collisionObject) const;
 
-	// Creates a collision shape for the given node and gameplay shape definition.
-	// Populates 'centerOfMassOffset' with the correct calculated center of mass offset.
-	PhysicsCollisionShape* createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset);
+    // Creates a collision shape for the given node and gameplay shape definition.
+    // Populates 'centerOfMassOffset' with the correct calculated center of mass offset.
+    PhysicsCollisionShape* createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset);
     
     // Creates a box collision shape.
     PhysicsCollisionShape* createBox(const Vector3& extents, const Vector3& scale);
 
-	// Creates a sphere collision shape.
+    // Creates a sphere collision shape.
     PhysicsCollisionShape* createSphere(float radius, const Vector3& scale);
 
     // Creates a capsule collision shape.
     PhysicsCollisionShape* createCapsule(float radius, float height, const Vector3& scale);
 
-	// Creates a heightfield collision shape.
+    // Creates a heightfield collision shape.
     PhysicsCollisionShape* createHeightfield(Node* node, Image* image, Vector3* centerOfMassOffset);
 
     // Creates a triangle mesh collision shape.
     PhysicsCollisionShape* createMesh(Mesh* mesh, const Vector3& scale);
 
-	// Destroys a collision shape created through PhysicsController
-	void destroyShape(PhysicsCollisionShape* shape);
+    // Destroys a collision shape created through PhysicsController
+    void destroyShape(PhysicsCollisionShape* shape);
 
-	// Helper function for calculating heights from heightmap (image) or heightfield data.
-	static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y);
+    // Helper function for calculating heights from heightmap (image) or heightfield data.
+    static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y);
 
     // Sets up the given constraint for the given two rigid bodies.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
@@ -373,7 +373,7 @@ private:
         void reportErrorWarning(const char* warningString);
         void draw3dText(const btVector3& location, const char* textString);        
         void setDebugMode(int mode);        
-        int	getDebugMode() const;
+        int    getDebugMode() const;
         
     private:
         

+ 1 - 1
gameplay/src/PhysicsGhostObject.cpp

@@ -17,7 +17,7 @@ PhysicsGhostObject::PhysicsGhostObject(Node* node, const PhysicsCollisionShape::
 
     // Create the ghost object.
     _ghostObject = bullet_new<btPairCachingGhostObject>();
-	_ghostObject->setCollisionShape(_collisionShape->getShape());
+    _ghostObject->setCollisionShape(_collisionShape->getShape());
     _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
 
     // Initialize a physics motion state object for syncing the transform.

+ 1 - 1
gameplay/src/PhysicsMotionState.cpp

@@ -23,7 +23,7 @@ PhysicsMotionState::~PhysicsMotionState()
 
 void PhysicsMotionState::getWorldTransform(btTransform &transform) const
 {
-	if (_node->getCollisionObject() && _node->getCollisionObject()->isKinematic())
+    if (_node->getCollisionObject() && _node->getCollisionObject()->isKinematic())
         updateTransformFromNode();
 
     transform = _centerOfMassOffset.inverse() * _worldTransform;

+ 4 - 4
gameplay/src/PhysicsMotionState.h

@@ -15,10 +15,10 @@ class Node;
  */
 class PhysicsMotionState : public btMotionState
 {
-	friend class PhysicsCollisionObject;
-	friend class PhysicsRigidBody;
-	friend class PhysicsGhostObject;
-	friend class PhysicsCharacter;
+    friend class PhysicsCollisionObject;
+    friend class PhysicsRigidBody;
+    friend class PhysicsGhostObject;
+    friend class PhysicsCharacter;
     friend class PhysicsConstraint;
 
 protected:

+ 2 - 2
gameplay/src/PhysicsRigidBody.cpp

@@ -24,8 +24,8 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Defi
     // inertia. However, if the collision shape is a triangle mesh, we don't calculate 
     // inertia since Bullet doesn't currently support this.
     btVector3 localInertia(0.0, 0.0, 0.0);
-	if (parameters.mass != 0.0 && _collisionShape->getType() != PhysicsCollisionShape::SHAPE_MESH)
-		_collisionShape->getShape()->calculateLocalInertia(parameters.mass, localInertia);
+    if (parameters.mass != 0.0 && _collisionShape->getType() != PhysicsCollisionShape::SHAPE_MESH)
+        _collisionShape->getShape()->calculateLocalInertia(parameters.mass, localInertia);
 
     // Create the Bullet physics rigid body object.
     btRigidBody::btRigidBodyConstructionInfo rbInfo(parameters.mass, _motionState, _collisionShape->getShape(), localInertia);

+ 83 - 83
gameplay/src/PhysicsRigidBody.h

@@ -30,75 +30,75 @@ class PhysicsRigidBody : public PhysicsCollisionObject, public Transform::Listen
 
 public:
 
-	/**
-	 * Rigid body construction parameters.
-	 */
-	struct Parameters
-	{
-		/**
-		 * The mass of the rigid body, in kilograms.
-		 */
-		float mass;
-
-		/**
-		 * The friction of the rigid body (non-zero values give best simulation results).
-		 */
-		float friction;
-
-		/**
-		 * The restitution of the rigid body (this controls the bounciness of
-		 * the rigid body; use zero for best simulation results).
-		 */
+    /**
+     * Rigid body construction parameters.
+     */
+    struct Parameters
+    {
+        /**
+         * The mass of the rigid body, in kilograms.
+         */
+        float mass;
+
+        /**
+         * The friction of the rigid body (non-zero values give best simulation results).
+         */
+        float friction;
+
+        /**
+         * The restitution of the rigid body (this controls the bounciness of
+         * the rigid body; use zero for best simulation results).
+         */
         float restitution;
 
-		/**
-		 * The percentage of linear velocity lost per second (between 0.0 and 1.0).
-		 */
-		float linearDamping;
-
-		/**
-		 * The percentage of angular velocity lost per second (between 0.0 and 1.0).
-		 */
-		float angularDamping;
-
-		/**
-		 * Whether the rigid body is kinematic.
-		 */
-		bool kinematic;
-
-		/**
-		 * The ansitropic friction term for the rigid body.
-		 */
-		Vector3 anisotropicFriction;
-
-		/**
-		 * The gravity acceleration factor for the rigid body.
-		 */
-		Vector3 gravity;
-
-		/**
-		 * Constructor.
-		 */
-		Parameters(float mass = 0.0f, float friction = 0.5f, float resititution = 0.0f,
-			float linearDamping = 0.0f, float angularDamping = 0.0f, bool kinematic = false,
-			const Vector3& anisotropicFriction = Vector3::one(), const Vector3& gravity = Vector3::zero())
-			: mass(mass), friction(friction), restitution(restitution), linearDamping(linearDamping), angularDamping(angularDamping),
-			  kinematic(kinematic), anisotropicFriction(anisotropicFriction), gravity(gravity)
-		{
-		}
-	};
+        /**
+         * The percentage of linear velocity lost per second (between 0.0 and 1.0).
+         */
+        float linearDamping;
+
+        /**
+         * The percentage of angular velocity lost per second (between 0.0 and 1.0).
+         */
+        float angularDamping;
+
+        /**
+         * Whether the rigid body is kinematic.
+         */
+        bool kinematic;
+
+        /**
+         * The ansitropic friction term for the rigid body.
+         */
+        Vector3 anisotropicFriction;
+
+        /**
+         * The gravity acceleration factor for the rigid body.
+         */
+        Vector3 gravity;
+
+        /**
+         * Constructor.
+         */
+        Parameters(float mass = 0.0f, float friction = 0.5f, float resititution = 0.0f,
+            float linearDamping = 0.0f, float angularDamping = 0.0f, bool kinematic = false,
+            const Vector3& anisotropicFriction = Vector3::one(), const Vector3& gravity = Vector3::zero())
+            : mass(mass), friction(friction), restitution(restitution), linearDamping(linearDamping), angularDamping(angularDamping),
+              kinematic(kinematic), anisotropicFriction(anisotropicFriction), gravity(gravity)
+        {
+        }
+    };
 
     /**
      * @see PhysicsCollisionObject#getType
      */
     PhysicsCollisionObject::Type getType() const;
 
-	/**
-	 * Gets the rigid body's mass.
-	 *
-	 * @return The mass.
-	 */
-	inline float getMass() const;
+    /**
+     * Gets the rigid body's mass.
+     *
+     * @return The mass.
+     */
+    inline float getMass() const;
 
     /**
      * Gets the rigid body's friction.
@@ -114,12 +114,12 @@ public:
      */
     inline void setFriction(float friction);
 
-	/**
-	 * Gets the rigid body's restitution.
-	 *
-	 * @return The restitution.
-	 */
-	inline float getRestitution() const;
+    /**
+     * Gets the rigid body's restitution.
+     *
+     * @return The restitution.
+     */
+    inline float getRestitution() const;
 
     /**
      * Sets the rigid body's restitution (or bounciness).
@@ -128,19 +128,19 @@ public:
      */
     inline void setRestitution(float restitution);
 
-	/**
-	 * Gets the rigid body's linear damping.
-	 *
-	 * @return The linear damping.
-	 */
-	inline float getLinearDamping() const;
+    /**
+     * Gets the rigid body's linear damping.
+     *
+     * @return The linear damping.
+     */
+    inline float getLinearDamping() const;
 
-	/**
-	 * Gets the rigid body's angular damping.
-	 *
-	 * @return The angular damping.
-	 */
-	inline float getAngularDamping() const;
+    /**
+     * Gets the rigid body's angular damping.
+     *
+     * @return The angular damping.
+     */
+    inline float getAngularDamping() const;
 
     /**
      * Sets the rigid body's linear and angular damping.
@@ -150,7 +150,7 @@ public:
      */
     inline void setDamping(float linearDamping, float angularDamping);
 
-	/**
+    /**
      * Gets the rigid body's linear velocity.
      * 
      * @return The linear velocity.
@@ -277,7 +277,7 @@ private:
      * @param shape The rigid body shape construction information.
      * @param parameters The rigid body construction parameters.
      */
-	PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Definition& shape, const Parameters& parameters);
+    PhysicsRigidBody(Node* node, const PhysicsCollisionShape::Definition& shape, const Parameters& parameters);
 
     /**
      * Destructor.
@@ -312,8 +312,8 @@ private:
     void transformChanged(Transform* transform, long cookie);
 
     btRigidBody* _body;
-	float _mass;
-	std::vector<PhysicsConstraint*>* _constraints;
+    float _mass;
+    std::vector<PhysicsConstraint*>* _constraints;
 
 };
 

+ 2 - 2
gameplay/src/PhysicsRigidBody.inl

@@ -6,7 +6,7 @@ namespace gameplay
 
 inline float PhysicsRigidBody::getMass() const
 {
-	return _mass;
+    return _mass;
 }
 
 inline float PhysicsRigidBody::getFriction() const
@@ -47,7 +47,7 @@ inline void PhysicsRigidBody::setDamping(float linearDamping, float angularDampi
 inline Vector3 PhysicsRigidBody::getLinearVelocity() const
 {
     const btVector3& v = _body->getLinearVelocity();
-	return Vector3(v.x(), v.y(), v.z());
+    return Vector3(v.x(), v.y(), v.z());
 }
 
 inline void PhysicsRigidBody::setLinearVelocity(const Vector3& velocity)

+ 101 - 102
gameplay/src/PlatformMacOS.mm

@@ -4,7 +4,7 @@
 #include "Platform.h"
 #include "FileSystem.h"
 #include "Game.h"
-
+#include "Form.h"
 #include <unistd.h>
 
 #import <Cocoa/Cocoa.h>
@@ -15,10 +15,10 @@
 using namespace std;
 using namespace gameplay;
 
-// Default to 720p
-#define WINDOW_WIDTH    1280
-#define WINDOW_HEIGHT   720
-
+// Default to 720p
+#define WINDOW_WIDTH    1280
+#define WINDOW_HEIGHT   720
+
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
@@ -32,7 +32,7 @@ static int __ly;
 static bool __hasMouse = false;
 static bool __leftMouseDown = false;
 static bool __rightMouseDown = false;
-static bool __otherMouseDown = false;
+static bool __otherMouseDown = false;
 static bool __shiftDown = false;
 
 long getMachTimeInMilliseconds()
@@ -67,7 +67,7 @@ static View* __view = NULL;
 -(void)windowWillClose:(NSNotification*)note 
 {
     [lock lock];
-    _game->exit();
+    _game->end();
     [lock unlock];
     [[NSApplication sharedApplication] terminate:self];
 }
@@ -88,10 +88,9 @@ static View* __view = NULL;
     [lock lock];
 
     [[self openGLContext] makeCurrentContext];
-    
     CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);
     
-    if (_game && _game->getState() == Game::RUNNING)       
+    if (_game && _game->getState() == Game::RUNNING)  
         _game->frame();
     
     CGLFlushDrawable((CGLContextObj)[[self openGLContext] CGLContextObj]);
@@ -109,7 +108,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 - (id) initWithFrame: (NSRect) frame
 {    
-
+
     NSOpenGLPixelFormatAttribute attrs[] = 
     {
         NSOpenGLPFAAccelerated,
@@ -125,12 +124,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     if (!pf)
         NSLog(@"OpenGL pixel format not supported.");
     
-    if((self = [super initWithFrame:frame pixelFormat:[pf autorelease]])) 
-    {
-        lock = [[NSRecursiveLock alloc] init];
-        _game = Game::getInstance();
-        __timeStart = getMachTimeInMilliseconds();
-    }
+    if((self = [super initWithFrame:frame pixelFormat:[pf autorelease]])) 
+    {
+        lock = [[NSRecursiveLock alloc] init];
+        _game = Game::getInstance();
+        __timeStart = getMachTimeInMilliseconds();
+    }
     
     return self;
 }
@@ -176,23 +175,23 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     CVDisplayLinkStop(displayLink);
     CVDisplayLinkRelease(displayLink);
     
-    _game->exit();
+    _game->end();
     
     [lock unlock];
 
     [super dealloc];
 }
 
-
-- (void) mouse: (Mouse::MouseEvent) mouseEvent orTouchEvent: (Touch::TouchEvent) touchEvent atX: (int) x y: (int) y s: (int) s 
-{
-    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y, s))
-    {
-        Game::getInstance()->touchEvent(touchEvent, x, y, 0);
-    }
-        
-}
-
+
+- (void) mouse: (Mouse::MouseEvent) mouseEvent orTouchEvent: (Touch::TouchEvent) touchEvent atX: (int) x y: (int) y s: (int) s 
+{
+    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y, s))
+    {
+        Game::getInstance()->touchEvent(touchEvent, x, y, 0);
+    }
+        
+}
+
 - (void) mouseDown: (NSEvent*) event
 {
     NSPoint point = [event locationInWindow];
@@ -220,12 +219,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     [self mouse: Mouse::MOUSE_RELEASE_LEFT_BUTTON orTouchEvent: Touch::TOUCH_RELEASE atX: point.x y: WINDOW_HEIGHT - point.y s: 0];
 }
 
-- (void)mouseMoved:(NSEvent *) event 
-{
-    NSPoint point = [event locationInWindow];
-    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
+- (void)mouseMoved:(NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
 - (void) mouseDragged: (NSEvent*) event
 {
     NSPoint point = [event locationInWindow];
@@ -240,15 +239,15 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __rightMouseDown = true;
      NSPoint point = [event locationInWindow];
     __lx = point.x;
-    __ly = WINDOW_HEIGHT - point.y;    
-    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    __ly = WINDOW_HEIGHT - point.y;    
+    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) rightMouseUp: (NSEvent*) event
 {
    __rightMouseDown = false;
-    NSPoint point = [event locationInWindow];
-    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) rightMouseDragged: (NSEvent*) event
@@ -268,48 +267,48 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
         __lx = point.x;
         __ly = (WINDOW_HEIGHT - point.y);
     }
-    
-    // In right-mouse case, whether __rightMouseDown is true or false
-    // this should not matter, mouse move is still occuring
-    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
-- (void)otherMouseDown: (NSEvent *) event 
-{
-    __otherMouseDown = true;
-    NSPoint point = [event locationInWindow];
-    _game->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
-- (void)otherMouseUp: (NSEvent *) event 
-{
-    __otherMouseDown = false;
-    NSPoint point = [event locationInWindow];
-    _game->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
-- (void)otherMouseDragged: (NSEvent *) event 
-{
-    NSPoint point = [event locationInWindow];
-    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
-}
-
+    
+    // In right-mouse case, whether __rightMouseDown is true or false
+    // this should not matter, mouse move is still occuring
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseDown: (NSEvent *) event 
+{
+    __otherMouseDown = true;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseUp: (NSEvent *) event 
+{
+    __otherMouseDown = false;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseDragged: (NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
 - (void) mouseEntered: (NSEvent*)event
 {
     __hasMouse = true;
 }
 
-- (void)scrollWheel: (NSEvent *) event 
-{
-    NSPoint point = [event locationInWindow];
-    Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, point.x, WINDOW_HEIGHT - point.y, (int)([event deltaY] * 10.0f));
-}
-
+- (void)scrollWheel: (NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, point.x, WINDOW_HEIGHT - point.y, (int)([event deltaY] * 10.0f));
+}
+
 - (void) mouseExited: (NSEvent*)event
 {
     __leftMouseDown = false;
     __rightMouseDown = false;
-    __otherMouseDown = false;
+    __otherMouseDown = false;
     __hasMouse = false;
 }
 
@@ -525,28 +524,28 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
             _game->keyEvent((flags & NSAlphaShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CAPS_LOCK);
             break;
         case 0x38:
-            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
+            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
             break;
         case 0x3C:
-            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
+            _game->keyEvent((flags & NSShiftKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_SHIFT);
             break;
         case 0x3A:
-            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
+            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
             break;
         case 0x3D:
-            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
+            _game->keyEvent((flags & NSAlternateKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_ALT);
             break;
         case 0x3B:
-            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
+            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
             break;
         case 0x3E:
-            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
+            _game->keyEvent((flags & NSControlKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_CTRL);
             break;
         case 0x37:
-            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
+            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
             break;
         case 0x36:
-            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
+            _game->keyEvent((flags & NSCommandKeyMask) ? Keyboard::KEY_PRESS : Keyboard::KEY_RELEASE, Keyboard::KEY_HYPER);
             break;
     }
 }
@@ -600,7 +599,7 @@ Platform* Platform::create(Game* game)
 int Platform::enterMessagePump()
 {
     NSAutoreleasePool* pool = [NSAutoreleasePool new];
-    NSApplication* app = [NSApplication sharedApplication];
+    NSApplication* app = [NSApplication sharedApplication];
     NSRect screenBounds = [[NSScreen mainScreen] frame];
     NSRect viewBounds = NSMakeRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
     
@@ -617,27 +616,27 @@ int Platform::enterMessagePump()
                         backing:NSBackingStoreBuffered
                         defer:NO];
     
-    [window setAcceptsMouseMovedEvents:YES];
+    [window setAcceptsMouseMovedEvents:YES];
     [window setContentView:__view];
     [window setDelegate:__view];
     [__view release];
     
-    [app run];
+    [app run];
     
     [pool release];
     return EXIT_SUCCESS;
 }
-
-unsigned int Platform::getDisplayWidth()
-{
-    return WINDOW_WIDTH;
-}
-
-unsigned int Platform::getDisplayHeight()
-{
-    return WINDOW_HEIGHT;
-}
-
+
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+
 long Platform::getAbsoluteTime()
 {
     __timeAbsolute = getMachTimeInMilliseconds();
@@ -680,18 +679,18 @@ void Platform::displayKeyboard(bool display)
 {
     // Do nothing.
 }
-
-void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    if (!Form::touchEventInternal(evt, x, y, contactIndex))
-    {
-        Game::getInstance()->touchEvent(evt, x, y, contactIndex);
-    }
+
+void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    if (!Form::touchEventInternal(evt, x, y, contactIndex))
+    {
+        Game::getInstance()->touchEvent(evt, x, y, contactIndex);
+    }
 }
 
-void Platform::sleep(long ms)
-{
-    usleep(ms * 1000);
+void Platform::sleep(long ms)
+{
+    usleep(ms * 1000);
 }
 
 }

+ 59 - 59
gameplay/src/PlatformQNX.cpp

@@ -573,70 +573,70 @@ Platform* Platform::create(Game* game)
         goto error;
     }
 
-	screen_display_t screen_display;
+    screen_display_t screen_display;
     rc = screen_get_window_property_pv(__screenWindow, SCREEN_PROPERTY_DISPLAY, (void **)&screen_display);
     if (rc)
     {
-    	perror("screen_get_window_property_pv(SCREEN_PROPERTY_DISPLAY)");
-    	goto error;
+        perror("screen_get_window_property_pv(SCREEN_PROPERTY_DISPLAY)");
+        goto error;
     }
 
-	screen_display_mode_t screen_mode;
-	rc = screen_get_display_property_pv(screen_display, SCREEN_PROPERTY_MODE, (void**)&screen_mode);
-	if (rc)
-	{
-		perror("screen_get_display_property_pv(SCREEN_PROPERTY_MODE)");
-		goto error;
-	}
+    screen_display_mode_t screen_mode;
+    rc = screen_get_display_property_pv(screen_display, SCREEN_PROPERTY_MODE, (void**)&screen_mode);
+    if (rc)
+    {
+        perror("screen_get_display_property_pv(SCREEN_PROPERTY_MODE)");
+        goto error;
+    }
 
     int size[2];
-	rc = screen_get_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, size);
-	if (rc)
-	{
-		perror("screen_get_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
-		goto error;
-	}
-
-	__screenWindowSize[0] = size[0];
-	__screenWindowSize[1] = size[1];
-
-	if ((angle == 0) || (angle == 180))
-	{
-		if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) ||
-			((screen_mode.width < screen_mode.height) && (size[0] > size[1])))
-		{
-			__screenWindowSize[1] = size[0];
-			__screenWindowSize[0] = size[1];
-		}
-	}
-	else if ((angle == 90) || (angle == 270))
-	{
-		if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) ||
-			((screen_mode.width < screen_mode.height) && (size[0] < size[1])))
-		{
-			__screenWindowSize[1] = size[0];
-			__screenWindowSize[0] = size[1];
-		}
-	}
-	else
-	{
-		perror("Navigator returned an unexpected orientation angle.");
-		goto error;
-	}
-
-	rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, __screenWindowSize);
-	if (rc)
-	{
-		perror("screen_set_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
-		goto error;
-	}
-
-	rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_ROTATION, &angle);
-	if (rc)
-	{
-		perror("screen_set_window_property_iv(SCREEN_PROPERTY_ROTATION)");
-		goto error;
-	}
+    rc = screen_get_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, size);
+    if (rc)
+    {
+        perror("screen_get_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
+        goto error;
+    }
+
+    __screenWindowSize[0] = size[0];
+    __screenWindowSize[1] = size[1];
+
+    if ((angle == 0) || (angle == 180))
+    {
+        if (((screen_mode.width > screen_mode.height) && (size[0] < size[1])) ||
+            ((screen_mode.width < screen_mode.height) && (size[0] > size[1])))
+        {
+            __screenWindowSize[1] = size[0];
+            __screenWindowSize[0] = size[1];
+        }
+    }
+    else if ((angle == 90) || (angle == 270))
+    {
+        if (((screen_mode.width > screen_mode.height) && (size[0] > size[1])) ||
+            ((screen_mode.width < screen_mode.height) && (size[0] < size[1])))
+        {
+            __screenWindowSize[1] = size[0];
+            __screenWindowSize[0] = size[1];
+        }
+    }
+    else
+    {
+        perror("Navigator returned an unexpected orientation angle.");
+        goto error;
+    }
+
+    rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_BUFFER_SIZE, __screenWindowSize);
+    if (rc)
+    {
+        perror("screen_set_window_property_iv(SCREEN_PROPERTY_BUFFER_SIZE)");
+        goto error;
+    }
+
+    rc = screen_set_window_property_iv(__screenWindow, SCREEN_PROPERTY_ROTATION, &angle);
+    if (rc)
+    {
+        perror("screen_set_window_property_iv(SCREEN_PROPERTY_ROTATION)");
+        goto error;
+    }
 
     if (windowPosition[0] != 0 || windowPosition[1] != 0)
     {
@@ -962,7 +962,7 @@ int Platform::enterMessagePump()
                     _game->menu();
                     break;
                 case NAVIGATOR_EXIT:
-                    _game->exit();
+                    _game->end();
                     break;
                 }
             }
@@ -990,7 +990,7 @@ int Platform::enterMessagePump()
         rc = eglSwapBuffers(__eglDisplay, __eglSurface);
         if (rc != EGL_TRUE)
         {
-            _game->exit();
+            _game->end();
             perror("eglSwapBuffers");
             break;
         }

+ 4 - 4
gameplay/src/PlatformWin32.cpp

@@ -290,7 +290,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     case WM_LBUTTONDOWN:
         if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0))
         {
-	        gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
+            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, LOWORD(lParam), HIWORD(lParam), 0);
         }
         lMouseDown = true;
         return 0;
@@ -299,7 +299,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         lMouseDown = false;
         if (!gameplay::Game::getInstance()->mouseEvent(gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON, LOWORD(lParam), HIWORD(lParam), 0))
         {
-	        gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
+            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, LOWORD(lParam), HIWORD(lParam), 0);
         }
         return 0;
 
@@ -380,7 +380,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
         // Suppress key repeats
         if ((lParam & 0x40000000) == 0)
-	        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
+            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
         break;
         
     case WM_KEYUP:
@@ -589,7 +589,7 @@ int Platform::enterMessagePump()
 
             if (msg.message == WM_QUIT)
             {
-                _game->exit();
+                _game->end();
                 break;
             }
         }

+ 14 - 8
gameplay/src/RadioButton.cpp

@@ -27,7 +27,7 @@ RadioButton::~RadioButton()
 RadioButton* RadioButton::create(Theme::Style* style, Properties* properties)
 {
     RadioButton* radioButton = new RadioButton();
-    radioButton->init(style, properties);
+    radioButton->initialize(style, properties);
 
     properties->getVector2("imageSize", &radioButton->_imageSize);
 
@@ -48,6 +48,11 @@ RadioButton* RadioButton::create(Theme::Style* style, Properties* properties)
     return radioButton;
 }
 
+bool RadioButton::isSelected() const
+{
+    return _selected;
+}
+
 void RadioButton::setImageSize(float width, float height)
 {
     _imageSize.set(width, height);
@@ -82,8 +87,8 @@ bool RadioButton::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int c
         {
             if (_state == Control::ACTIVE)
             {
-                if (x > 0 && x <= _bounds.width &&
-                    y > 0 && y <= _bounds.height)
+                if (x > 0 && x <= _clipBounds.width &&
+                    y > 0 && y <= _clipBounds.height)
                 {
                     if (!_selected)
                     {
@@ -110,6 +115,7 @@ void RadioButton::clearSelected(const std::string& groupId)
         {
             radioButton->_selected = false;
             radioButton->_dirty = true;
+            radioButton->notifyListeners(Listener::VALUE_CHANGED);
         }
     }
 }
@@ -119,7 +125,7 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     // Left, v-center.
     // TODO: Set an alignment for radio button images.
     const Theme::Border border = getBorder(_state);
-    const Theme::Padding padding = _style->getPadding();
+    const Theme::Padding padding = getPadding();
     float opacity = getOpacity(_state);
 
     if (_selected)
@@ -139,8 +145,8 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             size.set(_imageSize);
         }
 
-        Vector2 pos(clip.x + _position.x + border.left + padding.left,
-            clip.y + _position.y + (_bounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
+        Vector2 pos(clip.x + _bounds.x + border.left + padding.left,
+            clip.y + _bounds.y + (_clipBounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
 
         spriteBatch->draw(pos.x, pos.y, size.x, size.y, selected.u1, selected.v1, selected.u2, selected.v2, selectedColor, _clip);
     }
@@ -161,8 +167,8 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             size.set(_imageSize);
         }
 
-        Vector2 pos(clip.x + _position.x + border.left + padding.left,
-            clip.y + _position.y + (_bounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
+        Vector2 pos(clip.x + _bounds.x + border.left + padding.left,
+            clip.y + _bounds.y + (_clipBounds.height - border.bottom - padding.bottom) / 2.0f - size.y / 2.0f);
 
         spriteBatch->draw(pos.x, pos.y, size.x, size.y, unselected.u1, unselected.v1, unselected.u2, unselected.v2, unselectedColor, _clip);
     }

+ 39 - 2
gameplay/src/RadioButton.h

@@ -36,7 +36,7 @@ public:
      *
      * @return Whether this radio button is currently selected.
      */
-    bool isSelected();
+    bool isSelected() const;
 
     /**
      * Set the size to draw the radio button icon.
@@ -66,7 +66,15 @@ public:
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     RadioButton();
+
+    /**
+     * Destructor.
+     */
     virtual ~RadioButton();
 
     /**
@@ -79,13 +87,41 @@ protected:
      */
     static RadioButton* create(Theme::Style* style, Properties* properties);
 
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void update(const Rectangle& clip);
 
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-    // Clear the _selected flag of all radio buttons in the given group.
+    /**
+     * Clear the _selected flag of all radio buttons in the given group.
+     *
+     * @param groupID The group to clear.
+     */
     static void clearSelected(const std::string& groupId);
 
     std::string _groupId;
@@ -93,6 +129,7 @@ protected:
     Vector2 _imageSize;
 
 private:
+
     RadioButton(const RadioButton& copy);
 };
 

+ 11 - 11
gameplay/src/Rectangle.cpp

@@ -9,12 +9,12 @@ Rectangle::Rectangle()
 {
 }
 
-Rectangle::Rectangle(unsigned int width, unsigned int height) :
+Rectangle::Rectangle(float width, float height) :
     x(0), y(0), width(width), height(height)
 {
 }
 
-Rectangle::Rectangle(float x, float y, unsigned int width, unsigned int height) :
+Rectangle::Rectangle(float x, float y, float width, float height) :
     x(x), y(y), width(width), height(height)
 {
 }
@@ -44,7 +44,7 @@ void Rectangle::set(const Rectangle& r)
     set(r.x, r.y, r.width, r.height);
 }
 
-void Rectangle::set(float x, float y, unsigned int width, unsigned int height)
+void Rectangle::set(float x, float y, float width, float height)
 {
     this->x = x;
     this->y = y;
@@ -70,22 +70,22 @@ float Rectangle::top() const
 
 float Rectangle::right() const
 {
-    return x + (float)width;
+    return x + width;
 }
 
 float Rectangle::bottom() const
 {
-    return y + (float)height;
+    return y + height;
 }
 
 bool Rectangle::contains(float x, float y) const
 {
-    return (x >= x && x <= (x + (float)width) && y >= y && y <= (y + (float)height));
+    return (x >= x && x <= (x + width) && y >= y && y <= (y + height));
 }
 
-bool Rectangle::contains(float x, float y, unsigned int width, unsigned int height) const
+bool Rectangle::contains(float x, float y, float width, float height) const
 {
-    return (contains(x, y) && contains(x + (float)width, y + (float)height));
+    return (contains(x, y) && contains(x + width, y + height));
 }
 
 bool Rectangle::contains(const Rectangle& r) const
@@ -93,12 +93,12 @@ bool Rectangle::contains(const Rectangle& r) const
     return contains(r.x, r.y, r.width, r.height);
 }
 
-bool Rectangle::intersects(float x, float y, unsigned int width, unsigned int height) const
+bool Rectangle::intersects(float x, float y, float width, float height) const
 {
     const float left   = max(this->x, x);
     const float top    = max(this->y, y);
-    const float right  = min(x + (float)width, x + (float)width);
-    const float bottom = min(y + (float)height, y + (float)height);
+    const float right  = min(x + width, x + width);
+    const float bottom = min(y + height, y + height);
 
     return (right > left && bottom > top);
 }

+ 7 - 7
gameplay/src/Rectangle.h

@@ -25,12 +25,12 @@ public:
     /**
      * Specifies the width of the rectangle.
      */
-    unsigned int width;
+    float width;
 
     /**
      * Specifies the height of the rectangle.
      */
-    unsigned int height;
+    float height;
 
     /**
      * Constructs a new rectangle initialized to all zeros.
@@ -43,7 +43,7 @@ public:
      * @param width The width of the rectangle.
      * @param height The height of the rectangle.
      */
-    Rectangle(unsigned int width, unsigned int height);
+    Rectangle(float width, float height);
 
     /**
      * Constructs a new rectangle with the specified x, y, width and height.
@@ -53,7 +53,7 @@ public:
      * @param width The width of the rectangle.
      * @param height The height of the rectangle.
      */
-    Rectangle(float x, float y, unsigned int width, unsigned int height);
+    Rectangle(float x, float y, float width, float height);
 
     /**
      * Constructs a new rectangle that is a copy of the specified rectangle.
@@ -89,7 +89,7 @@ public:
      * @param width The width of the rectangle.
      * @param height The height of the rectangle.
      */
-    void set(float x, float y, unsigned int width, unsigned int height);
+    void set(float x, float y, float width, float height);
 
     /**
      * Sets the values of this rectangle to those in the specified rectangle.
@@ -155,7 +155,7 @@ public:
      * @return true if the rectangle contains the specified rectangle, false
      * otherwise.
      */
-    bool contains(float x, float y, unsigned int width, unsigned int height) const;
+    bool contains(float x, float y, float width, float height) const;
 
     /**
      * Determines whether this rectangle contains a specified rectangle.
@@ -177,7 +177,7 @@ public:
      * 
      * @return true if the specified Rectangle intersects with this one, false otherwise.
      */
-    bool intersects(float x, float y, unsigned int width, unsigned int height) const;
+    bool intersects(float x, float y, float width, float height) const;
 
     /**
      * Determines whether a specified rectangle intersects with this rectangle.

+ 145 - 145
gameplay/src/Scene.cpp

@@ -282,38 +282,38 @@ void Scene::setAmbientColor(float red, float green, float blue)
 
 Material* createDebugMaterial()
 {
-	// Vertex shader for drawing colored lines.
-	const char* vs_str = 
-	{
-		"uniform mat4 u_viewProjectionMatrix;\n"
-		"attribute vec4 a_position;\n"
-		"attribute vec4 a_color;\n"
-		"varying vec4 v_color;\n"
-		"void main(void) {\n"
-		"    v_color = a_color;\n"
-		"    gl_Position = u_viewProjectionMatrix * a_position;\n"
-		"}"
-	};
-
-	// Fragment shader for drawing colored lines.
-	const char* fs_str = 
-	{
-	#ifdef OPENGL_ES
-		"precision highp float;\n"
-	#endif
-		"varying vec4 v_color;\n"
-		"void main(void) {\n"
-		"   gl_FragColor = v_color;\n"
-		"}"
-	};
-
-	Effect* effect = Effect::createFromSource(vs_str, fs_str);
-	Material* material = Material::create(effect);
-	material->getStateBlock()->setDepthTest(true);
-
-	SAFE_RELEASE(effect);
-
-	return material;
+    // Vertex shader for drawing colored lines.
+    const char* vs_str = 
+    {
+        "uniform mat4 u_viewProjectionMatrix;\n"
+        "attribute vec4 a_position;\n"
+        "attribute vec4 a_color;\n"
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "    v_color = a_color;\n"
+        "    gl_Position = u_viewProjectionMatrix * a_position;\n"
+        "}"
+    };
+
+    // Fragment shader for drawing colored lines.
+    const char* fs_str = 
+    {
+    #ifdef OPENGL_ES
+        "precision highp float;\n"
+    #endif
+        "varying vec4 v_color;\n"
+        "void main(void) {\n"
+        "   gl_FragColor = v_color;\n"
+        "}"
+    };
+
+    Effect* effect = Effect::createFromSource(vs_str, fs_str);
+    Material* material = Material::create(effect);
+    material->getStateBlock()->setDepthTest(true);
+
+    SAFE_RELEASE(effect);
+
+    return material;
 }
 
 struct DebugVertex
@@ -329,7 +329,7 @@ void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point
     verts[0].x = point1.x;
     verts[0].y = point1.y;
     verts[0].z = point1.z;
-	verts[0].r = color.x;
+    verts[0].r = color.x;
     verts[0].g = color.y;
     verts[0].b = color.z;
     verts[0].a = 1.0f;
@@ -342,7 +342,7 @@ void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point
     verts[1].b = color.z;
     verts[1].a = 1.0f;
 
-	batch->add(verts, 2);
+    batch->add(verts, 2);
 }
 
 #define DEBUG_BOX_COLOR Vector3(0, 1, 0)
@@ -350,141 +350,141 @@ void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point
 
 void drawDebugBox(MeshBatch* batch, const BoundingBox& box, const Matrix& matrix)
 {
-	// Transform box into world space (since we only store local boxes on mesh)
-	BoundingBox worldSpaceBox(box);
-	worldSpaceBox.transform(matrix);
+    // Transform box into world space (since we only store local boxes on mesh)
+    BoundingBox worldSpaceBox(box);
+    worldSpaceBox.transform(matrix);
 
-	// Get box corners
+    // Get box corners
     static Vector3 corners[8];
     worldSpaceBox.getCorners(corners);
 
-	// Draw box lines
-	drawDebugLine(batch, corners[0], corners[1], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[1], corners[2], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[2], corners[3], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[3], corners[0], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[4], corners[5], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[5], corners[6], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[6], corners[7], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[7], corners[4], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[0], corners[7], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[1], corners[6], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[2], corners[5], DEBUG_BOX_COLOR);
-	drawDebugLine(batch, corners[3], corners[4], DEBUG_BOX_COLOR);
+    // Draw box lines
+    drawDebugLine(batch, corners[0], corners[1], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[1], corners[2], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[2], corners[3], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[3], corners[0], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[4], corners[5], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[5], corners[6], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[6], corners[7], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[7], corners[4], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[0], corners[7], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[1], corners[6], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[2], corners[5], DEBUG_BOX_COLOR);
+    drawDebugLine(batch, corners[3], corners[4], DEBUG_BOX_COLOR);
 }
 
 void drawDebugSphere(MeshBatch* batch, const BoundingSphere& sphere)
 {
-	// Draw three rings for the sphere (one for the x, y and z axes)
-	Vector3 pos1, pos2;
-	float step = MATH_PI * 0.2f;
-	float max = MATH_PIX2 + step;
-
-	// X ring
-	for (float r = 0.0f; r < max; r += step)
-	{
-		pos2.x = sphere.center.x;
-		pos2.y = sphere.center.y + std::cos(r) * sphere.radius;
-		pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
-
-		if (r > 0)
-			drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-		pos1 = pos2;
-	}
-
-	// Y ring
-	for (float r = 0.0f; r < max; r += step)
-	{
-		pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
-		pos2.y = sphere.center.y;
-		pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
-
-		if (r > 0)
-			drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-		pos1 = pos2;
-	}
-
-	// Z ring
-	for (float r = 0.0f; r < max; r += step)
-	{
-		pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
-		pos2.y = sphere.center.y + std::sin(r) * sphere.radius;
-		pos2.z = sphere.center.z;
-
-		if (r > 0)
-			drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-		pos1 = pos2;
-	}
+    // Draw three rings for the sphere (one for the x, y and z axes)
+    Vector3 pos1, pos2;
+    float step = MATH_PI * 0.2f;
+    float max = MATH_PIX2 + step;
+
+    // X ring
+    for (float r = 0.0f; r < max; r += step)
+    {
+        pos2.x = sphere.center.x;
+        pos2.y = sphere.center.y + std::cos(r) * sphere.radius;
+        pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
+
+        if (r > 0)
+            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
+
+        pos1 = pos2;
+    }
+
+    // Y ring
+    for (float r = 0.0f; r < max; r += step)
+    {
+        pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
+        pos2.y = sphere.center.y;
+        pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
+
+        if (r > 0)
+            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
+
+        pos1 = pos2;
+    }
+
+    // Z ring
+    for (float r = 0.0f; r < max; r += step)
+    {
+        pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
+        pos2.y = sphere.center.y + std::sin(r) * sphere.radius;
+        pos2.z = sphere.center.z;
+
+        if (r > 0)
+            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
+
+        pos1 = pos2;
+    }
 }
 
 void drawDebugNode(MeshBatch* batch, Node* node, unsigned int debugFlags)
 {
-	Model* model = node->getModel();
-
-	if ((debugFlags & Scene::DEBUG_BOXES) && model)
-	{
-		MeshSkin* skin = model->getSkin();
-		if (skin && skin->getRootJoint()->getParent())
-		{
-			// For skinned meshes that have a parent node to the skin's root joint,
-			// we need to transform the bounding volume by that parent node's transform
-			// as well to get the full skinned bounding volume.
-			drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix() * skin->getRootJoint()->getParent()->getWorldMatrix());
-		}
-		else
-		{
-			drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix());
-		}
-	}
-
-	if ((debugFlags & Scene::DEBUG_SPHERES) && model)
-	{
-		drawDebugSphere(batch, node->getBoundingSphere());
-	}
-
-	Node* child = node->getFirstChild();
-	while (child)
-	{
-		drawDebugNode(batch, child, debugFlags);
-		child = child->getNextSibling();
-	}
+    Model* model = node->getModel();
+
+    if ((debugFlags & Scene::DEBUG_BOXES) && model)
+    {
+        MeshSkin* skin = model->getSkin();
+        if (skin && skin->getRootJoint()->getParent())
+        {
+            // For skinned meshes that have a parent node to the skin's root joint,
+            // we need to transform the bounding volume by that parent node's transform
+            // as well to get the full skinned bounding volume.
+            drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix() * skin->getRootJoint()->getParent()->getWorldMatrix());
+        }
+        else
+        {
+            drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix());
+        }
+    }
+
+    if ((debugFlags & Scene::DEBUG_SPHERES) && model)
+    {
+        drawDebugSphere(batch, node->getBoundingSphere());
+    }
+
+    Node* child = node->getFirstChild();
+    while (child)
+    {
+        drawDebugNode(batch, child, debugFlags);
+        child = child->getNextSibling();
+    }
 }
 
 void Scene::drawDebug(unsigned int debugFlags)
 {
-	if (_debugBatch == NULL)
-	{
-		Material* material = createDebugMaterial();
+    if (_debugBatch == NULL)
+    {
+        Material* material = createDebugMaterial();
 
-		VertexFormat::Element elements[] =
-		{
-			VertexFormat::Element(VertexFormat::POSITION, 3),
-			VertexFormat::Element(VertexFormat::COLOR, 4)
-		};
+        VertexFormat::Element elements[] =
+        {
+            VertexFormat::Element(VertexFormat::POSITION, 3),
+            VertexFormat::Element(VertexFormat::COLOR, 4)
+        };
 
-		_debugBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
+        _debugBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
 
-		SAFE_RELEASE(material);
-	}
+        SAFE_RELEASE(material);
+    }
 
-	_debugBatch->begin();
+    _debugBatch->begin();
 
-	Node* node = _firstNode;
-	while (node)
-	{
-		drawDebugNode(_debugBatch, node, debugFlags);
-		node = node->_nextSibling;
-	}
+    Node* node = _firstNode;
+    while (node)
+    {
+        drawDebugNode(_debugBatch, node, debugFlags);
+        node = node->_nextSibling;
+    }
 
-	_debugBatch->end();
+    _debugBatch->end();
 
-	if (_activeCamera)
-		_debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
+    if (_activeCamera)
+        _debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
 
-	_debugBatch->draw();
+    _debugBatch->draw();
 }
 
 }

+ 16 - 16
gameplay/src/Scene.h

@@ -14,14 +14,14 @@ class Scene : public Ref
 {
 public:
 
-	/**
-	 * Enumeration of supported scene debug flags for debug drawing.
-	 */
-	enum DebugFlags
-	{
-		DEBUG_BOXES = 1,
-		DEBUG_SPHERES = 2
-	};
+    /**
+     * Enumeration of supported scene debug flags for debug drawing.
+     */
+    enum DebugFlags
+    {
+        DEBUG_BOXES = 1,
+        DEBUG_SPHERES = 2
+    };
 
     /**
      * Creates a new empty scene.
@@ -176,13 +176,13 @@ public:
     template <class T>
     void visit(T* instance, bool (T::*visitMethod)(Node*,void*), void* cookie = 0);
 
-	/**
-	 * Draws debugging information (bounding volumes, etc.) for the scene.
-	 *
-	 * @param debugFlags Bitwise combination of debug flags from mthe DebugFlags 
-	 *		enumeration, specifying which debugging information to draw.
-	 */
-	void drawDebug(unsigned int debugFlags);
+    /**
+     * Draws debugging information (bounding volumes, etc.) for the scene.
+     *
+     * @param debugFlags Bitwise combination of debug flags from mthe DebugFlags 
+     *        enumeration, specifying which debugging information to draw.
+     */
+    void drawDebug(unsigned int debugFlags);
 
 private:
 
@@ -214,7 +214,7 @@ private:
     unsigned int _nodeCount;
     Vector3 _ambientColor;
     bool _bindAudioListenerToCamera;
-	MeshBatch* _debugBatch;
+    MeshBatch* _debugBatch;
 };
 
 template <class T>

+ 11 - 11
gameplay/src/SceneLoader.cpp

@@ -312,22 +312,22 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                             Model* model = node->getModel();
                         
                             // Up ref count to prevent node from releasing the model when we swap it.
-						    model->addRef(); 
+                            model->addRef(); 
                         
-						    // Create collision object with new rigidbodymodel set.
+                            // Create collision object with new rigidbodymodel set.
                             node->setModel(modelNode->getModel());
-						    node->setCollisionObject(p);
+                            node->setCollisionObject(p);
 
-						    // Restore original model.
+                            // Restore original model.
                             node->setModel(model);
-						
+                        
                             // Decrement temporarily added reference.
                             model->release();
                         }
                     }
                 }
                 else
-				    node->setCollisionObject(p);
+                    node->setCollisionObject(p);
             }
             break;
         }
@@ -668,7 +668,7 @@ void SceneLoader::createAnimations(const Scene* scene)
             }
         }
 
-        Game::getInstance()->getAnimationController()->createAnimation(_animations[i]._animationID, node, p);
+        node->createAnimation(_animations[i]._animationID, p);
     }
 }
 
@@ -814,12 +814,12 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
                 WARN_VARG("Node '%s' to be used as 'rigidBodyA' for constraint %s cannot be found.", name, constraint->getId());
                 continue;
             }
-			if (!rbANode->getCollisionObject() || rbANode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
+            if (!rbANode->getCollisionObject() || rbANode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
             {
                 WARN_VARG("Node '%s' to be used as 'rigidBodyA' does not have a rigid body.", name);
                 continue;
             }
-			PhysicsRigidBody* rbA = static_cast<PhysicsRigidBody*>(rbANode->getCollisionObject());
+            PhysicsRigidBody* rbA = static_cast<PhysicsRigidBody*>(rbANode->getCollisionObject());
 
             // Attempt to load the second rigid body. If the second rigid body is not
             // specified, that is usually okay (only spring constraints require both and
@@ -835,12 +835,12 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
                     WARN_VARG("Node '%s' to be used as 'rigidBodyB' for constraint %s cannot be found.", name, constraint->getId());
                     continue;
                 }
-				if (!rbBNode->getCollisionObject() || rbBNode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
+                if (!rbBNode->getCollisionObject() || rbBNode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
                 {
                     WARN_VARG("Node '%s' to be used as 'rigidBodyB' does not have a rigid body.", name);
                     continue;
                 }
-				rbB = static_cast<PhysicsRigidBody*>(rbBNode->getCollisionObject());
+                rbB = static_cast<PhysicsRigidBody*>(rbBNode->getCollisionObject());
             }
 
             PhysicsConstraint* physicsConstraint = NULL;

+ 2 - 2
gameplay/src/SceneLoader.h

@@ -16,8 +16,8 @@ namespace gameplay
  * @todo Add support for loading ghost objects and characters for nodes.
  * @todo Add support for explicitly specifying collision shapes for rigid bodies/ghost objects/characters.
  * @todo Consider supporting 'rigidbodymodel' on models/meshes that are not part of the scene to allow
- *		mesh data to be exported from a modelling tool for the sole purpose of representing a physics
- *		rigid body, but not have it get loaded into the scene and rendering context.
+ *        mesh data to be exported from a modelling tool for the sole purpose of representing a physics
+ *        rigid body, but not have it get loaded into the scene and rendering context.
  */
 class SceneLoader
 {

+ 69 - 0
gameplay/src/ScreenDisplayer.h

@@ -0,0 +1,69 @@
+#ifndef SCREENDISPLAYER_H_
+#define SCREENDISPLAYER_H_
+
+#include "Game.h"
+#include "Platform.h"
+
+namespace gameplay
+{
+
+/**
+ * Used for displaying screens (i.e. splash or level loading screens).
+ */
+class ScreenDisplayer
+{
+public:
+
+    /**
+     * Displays a screen using the {@link Game#renderOnce} mechanism for at least the given amount of time.
+     * 
+     * @param instance See {@link Game#renderOnce}.
+     * @param method See {@link Game#renderOnce}.
+     * @param cookie See {@link Game#renderOnce}.
+     * @param time The minimum amount of time to display the screen (in milliseconds).
+     */
+    template <typename T> void run(T* instance, void (T::*method) (void*), void* cookie, long time);
+
+    /**
+     * Destructor.
+     */
+    ~ScreenDisplayer();
+
+private:
+
+    long _time;
+    long _startTime;
+};
+
+template <typename T> void ScreenDisplayer::run(T* instance, void (T::*method) (void*), void* cookie, long time)
+{
+    _time = time;
+    Game::getInstance()->renderOnce(instance, method, cookie);
+    _startTime = Game::getInstance()->getGameTime();
+}
+
+inline ScreenDisplayer::~ScreenDisplayer()
+{
+    long elapsedTime = Game::getInstance()->getGameTime() - _startTime;
+    if (elapsedTime < _time)
+        Platform::sleep(_time - (Game::getInstance()->getGameTime() - _startTime));
+}
+
+/**
+ * Displays a screen using the {@link Game#renderOnce} mechanism for at least the given amount
+ * of time. This function is intended to be called at the beginning of a block of code that is be 
+ * executed while the screen is displayed (i.e. Game#initialize). This function will block 
+ * at the end of the block of code in which it is called for the amount of time that has not yet elapsed.
+ * 
+ * @param instance See {@link Game#renderOnce}.
+ * @param method See {@link Game#renderOnce}.
+ * @param cookie See {@link Game#renderOnce}.
+ * @param time The minimum amount of time to display the screen (in milliseconds).
+ */
+#define displayScreen(instance, method, cookie, time) \
+    ScreenDisplayer __##instance##ScreenDisplayer; \
+    __##instance##ScreenDisplayer.run(instance, method, cookie, time)
+
+}
+
+#endif

+ 15 - 15
gameplay/src/Slider.cpp

@@ -14,7 +14,7 @@ Slider::~Slider()
 Slider* Slider::create(Theme::Style* style, Properties* properties)
 {
     Slider* slider = new Slider();
-    slider->init(style, properties);
+    slider->initialize(style, properties);
 
     slider->_min = properties->getFloat("min");
     slider->_max = properties->getFloat("max");
@@ -91,8 +91,8 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
     case Touch::TOUCH_MOVE:
     case Touch::TOUCH_RELEASE:
         if (_state == ACTIVE &&
-            x > 0 && x <= _bounds.width &&
-            y > 0 && y <= _bounds.height)
+            x > 0 && x <= _clipBounds.width &&
+            y > 0 && y <= _clipBounds.height)
         {
             // Horizontal case.
             const Theme::Border& border = getBorder(_state);
@@ -101,7 +101,7 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
             const Rectangle& maxCapRegion = getImageRegion("maxCap", _state);
 
             float markerPosition = ((float)x - maxCapRegion.width - border.left - padding.left) /
-                (_bounds.width - border.left - border.right - padding.left - padding.right - minCapRegion.width - maxCapRegion.width);
+                (_clipBounds.width - border.left - border.right - padding.left - padding.right - minCapRegion.width - maxCapRegion.width);
             
             if (markerPosition > 1.0f)
             {
@@ -113,7 +113,7 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
             }
 
             float oldValue = _value;
-            _value = markerPosition * _max;
+            _value = (markerPosition * (_max - _min)) + _min;
             if (_step > 0.0f)
             {
                 float stepDistance = _step / (_max - _min);
@@ -167,23 +167,23 @@ void Slider::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     trackColor.w *= opacity;
 
     // Draw order: track, caps, marker.
-    float midY = clip.y + _bounds.y + (_bounds.height - border.bottom - padding.bottom) / 2.0f;
-    Vector2 pos(clip.x + _bounds.x + border.left + padding.left, midY - trackRegion.height / 2.0f);
-    spriteBatch->draw(pos.x, pos.y, _bounds.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor);
+    float midY = clip.y + _clipBounds.y + (_clipBounds.height - border.bottom - padding.bottom) / 2.0f;
+    Vector2 pos(clip.x + _clipBounds.x + border.left + padding.left, midY - trackRegion.height / 2.0f);
+    spriteBatch->draw(pos.x, pos.y, _clipBounds.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _clip);
 
     pos.y = midY - minCapRegion.height * 0.5f;
     pos.x -= minCapRegion.width * 0.5f;
-    spriteBatch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor);
+    spriteBatch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _clip);
         
-    pos.x = clip.x + _bounds.x + _bounds.width - border.right - padding.right - maxCapRegion.width * 0.5f;
-    spriteBatch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor);
+    pos.x = clip.x + _clipBounds.x + _clipBounds.width - border.right - padding.right - maxCapRegion.width * 0.5f;
+    spriteBatch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _clip);
 
     // Percent across.
-    float markerPosition = _value / (_max - _min);
-    markerPosition *= _bounds.width - border.left - padding.left - border.right - padding.right - minCapRegion.width * 0.5f - maxCapRegion.width * 0.5f - markerRegion.width;
-    pos.x = clip.x + _bounds.x + border.left + padding.left + minCapRegion.width * 0.5f + markerPosition;
+    float markerPosition = (_value - _min) / (_max - _min);
+    markerPosition *= _clipBounds.width - border.left - padding.left - border.right - padding.right - minCapRegion.width * 0.5f - maxCapRegion.width * 0.5f - markerRegion.width;
+    pos.x = clip.x + _clipBounds.x + border.left + padding.left + minCapRegion.width * 0.5f + markerPosition;
     pos.y = midY - markerRegion.height / 2.0f;
-    spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor);
+    spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _clip);
 }
 
 }

+ 46 - 0
gameplay/src/Slider.h

@@ -32,6 +32,7 @@ class Slider : public Label
     friend class Container;
 
 public:
+
     /**
      * Set the minimum value that can be set on this slider.
      *
@@ -90,16 +91,60 @@ public:
      */
     float getValue();
 
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
     void addListener(Control::Listener* listener, int eventFlags);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     Slider();
+
+    /**
+     * Destructor.
+     */
     ~Slider();
 
+    /**
+     * Create a slider with a given style and properties.
+     *
+     * @param style The style to apply to this slider.
+     * @param properties The properties to set on this slider.
+     *
+     * @return The new slider.
+     */
     static Slider* create(Theme::Style* style, Properties* properties);
 
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
 
     float _min;
@@ -108,6 +153,7 @@ protected:
     float _value;
 
 private:
+
     Slider(const Slider& copy);
 };
 

+ 80 - 70
gameplay/src/TextBox.cpp

@@ -19,7 +19,7 @@ TextBox::~TextBox()
 TextBox* TextBox::create(Theme::Style* style, Properties* properties)
 {
     TextBox* textBox = new TextBox();
-    textBox->init(style, properties);
+    textBox->initialize(style, properties);
 
     return textBox;
 }
@@ -29,15 +29,6 @@ int TextBox::getLastKeypress()
     return _lastKeypress;
 }
 
-void TextBox::setCursorLocation(int x, int y)
-{
-    Theme::Border border = getBorder(_state);
-    Theme::Padding padding = getPadding();
-
-    _cursorLocation.set(x - border.left - padding.left + _clip.x,
-                       y - border.top - padding.top + _clip.y);
-}
-
 void TextBox::addListener(Control::Listener* listener, int eventFlags)
 {
     if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
@@ -66,8 +57,8 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
             _dirty = true;
             return _consumeTouchEvents;
         }
-        else if (!(x > 0 && x <= _bounds.width &&
-                    y > 0 && y <= _bounds.height))
+        else if (!(x > 0 && x <= _clipBounds.width &&
+                    y > 0 && y <= _clipBounds.height))
         {
             _state = NORMAL;
             Game::getInstance()->displayKeyboard(false);
@@ -77,19 +68,19 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
         break;
     case Touch::TOUCH_MOVE:
         if (_state == FOCUS &&
-            x > 0 && x <= _bounds.width &&
-            y > 0 && y <= _bounds.height)
+            x > 0 && x <= _clipBounds.width &&
+            y > 0 && y <= _clipBounds.height)
         {
-            setCursorLocation(x, y);
+            setCaretLocation(x, y);
             _dirty = true;
             return _consumeTouchEvents;
         }
         break;
     case Touch::TOUCH_RELEASE:
-        if (x > 0 && x <= _bounds.width &&
-            y > 0 && y <= _bounds.height)
+        if (x > 0 && x <= _clipBounds.width &&
+            y > 0 && y <= _clipBounds.height)
         {
-            setCursorLocation(x, y);
+            setCaretLocation(x, y);
             _state = FOCUS;
             _dirty = true;
             return _consumeTouchEvents;
@@ -115,7 +106,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         // TODO: Move cursor to beginning of line.
                         // This only works for left alignment...
                         
-                        //_cursorLocation.x = _clip.x;
+                        //_caretLocation.x = _clip.x;
                         //_dirty = true;
                         break;
                     }
@@ -126,66 +117,71 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     }
                     case Keyboard::KEY_DELETE:
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
 
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+                            textAlignment, true, rightToLeft);
                         _text.erase(textIndex, 1);
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex,
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         notifyListeners(Listener::TEXT_CHANGED);
                         break;
                     }
                     case Keyboard::KEY_LEFT_ARROW:
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
-
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex - 1,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
+
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+                            textAlignment, true, rightToLeft);
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex - 1,
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
                     }
                     case Keyboard::KEY_RIGHT_ARROW:
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
-
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
+
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+                            textAlignment, true, rightToLeft);
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex + 1,
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
                     }
                     case Keyboard::KEY_UP_ARROW:
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
-
-                        _cursorLocation.y -= fontSize;
-                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
+
+                        _caretLocation.y -= fontSize;
+                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
                     }
                     case Keyboard::KEY_DOWN_ARROW:
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
-
-                        _cursorLocation.y += fontSize;
-                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
+
+                        _caretLocation.y += fontSize;
+                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
                     }
@@ -195,11 +191,13 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
 
             case Keyboard::KEY_CHAR:
             {
-                Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                Font* font = overlay->getFont();
-                unsigned int fontSize = overlay->getFontSize();
-                unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                    overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                Font* font = getFont(_state);
+                unsigned int fontSize = getFontSize(_state);
+                Font::Justify textAlignment = getTextAlignment(_state);
+                bool rightToLeft = getTextRightToLeft(_state);
+
+                unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+                    textAlignment, true, rightToLeft);
 
                 switch (key)
                 {
@@ -209,8 +207,8 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         {
                             --textIndex;
                             _text.erase(textIndex, 1);
-                            font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
-                                overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex,
+                                textAlignment, true, rightToLeft);
 
                             _dirty = true;
                         }
@@ -225,8 +223,8 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         _text.insert(textIndex, 1, (char)key);
 
                         // Get new location of cursor.
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex + 1,
+                            textAlignment, true, rightToLeft);
                 
                         _dirty = true;
                         break;
@@ -250,10 +248,13 @@ void TextBox::update(const Rectangle& clip)
     // Get index into string and cursor location from the last recorded touch location.
     if (_state == FOCUS)
     {
-        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-        Font* font = overlay->getFont();
-        font->getIndexAtLocation(_text.c_str(), _clip, overlay->getFontSize(), _cursorLocation, &_cursorLocation,
-            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+        Font* font = getFont(_state);
+        unsigned int fontSize = getFontSize(_state);
+        Font::Justify textAlignment = getTextAlignment(_state);
+        bool rightToLeft = getTextRightToLeft(_state);
+
+        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
+            textAlignment, true, rightToLeft);
     }
 }
 
@@ -269,11 +270,20 @@ void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             const Theme::UVs uvs = getImageUVs("textCaret", _state);
             unsigned int fontSize = getFontSize(_state);
 
-            spriteBatch->draw(_cursorLocation.x - (region.width / 2.0f), _cursorLocation.y, region.width, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
+            spriteBatch->draw(_caretLocation.x - (region.width / 2.0f), _caretLocation.y, region.width, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
         }
     }
 
     _dirty = false;
 }
 
+void TextBox::setCaretLocation(int x, int y)
+{
+    Theme::Border border = getBorder(_state);
+    Theme::Padding padding = getPadding();
+
+    _caretLocation.set(x - border.left - padding.left + _clip.x,
+                       y - border.top - padding.top + _clip.y);
+}
+
 }

+ 60 - 4
gameplay/src/TextBox.h

@@ -31,6 +31,7 @@ class TextBox : public Label
     friend class Container;
 
 public:
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -43,31 +44,86 @@ public:
      */
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
+    /**
+     * Get the last key pressed within this text box.
+     *
+     * @return The last key pressed within this text box.
+     */
     int getLastKeypress();
 
 protected:
+
+    /**
+     * Constructor.
+     */
     TextBox();
+
+    /**
+     * Destructor.
+     */
     ~TextBox();
 
+    /**
+     * Create a text box with a given style and properties.
+     *
+     * @param style The style to apply to this text box.
+     * @param properties The properties to set on this text box.
+     *
+     * @return The new text box.
+     */
     static TextBox* create(Theme::Style* style, Properties* properties);
 
-    void setCursorLocation(int x, int y);
-
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Keyboard callback on key events.
+     *
+     * @param evt The key event that occured.
+     * @param key If evt is KEY_PRESS or KEY_RELEASE then key is the key code from Keyboard::Key.
+     *            If evt is KEY_CHAR then key is the unicode value of the character.
+     * 
+     * @see Keyboard::KeyEvent
+     * @see Keyboard::Key
+     */
     void keyEvent(Keyboard::KeyEvent evt, int key);
 
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void update(const Rectangle& clip);
 
-    // Draw the cursor.
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-    Vector2 _cursorLocation;
+    Vector2 _caretLocation;
     unsigned int textIndex;
     int _lastKeypress;
 
 private:
+
     TextBox(const TextBox& copy);
+
+    void setCaretLocation(int x, int y);
 };
 
 }

+ 127 - 127
gameplay/src/Texture.cpp

@@ -73,15 +73,15 @@ Texture* Texture::create(const char* path, bool generateMipmaps)
                     texture = create(image, generateMipmaps);
                 SAFE_RELEASE(image);
             }
-			else if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'v' && tolower(ext[3]) == 'r')
-			{
+            else if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'v' && tolower(ext[3]) == 'r')
+            {
 #ifdef OPENGL_ES_PVR
-            	// PowerVR Compressed RGBA
-				texture = createCompressedPVR(path);
+                // PowerVR Compressed RGBA
+                texture = createCompressedPVR(path);
 #else
                 texture = NULL; // Cannot handle PVR if not supported on platform
 #endif
-			}
+            }
             break;
         }
     }
@@ -150,134 +150,134 @@ Texture* Texture::create(Format format, unsigned int width, unsigned int height,
 #ifdef OPENGL_ES_PVR
 Texture* Texture::createCompressedPVR(const char* path)
 {
-	char PVRTexIdentifier[] = "PVR!";
-
-	enum
-	{
-	    PVRTextureFlagTypePVRTC_2 = 24,
-	    PVRTextureFlagTypePVRTC_4
-	};
-
-	struct pvr_file_header
-	{
-		unsigned int size;          		// size of the structure
-		unsigned int height;              	// height of surface to be created
-		unsigned int width;               	// width of input surface
-		unsigned int mipmapCount;         	// number of mip-map levels requested
-		unsigned int formatflags;           // pixel format flags
-		unsigned int dataSize;     			// total size in bytes
-		unsigned int bpp;            		// number of bits per pixel
-		unsigned int redBitMask;            // mask for red bit
-		unsigned int greenBitMask;          // mask for green bits
-		unsigned int blueBitMask;           // mask for blue bits
-		unsigned int alphaBitMask;        	// mask for alpha channel
-		unsigned int pvrTag;                // magic number identifying pvr file
-		unsigned int surfaceCount;          // number of surfaces present in the pvr
-	} ;
-
-	FILE* file = FileSystem::openFile(path, "rb");
-	if (file == NULL)
-	{
-		LOG_ERROR_VARG("Failed to load file: %s", path);
-		return NULL;
-	}
-
-	// Read the file header
-	unsigned int size = sizeof(pvr_file_header);
-	pvr_file_header header;
-	unsigned int read = (int)fread(&header, 1, size, file);
-	assert(read == size);
-	if (read != size)
-	{
-		LOG_ERROR_VARG("Read file header error for pvr file: %s (%d < %d)", path, (int)read, (int)size);
-		fclose(file);
-		return NULL;
-	}
-
-	// Proper file header identifier
-	if (PVRTexIdentifier[0] != (char)((header.pvrTag >>  0) & 0xff) ||
-		PVRTexIdentifier[1] != (char)((header.pvrTag >>  8) & 0xff) ||
-	    PVRTexIdentifier[2] != (char)((header.pvrTag >> 16) & 0xff) ||
-	    PVRTexIdentifier[3] != (char)((header.pvrTag >> 24) & 0xff))
-	 {
-		LOG_ERROR_VARG("Invalid PVR texture file: %s", path);
-		fclose(file);
-	    return NULL;
-	}
-
-	// Format flags for GLenum format
-	GLenum format;
-	unsigned int formatFlags = header.formatflags & 0xff;
-	if (formatFlags == PVRTextureFlagTypePVRTC_4)
-	{
-		format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_4BPP : COMPRESSED_RGB_PVRTC_4BPP;
-	}
-	else if (formatFlags == PVRTextureFlagTypePVRTC_2)
-	{
-		format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_2BPP : COMPRESSED_RGB_PVRTC_2BPP;
-	}
-	else
-	{
-		LOG_ERROR_VARG("Invalid PVR texture format flags for file: %s", path);
-		fclose(file);
-		return NULL;
-	}
-
-	unsigned char* data = new unsigned char[header.dataSize];
-	read = (int)fread(data, 1, header.dataSize, file);
-	assert(read == header.dataSize);
-	if (read != header.dataSize)
-	{
-		LOG_ERROR_VARG("Read file data error for pvr file: %s (%d < %d)", path, (int)read, (int)header.dataSize);
-		SAFE_DELETE_ARRAY(data);
-		fclose(file);
-		return NULL;
-	}
-	// Close file
-	fclose(file);
-
-	// Load our texture.
-	GLuint textureId;
-	GL_ASSERT( glGenTextures(1, &textureId) );
-	GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
-	GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, header.mipmapCount > 0 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) );
+    char PVRTexIdentifier[] = "PVR!";
+
+    enum
+    {
+        PVRTextureFlagTypePVRTC_2 = 24,
+        PVRTextureFlagTypePVRTC_4
+    };
+
+    struct pvr_file_header
+    {
+        unsigned int size;                  // size of the structure
+        unsigned int height;                  // height of surface to be created
+        unsigned int width;                   // width of input surface
+        unsigned int mipmapCount;             // number of mip-map levels requested
+        unsigned int formatflags;           // pixel format flags
+        unsigned int dataSize;                 // total size in bytes
+        unsigned int bpp;                    // number of bits per pixel
+        unsigned int redBitMask;            // mask for red bit
+        unsigned int greenBitMask;          // mask for green bits
+        unsigned int blueBitMask;           // mask for blue bits
+        unsigned int alphaBitMask;            // mask for alpha channel
+        unsigned int pvrTag;                // magic number identifying pvr file
+        unsigned int surfaceCount;          // number of surfaces present in the pvr
+    } ;
+
+    FILE* file = FileSystem::openFile(path, "rb");
+    if (file == NULL)
+    {
+        LOG_ERROR_VARG("Failed to load file: %s", path);
+        return NULL;
+    }
+
+    // Read the file header
+    unsigned int size = sizeof(pvr_file_header);
+    pvr_file_header header;
+    unsigned int read = (int)fread(&header, 1, size, file);
+    assert(read == size);
+    if (read != size)
+    {
+        LOG_ERROR_VARG("Read file header error for pvr file: %s (%d < %d)", path, (int)read, (int)size);
+        fclose(file);
+        return NULL;
+    }
+
+    // Proper file header identifier
+    if (PVRTexIdentifier[0] != (char)((header.pvrTag >>  0) & 0xff) ||
+        PVRTexIdentifier[1] != (char)((header.pvrTag >>  8) & 0xff) ||
+        PVRTexIdentifier[2] != (char)((header.pvrTag >> 16) & 0xff) ||
+        PVRTexIdentifier[3] != (char)((header.pvrTag >> 24) & 0xff))
+     {
+        LOG_ERROR_VARG("Invalid PVR texture file: %s", path);
+        fclose(file);
+        return NULL;
+    }
+
+    // Format flags for GLenum format
+    GLenum format;
+    unsigned int formatFlags = header.formatflags & 0xff;
+    if (formatFlags == PVRTextureFlagTypePVRTC_4)
+    {
+        format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_4BPP : COMPRESSED_RGB_PVRTC_4BPP;
+    }
+    else if (formatFlags == PVRTextureFlagTypePVRTC_2)
+    {
+        format = header.alphaBitMask ? COMPRESSED_RGBA_PVRTC_2BPP : COMPRESSED_RGB_PVRTC_2BPP;
+    }
+    else
+    {
+        LOG_ERROR_VARG("Invalid PVR texture format flags for file: %s", path);
+        fclose(file);
+        return NULL;
+    }
+
+    unsigned char* data = new unsigned char[header.dataSize];
+    read = (int)fread(data, 1, header.dataSize, file);
+    assert(read == header.dataSize);
+    if (read != header.dataSize)
+    {
+        LOG_ERROR_VARG("Read file data error for pvr file: %s (%d < %d)", path, (int)read, (int)header.dataSize);
+        SAFE_DELETE_ARRAY(data);
+        fclose(file);
+        return NULL;
+    }
+    // Close file
+    fclose(file);
+
+    // Load our texture.
+    GLuint textureId;
+    GL_ASSERT( glGenTextures(1, &textureId) );
+    GL_ASSERT( glBindTexture(GL_TEXTURE_2D, textureId) );
+    GL_ASSERT( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, header.mipmapCount > 0 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) );
 
     Texture* texture = new Texture();
     texture->_handle = textureId;
     texture->_width = header.width;
     texture->_height = header.height;
 
-	// Load the data for each level
-	unsigned int width = header.width;
-	unsigned int height = header.height;
-	unsigned int blockSize = 0;
-	unsigned int widthBlocks = 0;
-	unsigned int heightBlocks = 0;
-	unsigned int bpp = 0;
-	unsigned int dataSize = 0;
-	unsigned char* dataOffset = data;
-
-	for (unsigned int level = 0; level <= header.mipmapCount; level++)
-	{
-		if (formatFlags == PVRTextureFlagTypePVRTC_4)
-		{
-			dataSize = ( max((int)width, 8) * max((int)height, 8) * 4 + 7) / 8;
-		}
-		else
-		{
-			dataSize = ( max((int)width, 16) * max((int)height, 8) * 2 + 7) / 8;
-		}
-
-		GL_ASSERT( glCompressedTexImage2D(GL_TEXTURE_2D, level, (GLenum)format, width, height, 0, dataSize, dataOffset) );
-
-		dataOffset += dataSize;
-		width = max((int)width >> 1, 1);
-		height = max((int)height >> 1, 1);
-	}
-
-	SAFE_DELETE_ARRAY(data);
-
-	return texture;
+    // Load the data for each level
+    unsigned int width = header.width;
+    unsigned int height = header.height;
+    unsigned int blockSize = 0;
+    unsigned int widthBlocks = 0;
+    unsigned int heightBlocks = 0;
+    unsigned int bpp = 0;
+    unsigned int dataSize = 0;
+    unsigned char* dataOffset = data;
+
+    for (unsigned int level = 0; level <= header.mipmapCount; level++)
+    {
+        if (formatFlags == PVRTextureFlagTypePVRTC_4)
+        {
+            dataSize = ( max((int)width, 8) * max((int)height, 8) * 4 + 7) / 8;
+        }
+        else
+        {
+            dataSize = ( max((int)width, 16) * max((int)height, 8) * 2 + 7) / 8;
+        }
+
+        GL_ASSERT( glCompressedTexImage2D(GL_TEXTURE_2D, level, (GLenum)format, width, height, 0, dataSize, dataOffset) );
+
+        dataOffset += dataSize;
+        width = max((int)width >> 1, 1);
+        height = max((int)height >> 1, 1);
+    }
+
+    SAFE_DELETE_ARRAY(data);
+
+    return texture;
 }
 #endif
     

+ 4 - 4
gameplay/src/Texture.h

@@ -32,9 +32,9 @@ public:
         DEPTH   = GL_DEPTH_COMPONENT,
 #ifdef OPENGL_ES_PVR
         COMPRESSED_RGB_PVRTC_4BPP = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
-		COMPRESSED_RGBA_PVRTC_4BPP = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
-		COMPRESSED_RGB_PVRTC_2BPP = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
-		COMPRESSED_RGBA_PVRTC_2BPP = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
+        COMPRESSED_RGBA_PVRTC_4BPP = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
+        COMPRESSED_RGB_PVRTC_2BPP = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
+        COMPRESSED_RGBA_PVRTC_2BPP = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
 #endif
     };
 
@@ -214,7 +214,7 @@ private:
     virtual ~Texture();
 
 #ifdef OPENGL_ES_PVR
-	static Texture* createCompressedPVR(const char* path);
+    static Texture* createCompressedPVR(const char* path);
 #endif
     
     std::string _path;

+ 2 - 466
gameplay/src/Theme.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "Theme.h"
+#include "ThemeStyle.h"
 
 namespace gameplay
 {
@@ -9,7 +10,7 @@ namespace gameplay
     {
     }
 
-    Theme::Theme(const Theme* theme)
+    Theme::Theme(const Theme& theme)
     {
     }
 
@@ -711,471 +712,6 @@ namespace gameplay
     {
         return _color;
     }
-
-    /****************
-     * Theme::Style *
-     ****************/
-    Theme::Style::Style(const char* id, float tw, float th,
-            const Theme::Margin& margin, const Theme::Padding& padding,
-            Theme::Style::Overlay* normal, Theme::Style::Overlay* focus, Theme::Style::Overlay* active, Theme::Style::Overlay* disabled)
-        : _id(id), _tw(tw), _th(th), _margin(margin), _padding(padding)
-    {
-        _overlays[OVERLAY_NORMAL] = normal;
-        _overlays[OVERLAY_FOCUS] = focus;
-        _overlays[OVERLAY_ACTIVE] = active;
-        _overlays[OVERLAY_DISABLED] = disabled;
-    }
-
-    Theme::Style::Style(const Style& copy)
-    {
-        _id = copy._id;
-        _margin = copy._margin;
-        _padding = copy._padding;
-        _tw = copy._tw;
-        _th = copy._th;
-
-        for (int i = 0; i < MAX_OVERLAYS; i++)
-        {
-            _overlays[i] = new Theme::Style::Overlay(*copy._overlays[i]);
-        }
-    }
-
-    Theme::Style::~Style()
-    {
-        for (unsigned int i = 0; i < MAX_OVERLAYS; i++)
-        {
-            SAFE_RELEASE(_overlays[i]);
-        }
-    }
-    
-    const char* Theme::Style::getId() const
-    {
-        return _id.data();
-    }
-
-    Theme::Style::Overlay* Theme::Style::getOverlay(OverlayType overlayType) const
-    {
-        return _overlays[overlayType];
-    }
-
-    void Theme::Style::setMargin(float top, float bottom, float left, float right)
-    {
-        _margin.top = top;
-        _margin.bottom = bottom;
-        _margin.left = left;
-        _margin.right = right;
-    }
-
-    const Theme::Margin& Theme::Style::getMargin() const
-    {
-        return _margin;
-    }
-
-    void Theme::Style::setPadding(float top, float bottom, float left, float right)
-    {
-        _padding.top = top;
-        _padding.bottom = bottom;
-        _padding.left = left;
-        _padding.right = right;
-    }
-
-    const Theme::Padding& Theme::Style::getPadding() const
-    {
-        return _padding;
-    }
-    
-    /*************************
-     * Theme::Style::Overlay *
-     *************************/
-    Theme::Style::Overlay* Theme::Style::Overlay::create()
-    {
-        Overlay* overlay = new Overlay();
-        return overlay;
-    }
-
-    Theme::Style::Overlay::Overlay() : _skin(NULL), _cursor(NULL), _imageList(NULL), _font(NULL)
-    {
-    }
-
-    Theme::Style::Overlay::Overlay(const Overlay& copy) : _skin(NULL), _cursor(NULL), _imageList(NULL), _font(NULL)
-    {
-        if (copy._skin)
-        {
-            _skin = new Skin(*copy._skin);
-        }
-        if (copy._cursor)
-        {
-            _cursor = new Image(*copy._cursor);
-        }
-        if (copy._imageList)
-        {
-            _imageList = new ImageList(*copy._imageList);
-        }
-
-        _font = copy._font;
-        _fontSize = copy._fontSize;
-        _alignment = copy._alignment;
-        _textRightToLeft = copy._textRightToLeft;
-        _textColor = Vector4(copy._textColor);
-        _opacity = copy._opacity;
-
-        if (_font)
-        {
-            _font->addRef();
-        }
-    }
-
-    Theme::Style::Overlay::~Overlay()
-    {
-        SAFE_RELEASE(_skin);
-        SAFE_RELEASE(_imageList);
-        SAFE_RELEASE(_cursor);
-        SAFE_RELEASE(_font);
-    }
-
-    float Theme::Style::Overlay::getOpacity() const
-    {
-        return _opacity;
-    }
-
-    void Theme::Style::Overlay::setOpacity(float opacity)
-    {
-        _opacity = opacity;
-    }
-
-    void Theme::Style::Overlay::setBorder(float top, float bottom, float left, float right)
-    {
-        if (_skin)
-        {
-            _skin->_border.top = top;
-            _skin->_border.bottom = bottom;
-            _skin->_border.left = left;
-            _skin->_border.right = right;
-        }
-    }
-
-    const Theme::Border& Theme::Style::Overlay::getBorder() const
-    {
-        if (_skin)
-        {
-            return _skin->getBorder();
-        }
-        else
-        {
-            return Theme::Border::empty();
-        }
-    }
-
-    void Theme::Style::Overlay::setSkinColor(const Vector4& color)
-    {
-        if (_skin)
-        {
-            _skin->_color.set(color);
-        }
-    }
-
-    const Vector4& Theme::Style::Overlay::getSkinColor() const
-    {
-        if (_skin)
-        {
-            return _skin->getColor();
-        }
-
-        return Vector4::one();
-    }
-
-    void Theme::Style::Overlay::setSkinRegion(const Rectangle& region, float tw, float th)
-    {
-        assert(_skin);
-        _skin->setRegion(region, tw, th);
-    }
-
-    const Rectangle& Theme::Style::Overlay::getSkinRegion() const
-    {
-        if (_skin)
-        {
-            return _skin->getRegion();
-        }
-
-        return Rectangle::empty();
-    }
-
-    const Theme::UVs& Theme::Style::Overlay::getSkinUVs(Theme::Skin::SkinArea area) const
-    {
-        if (_skin)
-        {
-            return _skin->_uvs[area];
-        }
-
-        return UVs::empty();
-    }
-
-    Font* Theme::Style::Overlay::getFont() const
-    {
-        return _font;
-    }
-
-    void Theme::Style::Overlay::setFont(Font* font)
-    {
-        if (_font != font)
-        {
-            SAFE_RELEASE(_font);
-
-            _font = font;
-
-            if (_font)
-            {
-                _font->addRef();
-            }
-        }
-    }
-
-    unsigned int Theme::Style::Overlay::getFontSize() const
-    {
-        return _fontSize;
-    }
-
-    void Theme::Style::Overlay::setFontSize(unsigned int fontSize)
-    {
-        _fontSize = fontSize;
-    }
-
-    Font::Justify Theme::Style::Overlay::getTextAlignment() const
-    {
-        return _alignment;
-    }
-
-    void Theme::Style::Overlay::setTextAlignment(Font::Justify alignment)
-    {
-        _alignment = alignment;
-    }
-
-    bool Theme::Style::Overlay::getTextRightToLeft() const
-    {
-        return _textRightToLeft;
-    }
-
-    void Theme::Style::Overlay::setTextRightToLeft(bool rightToLeft)
-    {
-        _textRightToLeft = rightToLeft;
-    }
-
-    const Vector4& Theme::Style::Overlay::getTextColor() const
-    {
-        return _textColor;
-    }
-
-    void Theme::Style::Overlay::setTextColor(const Vector4& color)
-    {
-        _textColor = color;
-    }
-
-    const Rectangle& Theme::Style::Overlay::getImageRegion(const char* id) const
-    {
-        Image* image = _imageList->getImage(id);
-        if (image)
-        {
-            return image->getRegion();
-        }
-        else
-        {
-            return Rectangle::empty();
-        }
-    }
-    
-    void Theme::Style::Overlay::setImageRegion(const char* id, const Rectangle& region, float tw, float th)
-    {
-        Image* image = _imageList->getImage(id);
-        assert(image);
-        image->_region.set(region);
-        generateUVs(tw, th, region.x, region.y, region.width, region.height, &(image->_uvs));
-    }
-
-    const Vector4& Theme::Style::Overlay::getImageColor(const char* id) const
-    {
-        Image* image = _imageList->getImage(id);
-        if (image)
-        {
-            return image->getColor();
-        }
-        else
-        {
-            return Vector4::zero();
-        }
-    }
-
-    void Theme::Style::Overlay::setImageColor(const char* id, const Vector4& color)
-    {
-        Image* image = _imageList->getImage(id);
-        assert(image);
-        image->_color.set(color);
-    }
-
-    const Theme::UVs& Theme::Style::Overlay::getImageUVs(const char* id) const
-    {
-        Image* image = _imageList->getImage(id);
-        if (image)
-        {
-            return image->getUVs();
-        }
-        else
-        {
-            return UVs::empty();
-        }
-    }
-
-    const Rectangle& Theme::Style::Overlay::getCursorRegion() const
-    {
-        if (_cursor)
-        {
-            return _cursor->getRegion();
-        }
-        else
-        {
-            return Rectangle::empty();
-        }
-    }
-    
-    void Theme::Style::Overlay::setCursorRegion(const Rectangle& region, float tw, float th)
-    {
-        assert(_cursor);
-        _cursor->_region.set(region);
-        generateUVs(tw, th, region.x, region.y, region.width, region.height, &(_cursor->_uvs));
-    }
-
-    const Vector4& Theme::Style::Overlay::getCursorColor() const
-    {
-        if (_cursor)
-        {
-            return _cursor->getColor();
-        }
-        else
-        {
-            return Vector4::zero();
-        }
-    }
-
-    void Theme::Style::Overlay::setCursorColor(const Vector4& color)
-    {
-        assert(_cursor);
-        _cursor->_color.set(color);
-    }
-
-    const Theme::UVs Theme::Style::Overlay::getCursorUVs() const
-    {
-        if (_cursor)
-        {
-            return _cursor->getUVs();
-        }
-        else
-        {
-            return UVs::empty();
-        }
-    }
-
-    void Theme::Style::Overlay::setSkin(Skin* skin)
-    {
-        if (_skin != skin)
-        {
-            SAFE_RELEASE(_skin);
-            _skin = skin;
-
-            if (skin)
-            {
-                skin->addRef();
-            }
-        }
-    }
-
-    Theme::Skin* Theme::Style::Overlay::getSkin() const
-    {
-        return _skin;
-    }
-
-    void Theme::Style::Overlay::setCursor(Image* cursor)
-    {
-        if (_cursor != cursor)
-        {
-            SAFE_RELEASE(_cursor);
-            _cursor = cursor;
-
-            if (cursor)
-            {
-                cursor->addRef();
-            }
-        }
-    }
-
-    Theme::Image* Theme::Style::Overlay::getCursor() const
-    {
-        return _cursor;
-    }
-            
-    void Theme::Style::Overlay::setImageList(ImageList* imageList)
-    {
-        if (_imageList != imageList)
-        {
-            SAFE_RELEASE(_imageList);
-            _imageList = imageList;
-
-            if (imageList)
-            {
-                imageList->addRef();
-            }
-        }
-    }
-    
-    Theme::ImageList* Theme::Style::Overlay::getImageList() const
-    {
-        return _imageList;
-    }
-
-    // Implementation of AnimationHandler
-    unsigned int Theme::Style::Overlay::getAnimationPropertyComponentCount(int propertyId) const
-    {
-        switch(propertyId)
-        {
-        case Theme::Style::Overlay::ANIMATE_OPACITY:
-            return 1;
-        default:
-            return -1;
-        }
-    }
-
-    void Theme::Style::Overlay::getAnimationPropertyValue(int propertyId, AnimationValue* value)
-    {
-        switch(propertyId)
-        {
-        case ANIMATE_OPACITY:
-            value->setFloat(0, _opacity);
-            break;
-        default:
-            break;
-        }
-    }
-
-    void Theme::Style::Overlay::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
-    {
-        switch(propertyId)
-        {
-            case ANIMATE_OPACITY:
-            {
-                float opacity = value->getFloat(0);
-                if ((_animationPropertyBitFlag & ANIMATION_OPACITY_BIT) != ANIMATION_OPACITY_BIT)
-                {
-                    _animationPropertyBitFlag |= ANIMATION_OPACITY_BIT;
-                }
-                else
-                {
-                    opacity = Curve::lerp(blendWeight, _opacity, opacity);
-                }
-                _opacity = opacity;
-                break;
-            }
-            default:
-                break;
-        }
-    }
     
     /**
      * Theme utility methods.

+ 158 - 315
gameplay/src/Theme.h

@@ -11,109 +11,122 @@
 namespace gameplay
 {
 
-static const unsigned int MAX_OVERLAYS = 4;
-static const unsigned int MAX_OVERLAY_REGIONS = 9;
-
 /**
  * A theme is created and stored as part of a form and represents its appearance.
  * Once loaded, the appearance properties can be retrieved from their style IDs and set on other
- * UI controls.  A Theme has one property, 'texture', which points to an image containing
- * all the Icon, Cursor, Slider, and Skin sprites used by the theme.  Each set of sprites within
- * the texture is described in its own namespace.  The rest of the Theme consists of Style namespaces.
- * A Style describes the border, margin, and padding of a Control, what icons and cursors (if any) are
- * associated with a Control, and Font properties to apply to a Control's text.
+ * UI controls.  A Theme has one property, 'texture', which points to a texture atlas containing
+ * all the images used by the theme.  Cursor images, skins, and lists of images used by controls
+ * are defined in their own namespaces.  The rest of the Theme consists of Style namespaces.
+ * A Style describes the border, margin, and padding of a Control, what images, skins, and cursors
+ * are associated with a Control, and Font properties to apply to a Control's text.
  *
  * Below is an explanation of the properties that can be set within themes:
  *
  * theme
  * {
- *    texture = <Path to texture>
- *
- *    // Describes the images used for CheckBox and RadioButton icons.
- *    icon <iconID>
- *    {
- *        size            =   <width, height>     // Size of this icon.
- *        offPosition     =   <x, y>              // Position of the unchecked / unselected image.
- *        onPosition      =   <x, y>              // Position of the checked / selected image.
- *        color           =   <#ffffffff>         // Tint to apply to icon.
- *    }
- *   
- *    cursor <cursorID>
- *    {
- *        region  =   <x, y, width, height>   // Region within the texture of cursor sprite.
- *        color   =   <#ffffffff>             // Tint to apply to cursor.
- *    }
- *   
- *    slider <sliderID>
- *    {
- *        minCapRegion    =   <x, y, width, height>   // Left / bottom slider cap.
- *        maxCapRegion    =   <x, y, width, height>   // Right / top slider cap.
- *        markerRegion    =   <x, y, width, height>   // Shows the slider's current position.
- *        trackRegion     =   <x, y, width, height>   // Track the marker slides along.
- *        color           =   <#ffffffff>             // Tint to apply to slider sprites.
- *    }
- *   
- *    // Defines the border and background of a Control.
- *    Skin <SkinID>
- *    {
- *        // The corners and edges of the given region will be used as border sprites.
- *        border
- *        {
- *            top     =   <int>   // Height of top border, top corners.
- *            bottom  =   <int>   // Height of bottom border, bottom corners.
- *            left    =   <int>   // Width of left border, left corners.
- *            right   =   <int>   // Width of right border, right corners.
- *        }
- *       
- *        region  =   <x, y, width, height>   // Total Skin region including entire border.
- *        color   =   <#ffffffff>             // Tint to apply to Skin sprites.
- *    }
- *   
- *    style <styleID>
- *    {
- *        // Layouts may make use of a style's margin to put space between adjacent controls.
- *        margin
- *        {
- *            top     =   <int>
- *            bottom  =   <int>
- *            left    =   <int>
- *            right   =   <int>        
- *        }
- *       
- *        // Padding is the space between a control's border and its content.
- *        padding
- *        {
- *            top     =   <int>
- *            bottom  =   <int>
- *            left    =   <int>
- *            right   =   <int>        
- *        }
- *       
- *        // This overlay is used when a control is enabled but not active or focused.
- *        normal
- *        {
- *            Skin   =   <SkinID>               // Skin to use for border and background sprites.
- *            checkBox    =   <iconID>                    // Icon to use for checkbox sprites.
- *            radioButton =   <iconID>                    // Icon to use for radioButton sprites.
- *            slider      =   <sliderID>                  // Slider to use for slider sprites.
- *            mouseCursor =   <cursorID>                  // Cursor to use when the mouse is over this control.
- *            textCursor  =   <cursorID>                  // Cursor to use within a textBox.
- *            font        =   <Path to font>              // Font to use for rendering text.
- *            fontSize    =   <int>                       // Size of text.
- *            textColor   =   <#ffffffff>                 // Color of text.
- *            alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
- *            rightToLeft =   <bool>                      // Whether to draw text from right to left.
- *        }
- *       
- *        // This overlay is used when the control is in focus.
- *        // If not specified, the 'normal' overlay will be used.
- *        focus{}
- *       
- *        // This overlay is used when the control is active.
- *        // (Touch or mouse is down within the control.)
- *        // If not specified, the 'normal' overlay will be used.
- *        active{}
- *    }
+ *     texture = <Path to texture>
+ * 
+ *     // Describes a single image, to be used as a cursor.
+ *     cursor <Cursor ID>
+ *     {
+ *         region = <x, y, width, height>
+ *         color = <#ffffffff>
+ *     }
+ * 
+ *     // Describes all the images used by a control for one or more states.
+ *     imageList <ImageList ID>
+ *     {
+ *         image checked
+ *         {
+ *             region = <x, y, width, height>
+ *         }
+ * 
+ *         image unchecked
+ *         {
+ *             region = <x, y, width, height>
+ *             color = <#fffffffff>            // Optionally override image-list color.
+ *         }
+ * 
+ *         color = <#fffffffff>    // Default blend color for images that don't specify their own.
+ *     }
+ *     
+ *     // Defines the border and background of a Control.
+ *     skin <Skin ID>
+ *     {
+ *         // The corners and edges of the given region will be used as border sprites.
+ *         border
+ *         {
+ *             top     =   <int>   // Height of top border, top corners.
+ *             bottom  =   <int>   // Height of bottom border, bottom corners.
+ *             left    =   <int>   // Width of left border, left corners.
+ *             right   =   <int>   // Width of right border, right corners.
+ *         }
+ *         
+ *         region  =   <x, y, width, height>   // Total container region including entire border.
+ *         color   =   <#ffffffff>             // Tint to apply to skin.
+ *     }
+ *     
+ *     style <Style ID>
+ *     {
+ *         // Layouts may make use of a style's margin to put space between adjacent controls.
+ *         margin
+ *         {
+ *             top     =   <int>
+ *             bottom  =   <int>
+ *             left    =   <int>
+ *             right   =   <int>        
+ *         }
+ *         
+ *         // Padding is the space between a control's border and its content.
+ *         padding
+ *         {
+ *             top     =   <int>
+ *             bottom  =   <int>
+ *             left    =   <int>
+ *             right   =   <int>        
+ *         }
+ *         
+ *         // Properties used when in control is in the normal state.
+ *         stateNormal
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             imageList = <ImageList ID>
+ * 
+ *             cursor      =   <Cursor ID>                 // Cursor to use when the mouse is over this control.
+ *             font        =   <Path to font>              // Font to use for rendering text.
+ *             fontSize    =   <int>                       // Size of text.
+ *             textColor   =   <#ffffffff>                 // Color of text.
+ *             alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
+ *             rightToLeft =   <bool>                      // Whether to draw text from right to left.
+ *             opacity     =   <float>                     // Opacity to apply to all text/border/icon colors.
+ *         }
+ *         
+ *         // Properties used when in control is in the focus state
+ *         // If not specified, the 'normal' overlay will be used.
+ *         stateFocus
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             ...
+ *         }
+ *         
+ *         // Properties used when in control is in the focus. 
+ *         // This is when a touch/mouse is down within the control.
+ *         // If not specified, the 'normal' overlay will be used.
+ *         stateActive
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             ...
+ *         }
+ * 
+ *         // Properties used when in control is in the focus. 
+ *         // This is when a touch/mouse is down within the control.
+ *         // If not specified, the 'normal' overlay will be used.
+ *         state-disabled
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             ...        
+ *         }
+ *     }
  * }
  *
  */
@@ -125,40 +138,23 @@ class Theme: public Ref
     friend class Skin;
 
 public:
-    class Style;
-    class Cursor;
-
-private:
-    /**
-     * Creates an instance of a Theme from a theme file.
-     *
-     * @param path Path to a theme file.
-     *
-     * @return A new Theme.
-     */
-    static Theme* create(const char* path);
 
     /**
-     * Returns style with the given name.
-     *
-     * @param id ID of the style (as specified in the Theme file).
+     * Class representing a set of themed attributes that can be
+     * assigned to a control.
      *
-     * @return Instance of the Style.
+     * Defined in "ThemeStyle.h"
      */
-    Theme::Style* getStyle(const char* id) const;
-
-    void setProjectionMatrix(const Matrix& matrix);
-
-    SpriteBatch* getSpriteBatch() const;
+    class Style;
+    friend class Style;
 
-public:
     /**
      * Struct representing the UV coordinates of a rectangular image.
      */
-    typedef class UVs
+    struct UVs
     {
-    public:
         UVs();
+
         UVs(float u1, float v1, float u2, float v2);
 
         static const UVs& empty();
@@ -167,15 +163,14 @@ public:
         float v1;
         float u2;
         float v2;
-    } UVs;
+    };
 
     /**
      * Struct representing margin, border, and padding areas by
      * the width or height of each side.
      */
-    typedef class SideRegions
+    typedef struct SideRegions
     {
-    public:
         SideRegions() : top(0), bottom(0), left(0), right(0) {}
 
         static const SideRegions& empty();
@@ -186,12 +181,20 @@ public:
         float right;
     } Margin, Border, Padding;
 
+private:
+
+    /**
+     * Class representing an image within the theme's texture atlas.
+     * An image has a region and a blend color in addition to an ID.
+     * UV coordinates are calculated from the region and can be retrieved.
+     */
     class Image : public Ref
     {
         friend class Theme;
         friend class Control;
 
     public:
+
         const char* getId() const;
 
         const UVs& getUVs() const;
@@ -201,7 +204,9 @@ public:
         const Vector4& getColor() const;
 
     private:
+
         Image(float tw, float th, const Rectangle& region, const Vector4& color);
+
         ~Image();
 
         static Image* create(float tw, float th, Properties* properties, const Vector4& defaultColor);
@@ -212,19 +217,28 @@ public:
         Vector4 _color;
     };
 
+    /**
+     * Class representing a collection of theme images.  An image list
+     * can be assigned to each overlay of a style, and controls
+     * using the style can then retrieve images by ID in order to draw themselves.
+     */
     class ImageList : public Ref
     {
         friend class Theme;
         friend class Control;
 
     public:
+
         const char* getId() const;
 
         Image* getImage(const char* imageId) const;
 
     private:
+
         ImageList(const Vector4& color);
+
         ImageList(const ImageList& copy);
+
         ~ImageList();
 
         static ImageList* create(float tw, float th, Properties* properties);
@@ -242,6 +256,7 @@ public:
         friend class Theme;
 
     public:
+
         enum SkinArea
         {
             TOP_LEFT, TOP, TOP_RIGHT,
@@ -280,8 +295,9 @@ public:
         const Vector4& getColor() const;
 
     private:
+
         Skin(float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color);
-        //Skin(const Skin& copy);
+        
         ~Skin();
 
         static Skin* create(const char* id, float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color);
@@ -290,217 +306,44 @@ public:
     
         std::string _id;
         Theme::Border _border;
-        UVs _uvs[MAX_OVERLAY_REGIONS];
+        UVs _uvs[9];
         Vector4 _color;
         Rectangle _region;
         float _tw, _th;
     };
-    
-    /**
-     * This class represents the appearance of a control.  A style can have padding and margin values,
-     * as well as overlays for each of the control's states.  Each overlay in turn can reference
-     * the above classes to determine the border, background, cursor, and icon settings to use for
-     * a particular state.
-     */
-    class Style
-    {
-        friend class Theme;
-        friend class Control;
-
-    public:
-        class Overlay;
-
-        enum OverlayType
-        {
-            OVERLAY_NORMAL,
-            OVERLAY_FOCUS,
-            OVERLAY_ACTIVE,
-            OVERLAY_DISABLED
-        };
-
-        /**
-         * Returns the Id of this Style.
-         */
-        const char* getId() const;
-
-        /**
-         * Gets an overlay from the overlay type.
-         */
-        Theme::Style::Overlay* getOverlay(OverlayType overlayType) const;
-
-        /**
-         * Gets the Padding region of this style.
-         */
-        const Theme::Padding& getPadding() const;
-
-        /**
-         * Gets the Margin region of this style.
-         */
-        const Theme::Margin& getMargin() const;
-
-        /**
-         * Set this size of this Style's padding.
-         *
-         * Padding is the space between a Control's content (all icons and text) and its border.
-         */
-        void setPadding(float top, float bottom, float left, float right);
-
-        /**
-         * Set the size of this Style's margin.
-         *
-         * The margin is used by Layouts other than AbsoluteLayout to put space between Controls.
-         */
-        void setMargin(float top, float bottom, float left, float right);
-       
-        /**
-         * This class represents a control's overlay for one of the 3 modes: normal, focussed or active.
-         */
-        class Overlay : public Ref, public AnimationTarget
-        {
-            friend class Theme;
-            friend class Style;
-
-        public:
-            /**
-             * Animate this overlay's opacity property.  Data = opacity
-             */
-            static const int ANIMATE_OPACITY = 1;
-
-           /**
-            * Returns the Overlay type.
-            */
-            OverlayType getType();
-
-            float getOpacity() const;
-            void setOpacity(float opacity);
-
-            // setBorder(const Theme::Border& border) ??
-            void setBorder(float top, float bottom, float left, float right);
-            const Border& getBorder() const;
-
-            void setSkinColor(const Vector4& color);
-            const Vector4& getSkinColor() const;
-
-            void setSkinRegion(const Rectangle& region, float tw, float th);
-            const Rectangle& getSkinRegion() const;
-
-            const Theme::UVs& getSkinUVs(Theme::Skin::SkinArea area) const;
-
-           /**
-            * Gets a font associated with this overlay.
-            */
-            Font* getFont() const;
-
-            void setFont(Font* font);
-
-            // Font size.
-            unsigned int getFontSize() const;
-            void setFontSize(unsigned int fontSize);
-
-            // Alignment.
-            Font::Justify getTextAlignment() const;
-            void setTextAlignment(Font::Justify alignment);
-            
-            // Text direction.
-            bool getTextRightToLeft() const;
-            void setTextRightToLeft(bool rightToLeft);
-
-            const Vector4& getTextColor() const;
-            void setTextColor(const Vector4& color); 
-
-            const Rectangle& getImageRegion(const char* id) const;
-            void setImageRegion(const char* id, const Rectangle& region, float tw, float th);
-
-            const Vector4& getImageColor(const char* id) const;
-            void setImageColor(const char* id, const Vector4& color);
-
-            const Theme::UVs& getImageUVs(const char* id) const;
-
-            const Rectangle& getCursorRegion() const;
-            void setCursorRegion(const Rectangle& region, float tw, float th);
-
-            const Vector4& getCursorColor() const;
-            void setCursorColor(const Vector4& color);
-
-            const Theme::UVs getCursorUVs() const;
-
-            /**
-             * @see AnimationTarget#getAnimationPropertyComponentCount
-             */
-            unsigned int getAnimationPropertyComponentCount(int propertyId) const;
-
-            /**
-             * @see AnimationTarget#getAnimationProperty
-             */
-            void getAnimationPropertyValue(int propertyId, AnimationValue* value);
-
-            /**
-             * @see AnimationTarget#setAnimationProperty
-             */
-            void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
-        
-        private:
-            Overlay();
-            Overlay(const Overlay& copy);
-            ~Overlay();
-
-            static Overlay* create();
-
-            void setSkin(Skin* Skin);
-            Skin* getSkin() const;
-
-            void setCursor(Image* cursor);
-            Image* getCursor() const;
-            
-            void setImageList(ImageList* imageList);
-            ImageList* getImageList() const;
-
-            static const char ANIMATION_OPACITY_BIT = 0x01;
-            void applyAnimationValueOpacity(float opacity, float blendWeight);
-
-            Skin* _skin;
-            Image* _cursor;
-            ImageList* _imageList;
-            Font* _font;
-            unsigned int _fontSize;
-            Font::Justify _alignment;
-            bool _textRightToLeft;
-            Vector4 _textColor;
-            float _opacity;
-        };
-
-    private:
-        Style(const char* id, float tw, float th,
-            const Theme::Margin& margin, const Theme::Padding& padding,
-            Theme::Style::Overlay* normal, Theme::Style::Overlay* focus, Theme::Style::Overlay* active, Theme::Style::Overlay* disabled);
-        Style(const Style& style);
-        ~Style();
-        
-        std::string _id;
-        Margin _margin;
-        Padding _padding;
-        Overlay* _overlays[MAX_OVERLAYS];
-        float _tw;
-        float _th;
-    };
 
-private:
     /**
      * Constructor.
      */
     Theme();
 
     /**
-     * Copy Constructor.
+     * Constructor.
      */
-    Theme(const Theme* theme);
+    Theme(const Theme& theme);
 
     /**
      * Destructor.
      */
     ~Theme();
 
+    /**
+     * Creates an instance of a Theme from a theme file.
+     *
+     * @param path Path to a theme file.
+     *
+     * @return A new Theme.
+     */
+    static Theme* create(const char* path);
+
+    Theme::Style* getStyle(const char* id) const;
+
+    void setProjectionMatrix(const Matrix& matrix);
+
+    SpriteBatch* getSpriteBatch() const;
+
     static void generateUVs(float tw, float th, float x, float y, float width, float height, UVs* uvs);
+
     void lookUpSprites(const Properties* overlaySpace, ImageList** imageList, Image** mouseCursor, Skin** skin);
 
     std::string _path;

+ 471 - 0
gameplay/src/ThemeStyle.cpp

@@ -0,0 +1,471 @@
+#include "ThemeStyle.h"
+
+namespace gameplay
+{
+
+/****************
+ * Theme::Style *
+ ****************/
+Theme::Style::Style(const char* id, float tw, float th,
+        const Theme::Margin& margin, const Theme::Padding& padding,
+        Theme::Style::Overlay* normal, Theme::Style::Overlay* focus, Theme::Style::Overlay* active, Theme::Style::Overlay* disabled)
+    : _id(id), _tw(tw), _th(th), _margin(margin), _padding(padding)
+{
+    _overlays[OVERLAY_NORMAL] = normal;
+    _overlays[OVERLAY_FOCUS] = focus;
+    _overlays[OVERLAY_ACTIVE] = active;
+    _overlays[OVERLAY_DISABLED] = disabled;
+}
+
+Theme::Style::Style(const Style& copy)
+{
+    _id = copy._id;
+    _margin = copy._margin;
+    _padding = copy._padding;
+    _tw = copy._tw;
+    _th = copy._th;
+
+    for (int i = 0; i < OVERLAY_MAX; i++)
+    {
+        _overlays[i] = new Theme::Style::Overlay(*copy._overlays[i]);
+    }
+}
+
+Theme::Style::~Style()
+{
+    for (unsigned int i = 0; i < OVERLAY_MAX; i++)
+    {
+        SAFE_RELEASE(_overlays[i]);
+    }
+}
+    
+const char* Theme::Style::getId() const
+{
+    return _id.data();
+}
+
+Theme::Style::Overlay* Theme::Style::getOverlay(OverlayType overlayType) const
+{
+    return _overlays[overlayType];
+}
+
+void Theme::Style::setMargin(float top, float bottom, float left, float right)
+{
+    _margin.top = top;
+    _margin.bottom = bottom;
+    _margin.left = left;
+    _margin.right = right;
+}
+
+const Theme::Margin& Theme::Style::getMargin() const
+{
+    return _margin;
+}
+
+void Theme::Style::setPadding(float top, float bottom, float left, float right)
+{
+    _padding.top = top;
+    _padding.bottom = bottom;
+    _padding.left = left;
+    _padding.right = right;
+}
+
+const Theme::Padding& Theme::Style::getPadding() const
+{
+    return _padding;
+}
+    
+/*************************
+    * Theme::Style::Overlay *
+    *************************/
+Theme::Style::Overlay* Theme::Style::Overlay::create()
+{
+    Overlay* overlay = new Overlay();
+    return overlay;
+}
+
+Theme::Style::Overlay::Overlay() : _skin(NULL), _cursor(NULL), _imageList(NULL), _font(NULL)
+{
+}
+
+Theme::Style::Overlay::Overlay(const Overlay& copy) : _skin(NULL), _cursor(NULL), _imageList(NULL), _font(NULL)
+{
+    if (copy._skin)
+    {
+        _skin = new Skin(*copy._skin);
+    }
+    if (copy._cursor)
+    {
+        _cursor = new Image(*copy._cursor);
+    }
+    if (copy._imageList)
+    {
+        _imageList = new ImageList(*copy._imageList);
+    }
+
+    _font = copy._font;
+    _fontSize = copy._fontSize;
+    _alignment = copy._alignment;
+    _textRightToLeft = copy._textRightToLeft;
+    _textColor = Vector4(copy._textColor);
+    _opacity = copy._opacity;
+
+    if (_font)
+    {
+        _font->addRef();
+    }
+}
+
+Theme::Style::Overlay::~Overlay()
+{
+    SAFE_RELEASE(_skin);
+    SAFE_RELEASE(_imageList);
+    SAFE_RELEASE(_cursor);
+    SAFE_RELEASE(_font);
+}
+
+float Theme::Style::Overlay::getOpacity() const
+{
+    return _opacity;
+}
+
+void Theme::Style::Overlay::setOpacity(float opacity)
+{
+    _opacity = opacity;
+}
+
+void Theme::Style::Overlay::setBorder(float top, float bottom, float left, float right)
+{
+    if (_skin)
+    {
+        _skin->_border.top = top;
+        _skin->_border.bottom = bottom;
+        _skin->_border.left = left;
+        _skin->_border.right = right;
+    }
+}
+
+const Theme::Border& Theme::Style::Overlay::getBorder() const
+{
+    if (_skin)
+    {
+        return _skin->getBorder();
+    }
+    else
+    {
+        return Theme::Border::empty();
+    }
+}
+
+void Theme::Style::Overlay::setSkinColor(const Vector4& color)
+{
+    if (_skin)
+    {
+        _skin->_color.set(color);
+    }
+}
+
+const Vector4& Theme::Style::Overlay::getSkinColor() const
+{
+    if (_skin)
+    {
+        return _skin->getColor();
+    }
+
+    return Vector4::one();
+}
+
+void Theme::Style::Overlay::setSkinRegion(const Rectangle& region, float tw, float th)
+{
+    assert(_skin);
+    _skin->setRegion(region, tw, th);
+}
+
+const Rectangle& Theme::Style::Overlay::getSkinRegion() const
+{
+    if (_skin)
+    {
+        return _skin->getRegion();
+    }
+
+    return Rectangle::empty();
+}
+
+const Theme::UVs& Theme::Style::Overlay::getSkinUVs(Theme::Skin::SkinArea area) const
+{
+    if (_skin)
+    {
+        return _skin->_uvs[area];
+    }
+
+    return UVs::empty();
+}
+
+Font* Theme::Style::Overlay::getFont() const
+{
+    return _font;
+}
+
+void Theme::Style::Overlay::setFont(Font* font)
+{
+    if (_font != font)
+    {
+        SAFE_RELEASE(_font);
+
+        _font = font;
+
+        if (_font)
+        {
+            _font->addRef();
+        }
+    }
+}
+
+unsigned int Theme::Style::Overlay::getFontSize() const
+{
+    return _fontSize;
+}
+
+void Theme::Style::Overlay::setFontSize(unsigned int fontSize)
+{
+    _fontSize = fontSize;
+}
+
+Font::Justify Theme::Style::Overlay::getTextAlignment() const
+{
+    return _alignment;
+}
+
+void Theme::Style::Overlay::setTextAlignment(Font::Justify alignment)
+{
+    _alignment = alignment;
+}
+
+bool Theme::Style::Overlay::getTextRightToLeft() const
+{
+    return _textRightToLeft;
+}
+
+void Theme::Style::Overlay::setTextRightToLeft(bool rightToLeft)
+{
+    _textRightToLeft = rightToLeft;
+}
+
+const Vector4& Theme::Style::Overlay::getTextColor() const
+{
+    return _textColor;
+}
+
+void Theme::Style::Overlay::setTextColor(const Vector4& color)
+{
+    _textColor = color;
+}
+
+const Rectangle& Theme::Style::Overlay::getImageRegion(const char* id) const
+{
+    Image* image = _imageList->getImage(id);
+    if (image)
+    {
+        return image->getRegion();
+    }
+    else
+    {
+        return Rectangle::empty();
+    }
+}
+    
+void Theme::Style::Overlay::setImageRegion(const char* id, const Rectangle& region, float tw, float th)
+{
+    Image* image = _imageList->getImage(id);
+    assert(image);
+    image->_region.set(region);
+    generateUVs(tw, th, region.x, region.y, region.width, region.height, &(image->_uvs));
+}
+
+const Vector4& Theme::Style::Overlay::getImageColor(const char* id) const
+{
+    Image* image = _imageList->getImage(id);
+    if (image)
+    {
+        return image->getColor();
+    }
+    else
+    {
+        return Vector4::zero();
+    }
+}
+
+void Theme::Style::Overlay::setImageColor(const char* id, const Vector4& color)
+{
+    Image* image = _imageList->getImage(id);
+    assert(image);
+    image->_color.set(color);
+}
+
+const Theme::UVs& Theme::Style::Overlay::getImageUVs(const char* id) const
+{
+    Image* image = _imageList->getImage(id);
+    if (image)
+    {
+        return image->getUVs();
+    }
+    else
+    {
+        return UVs::empty();
+    }
+}
+
+const Rectangle& Theme::Style::Overlay::getCursorRegion() const
+{
+    if (_cursor)
+    {
+        return _cursor->getRegion();
+    }
+    else
+    {
+        return Rectangle::empty();
+    }
+}
+    
+void Theme::Style::Overlay::setCursorRegion(const Rectangle& region, float tw, float th)
+{
+    assert(_cursor);
+    _cursor->_region.set(region);
+    generateUVs(tw, th, region.x, region.y, region.width, region.height, &(_cursor->_uvs));
+}
+
+const Vector4& Theme::Style::Overlay::getCursorColor() const
+{
+    if (_cursor)
+    {
+        return _cursor->getColor();
+    }
+    else
+    {
+        return Vector4::zero();
+    }
+}
+
+void Theme::Style::Overlay::setCursorColor(const Vector4& color)
+{
+    assert(_cursor);
+    _cursor->_color.set(color);
+}
+
+const Theme::UVs& Theme::Style::Overlay::getCursorUVs() const
+{
+    if (_cursor)
+    {
+        return _cursor->getUVs();
+    }
+    else
+    {
+        return UVs::empty();
+    }
+}
+
+void Theme::Style::Overlay::setSkin(Skin* skin)
+{
+    if (_skin != skin)
+    {
+        SAFE_RELEASE(_skin);
+        _skin = skin;
+
+        if (skin)
+        {
+            skin->addRef();
+        }
+    }
+}
+
+Theme::Skin* Theme::Style::Overlay::getSkin() const
+{
+    return _skin;
+}
+
+void Theme::Style::Overlay::setCursor(Image* cursor)
+{
+    if (_cursor != cursor)
+    {
+        SAFE_RELEASE(_cursor);
+        _cursor = cursor;
+
+        if (cursor)
+        {
+            cursor->addRef();
+        }
+    }
+}
+
+Theme::Image* Theme::Style::Overlay::getCursor() const
+{
+    return _cursor;
+}
+            
+void Theme::Style::Overlay::setImageList(ImageList* imageList)
+{
+    if (_imageList != imageList)
+    {
+        SAFE_RELEASE(_imageList);
+        _imageList = imageList;
+
+        if (imageList)
+        {
+            imageList->addRef();
+        }
+    }
+}
+    
+Theme::ImageList* Theme::Style::Overlay::getImageList() const
+{
+    return _imageList;
+}
+
+// Implementation of AnimationHandler
+unsigned int Theme::Style::Overlay::getAnimationPropertyComponentCount(int propertyId) const
+{
+    switch(propertyId)
+    {
+    case Theme::Style::Overlay::ANIMATE_OPACITY:
+        return 1;
+    default:
+        return -1;
+    }
+}
+
+void Theme::Style::Overlay::getAnimationPropertyValue(int propertyId, AnimationValue* value)
+{
+    switch(propertyId)
+    {
+    case ANIMATE_OPACITY:
+        value->setFloat(0, _opacity);
+        break;
+    default:
+        break;
+    }
+}
+
+void Theme::Style::Overlay::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
+{
+    switch(propertyId)
+    {
+        case ANIMATE_OPACITY:
+        {
+            float opacity = value->getFloat(0);
+            if ((_animationPropertyBitFlag & ANIMATION_OPACITY_BIT) != ANIMATION_OPACITY_BIT)
+            {
+                _animationPropertyBitFlag |= ANIMATION_OPACITY_BIT;
+            }
+            else
+            {
+                opacity = Curve::lerp(blendWeight, _opacity, opacity);
+            }
+            _opacity = opacity;
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+}

+ 223 - 0
gameplay/src/ThemeStyle.h

@@ -0,0 +1,223 @@
+#ifndef THEMESTYLE_H_
+#define THEMESTYLE_H_
+
+#include "Base.h"
+#include "Ref.h"
+#include "Font.h"
+#include "Rectangle.h"
+#include "Texture.h"
+#include "Properties.h"
+#include "Theme.h"
+
+namespace gameplay
+{
+
+/**
+ * This class represents the appearance of a control.  A style can have padding and margin values,
+ * as well as overlays for each of the control's states.  Each overlay in turn can reference
+ * other theme classes to determine the border, background, cursor, and image settings to use for
+ * a particular state, as well as color and font settings, etcetera.
+ */
+class Theme::Style
+{
+    friend class Theme;
+    friend class Control;
+
+private:
+
+    /**
+     * A style has one overlay for each possible control state.
+     */
+    enum OverlayType
+    {
+        OVERLAY_NORMAL,
+        OVERLAY_FOCUS,
+        OVERLAY_ACTIVE,
+        OVERLAY_DISABLED,
+        OVERLAY_MAX
+    };
+
+    /**
+     * This class represents a control's overlay for one of its states.
+     */
+    class Overlay : public Ref, public AnimationTarget
+    {
+        friend class Theme;
+        friend class Theme::Style;
+        friend class Control;
+
+    private:
+
+        static const int ANIMATE_OPACITY = 1;
+        static const char ANIMATION_OPACITY_BIT = 0x01;
+
+        Overlay();
+            
+        Overlay(const Overlay& copy);
+            
+        ~Overlay();
+
+        static Overlay* create();
+
+        OverlayType getType();
+
+        float getOpacity() const;
+
+        void setOpacity(float opacity);
+
+        void setBorder(float top, float bottom, float left, float right);
+
+        const Theme::Border& getBorder() const;
+
+        void setSkinColor(const Vector4& color);
+
+        const Vector4& getSkinColor() const;
+
+        void setSkinRegion(const Rectangle& region, float tw, float th);
+
+        const Rectangle& getSkinRegion() const;
+
+        const Theme::UVs& getSkinUVs(Theme::Skin::SkinArea area) const;
+
+        Font* getFont() const;
+
+        void setFont(Font* font);
+
+        unsigned int getFontSize() const;
+
+        void setFontSize(unsigned int fontSize);
+
+        Font::Justify getTextAlignment() const;
+
+        void setTextAlignment(Font::Justify alignment);
+            
+        bool getTextRightToLeft() const;
+
+        void setTextRightToLeft(bool rightToLeft);
+
+        const Vector4& getTextColor() const;
+
+        void setTextColor(const Vector4& color); 
+
+        const Rectangle& getImageRegion(const char* id) const;
+
+        void setImageRegion(const char* id, const Rectangle& region, float tw, float th);
+
+        const Vector4& getImageColor(const char* id) const;
+
+        void setImageColor(const char* id, const Vector4& color);
+
+        const Theme::UVs& getImageUVs(const char* id) const;
+
+        const Rectangle& getCursorRegion() const;
+
+        void setCursorRegion(const Rectangle& region, float tw, float th);
+
+        const Vector4& getCursorColor() const;
+
+        void setCursorColor(const Vector4& color);
+
+        const Theme::UVs& getCursorUVs() const;
+
+        /**
+         * @see AnimationTarget#getAnimationPropertyComponentCount
+         */
+        unsigned int getAnimationPropertyComponentCount(int propertyId) const;
+
+        /**
+         * @see AnimationTarget#getAnimationProperty
+         */
+        void getAnimationPropertyValue(int propertyId, AnimationValue* value);
+
+        /**
+         * @see AnimationTarget#setAnimationProperty
+         */
+        void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
+       
+        void setSkin(Theme::Skin* Skin);
+
+        Theme::Skin* getSkin() const;
+
+        void setCursor(Theme::Image* cursor);
+            
+        Theme::Image* getCursor() const;
+            
+        void setImageList(Theme::ImageList* imageList);
+            
+        Theme::ImageList* getImageList() const;
+
+        void applyAnimationValueOpacity(float opacity, float blendWeight);
+
+        Skin* _skin;
+        Theme::Image* _cursor;
+        Theme::ImageList* _imageList;
+        Font* _font;
+        unsigned int _fontSize;
+        Font::Justify _alignment;
+        bool _textRightToLeft;
+        Vector4 _textColor;
+        float _opacity;
+    };
+
+    /**
+     * Constructor.
+     */
+    Style(const char* id, float tw, float th,
+          const Theme::Margin& margin, const Theme::Padding& padding,
+          Overlay* normal, Overlay* focus, Overlay* active, Overlay* disabled);
+
+    /**
+     * Constructor.
+     */
+    Style(const Style& style);
+
+    /**
+     * Destructor.
+     */
+    ~Style();
+
+    /**
+     * Returns the Id of this Style.
+     */
+    const char* getId() const;
+
+    /**
+     * Gets an overlay from the overlay type.
+     */
+    Overlay* getOverlay(OverlayType overlayType) const;
+
+    /**
+     * Gets the Padding region of this style.
+     */
+    const Theme::Padding& getPadding() const;
+
+    /**
+     * Gets the Margin region of this style.
+     */
+    const Theme::Margin& getMargin() const;
+
+    /**
+     * Set this size of this Style's padding.
+     *
+     * Padding is the space between a Control's content (all icons and text) and its border.
+     */
+    void setPadding(float top, float bottom, float left, float right);
+
+    /**
+     * Set the size of this Style's margin.
+     *
+     * The margin is used by Layouts other than AbsoluteLayout to put space between Controls.
+     */
+    void setMargin(float top, float bottom, float left, float right);
+        
+    std::string _id;
+    float _tw;
+    float _th;
+    Theme::Margin _margin;
+    Theme::Padding _padding;
+    Overlay* _overlays[OVERLAY_MAX];
+};
+
+}
+
+#endif

+ 6 - 12
gameplay/src/VerticalLayout.cpp

@@ -44,16 +44,10 @@ namespace gameplay
     void VerticalLayout::update(const Container* container)
     {
         // Need border, padding.
-        Theme::Style* style = container->getStyle();
+        //Theme::Style* style = container->getStyle();
         Theme::Border border = container->getBorder(container->getState());
-        /*
-        Theme::Skin* skin = style->getOverlay(container->getOverlayType())->getSkin();
-        if (skin)
-        {
-            border = skin->getBorder();
-        }
-        */
-        Theme::Padding padding = style->getPadding();
+        //Theme::Padding padding = style->getPadding();
+        Theme::Padding padding = container->getPadding();
 
         float yPosition = 0;
 
@@ -77,12 +71,12 @@ namespace gameplay
         {
             Control* control = controls.at(i);
 
-            const Rectangle& bounds = control->getBounds();
-            const Theme::Margin& margin = control->getStyle()->getMargin();
+            const Rectangle& bounds = control->getClipBounds();
+            const Theme::Margin& margin = control->getMargin();
 
             yPosition += margin.top;
 
-            control->setPosition(0, yPosition, 0L);
+            control->setPosition(0, yPosition);
             if (control->isDirty())
             {
                 control->update(container->getClip());

+ 23 - 0
gameplay/src/VerticalLayout.h

@@ -17,6 +17,7 @@ class VerticalLayout : public Layout
     friend class Container;
 
 public:
+
     /**
      * Set whether this layout will start laying out controls from the bottom of the container.
      * This setting defaults to 'false', meaning controls will start at the top.
@@ -40,16 +41,38 @@ public:
     Layout::Type getType();
 
 protected:
+
+    /**
+     * Constructor.
+     */
     VerticalLayout();
+
+    /**
+     * Destructor.
+     */
     virtual ~VerticalLayout();
 
+    /**
+     * Create a VerticalLayout.
+     *
+     * @return a VerticalLayout object.
+     */
     static VerticalLayout* create();
 
+    /**
+     * Update the controls contained by the specified container.
+     *
+     * Controls are placed next to one another vertically until
+     * the bottom-most edge of the container is reached.
+     *
+     * @param container The container to update.
+     */
     void update(const Container* container);
 
     bool _bottomToTop;
 
 private:
+
     VerticalLayout(const VerticalLayout& copy);
 };
 

+ 3 - 0
gameplay/src/gameplay.h

@@ -7,6 +7,7 @@
 #include "Mouse.h"
 #include "FileSystem.h"
 #include "Package.h"
+#include "ScreenDisplayer.h"
 
 // Math
 #include "Rectangle.h"
@@ -69,6 +70,8 @@
 #include "PhysicsCollisionObject.h"
 #include "PhysicsRigidBody.h"
 #include "PhysicsCharacter.h"
+#include "PhysicsCollisionShape.h"
+#include "PhysicsGhostObject.h"
 
 // UI
 #include "Theme.h"