Răsfoiți Sursa

Merge pull request #56 from blackberry-gaming/next

Next
Sean Paul Taylor 13 ani în urmă
părinte
comite
671fb27f22
43 a modificat fișierele cu 3138 adăugiri și 1147 ștergeri
  1. 3 2
      gameplay-encoder/gameplay-encoder.vcxproj
  2. 9 6
      gameplay-encoder/gameplay-encoder.vcxproj.filters
  3. 10 14
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  4. 1346 0
      gameplay-encoder/src/Curve.cpp
  5. 484 0
      gameplay-encoder/src/Curve.h
  6. 36 0
      gameplay-encoder/src/Curve.inl
  7. 3 0
      gameplay-encoder/src/FileIO.h
  8. 1 1
      gameplay-encoder/src/MeshSkin.cpp
  9. 2 2
      gameplay-encoder/src/Reference.h
  10. 3 0
      gameplay/gameplay.vcxproj
  11. 9 0
      gameplay/gameplay.vcxproj.filters
  12. 18 0
      gameplay/gameplay.xcodeproj/project.pbxproj
  13. 9 29
      gameplay/src/Animation.cpp
  14. 1 21
      gameplay/src/Animation.h
  15. 5 2
      gameplay/src/Button.h
  16. 7 7
      gameplay/src/CheckBox.cpp
  17. 2 2
      gameplay/src/CheckBox.h
  18. 1 1
      gameplay/src/Container.cpp
  19. 9 4
      gameplay/src/Container.h
  20. 101 133
      gameplay/src/Control.cpp
  21. 93 41
      gameplay/src/Control.h
  22. 5 0
      gameplay/src/Curve.cpp
  23. 25 11
      gameplay/src/Curve.h
  24. 8 9
      gameplay/src/Form.cpp
  25. 3 3
      gameplay/src/Game.cpp
  26. 3 46
      gameplay/src/Game.h
  27. 0 14
      gameplay/src/Game.inl
  28. 4 7
      gameplay/src/Label.cpp
  29. 1 1
      gameplay/src/Node.cpp
  30. 24 20
      gameplay/src/PhysicsCharacter.cpp
  31. 3 1
      gameplay/src/PhysicsCharacter.h
  32. 3 4
      gameplay/src/PlatformMacOS.mm
  33. 13 7
      gameplay/src/RadioButton.cpp
  34. 1 1
      gameplay/src/RadioButton.h
  35. 69 0
      gameplay/src/ScreenDisplayer.h
  36. 14 14
      gameplay/src/Slider.cpp
  37. 52 42
      gameplay/src/TextBox.cpp
  38. 2 466
      gameplay/src/Theme.cpp
  39. 51 224
      gameplay/src/Theme.h
  40. 471 0
      gameplay/src/ThemeStyle.cpp
  41. 225 0
      gameplay/src/ThemeStyle.h
  42. 6 12
      gameplay/src/VerticalLayout.cpp
  43. 3 0
      gameplay/src/gameplay.h

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

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

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

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

+ 10 - 14
gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj

@@ -8,9 +8,9 @@
 
 
 /* Begin PBXBuildFile section */
 /* Begin PBXBuildFile section */
 		42475D7C14720ECE00610A6A /* libdom.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42475D7B14720ECE00610A6A /* libdom.a */; };
 		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 */; };
 		42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4278341E148D6F7500A6E27F /* FBXSceneEncoder.cpp */; };
 		4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4283905714896E6C00E2B2F5 /* BoundingVolume.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 */; };
 		42C8EE0A14724CD700E43619 /* Animation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB714724CD700E43619 /* Animation.cpp */; };
 		42C8EE0B14724CD700E43619 /* AnimationChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB914724CD700E43619 /* AnimationChannel.cpp */; };
 		42C8EE0B14724CD700E43619 /* AnimationChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDB914724CD700E43619 /* AnimationChannel.cpp */; };
 		42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBB14724CD700E43619 /* Animations.cpp */; };
 		42C8EE0C14724CD700E43619 /* Animations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C8EDBB14724CD700E43619 /* Animations.cpp */; };
@@ -75,6 +75,10 @@
 /* Begin PBXFileReference section */
 /* Begin PBXFileReference section */
 		42475CE6147208A000610A6A /* gameplay-encoder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gameplay-encoder"; sourceTree = BUILT_PRODUCTS_DIR; };
 		42475CE6147208A000610A6A /* gameplay-encoder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gameplay-encoder"; sourceTree = BUILT_PRODUCTS_DIR; };
 		42475D7B14720ECE00610A6A /* libdom.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdom.a; path = "../external-deps/collada-dom/lib/macos/libdom.a"; sourceTree = "<group>"; };
 		42475D7B14720ECE00610A6A /* libdom.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdom.a; path = "../external-deps/collada-dom/lib/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; };
 		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; };
 		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; };
 		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; };
 		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; };
 		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; };
 		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; };
 		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; };
 		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; };
 		42C8EDB914724CD700E43619 /* AnimationChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnimationChannel.cpp; path = src/AnimationChannel.cpp; sourceTree = SOURCE_ROOT; };
@@ -194,7 +196,6 @@
 		42475CDB147208A000610A6A = {
 		42475CDB147208A000610A6A = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				4283906414896F3000E2B2F5 /* gameplay */,
 				42475CE9147208A000610A6A /* src */,
 				42475CE9147208A000610A6A /* src */,
 				427D4F44147DC9080076760E /* Libraries */,
 				427D4F44147DC9080076760E /* Libraries */,
 				42475CE7147208A000610A6A /* Products */,
 				42475CE7147208A000610A6A /* Products */,
@@ -224,6 +225,9 @@
 				4283905814896E6C00E2B2F5 /* BoundingVolume.h */,
 				4283905814896E6C00E2B2F5 /* BoundingVolume.h */,
 				42C8EDBF14724CD700E43619 /* Camera.cpp */,
 				42C8EDBF14724CD700E43619 /* Camera.cpp */,
 				42C8EDC014724CD700E43619 /* Camera.h */,
 				42C8EDC014724CD700E43619 /* Camera.h */,
+				4251B128152D044B002F6199 /* Curve.cpp */,
+				4251B129152D044B002F6199 /* Curve.h */,
+				4251B12A152D044B002F6199 /* Curve.inl */,
 				42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */,
 				42C8EDC314724CD700E43619 /* DAEChannelTarget.cpp */,
 				42C8EDC414724CD700E43619 /* DAEChannelTarget.h */,
 				42C8EDC414724CD700E43619 /* DAEChannelTarget.h */,
 				42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */,
 				42C8EDC514724CD700E43619 /* DAEOptimizer.cpp */,
@@ -273,6 +277,7 @@
 				42C8EDF114724CD700E43619 /* Object.h */,
 				42C8EDF114724CD700E43619 /* Object.h */,
 				42C8EDF214724CD700E43619 /* Quaternion.cpp */,
 				42C8EDF214724CD700E43619 /* Quaternion.cpp */,
 				42C8EDF314724CD700E43619 /* Quaternion.h */,
 				42C8EDF314724CD700E43619 /* Quaternion.h */,
+				4251B12B152D044B002F6199 /* Quaternion.inl */,
 				42C8EDF414724CD700E43619 /* Reference.cpp */,
 				42C8EDF414724CD700E43619 /* Reference.cpp */,
 				42C8EDF514724CD700E43619 /* Reference.h */,
 				42C8EDF514724CD700E43619 /* Reference.h */,
 				42C8EDF614724CD700E43619 /* ReferenceTable.cpp */,
 				42C8EDF614724CD700E43619 /* ReferenceTable.cpp */,
@@ -318,15 +323,6 @@
 			name = Libraries;
 			name = Libraries;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
-		4283906414896F3000E2B2F5 /* gameplay */ = {
-			isa = PBXGroup;
-			children = (
-				4283906114896F1600E2B2F5 /* Curve.cpp */,
-				4283906214896F1600E2B2F5 /* Curve.h */,
-			);
-			name = gameplay;
-			sourceTree = "<group>";
-		};
 /* End PBXGroup section */
 /* End PBXGroup section */
 
 
 /* Begin PBXNativeTarget section */
 /* Begin PBXNativeTarget section */
@@ -418,8 +414,8 @@
 				42C8EE3214724CD700E43619 /* Vertex.cpp in Sources */,
 				42C8EE3214724CD700E43619 /* Vertex.cpp in Sources */,
 				42C8EE3314724CD700E43619 /* VertexElement.cpp in Sources */,
 				42C8EE3314724CD700E43619 /* VertexElement.cpp in Sources */,
 				4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */,
 				4283905914896E6C00E2B2F5 /* BoundingVolume.cpp in Sources */,
-				4283906314896F1600E2B2F5 /* Curve.cpp in Sources */,
 				42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */,
 				42783423148D6F7500A6E27F /* FBXSceneEncoder.cpp in Sources */,
+				4251B12C152D044B002F6199 /* Curve.cpp in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

+ 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;
+}
+
+}

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

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

+ 1 - 1
gameplay-encoder/src/MeshSkin.cpp

@@ -6,7 +6,7 @@
 #include "GPBFile.h"
 #include "GPBFile.h"
 #include "Animations.h"
 #include "Animations.h"
 #include "Transform.h"
 #include "Transform.h"
-#include "../../gameplay/src/Curve.h"
+#include "Curve.h"
 #include "Matrix.h"
 #include "Matrix.h"
 
 
 namespace gameplay
 namespace gameplay

+ 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"
 #include "Object.h"
 
 

+ 3 - 0
gameplay/gameplay.vcxproj

@@ -94,6 +94,7 @@
     <ClCompile Include="src\TextBox.cpp" />
     <ClCompile Include="src\TextBox.cpp" />
     <ClCompile Include="src\Texture.cpp" />
     <ClCompile Include="src\Texture.cpp" />
     <ClCompile Include="src\Theme.cpp" />
     <ClCompile Include="src\Theme.cpp" />
+    <ClCompile Include="src\ThemeStyle.cpp" />
     <ClCompile Include="src\Transform.cpp" />
     <ClCompile Include="src\Transform.cpp" />
     <ClCompile Include="src\Vector2.cpp" />
     <ClCompile Include="src\Vector2.cpp" />
     <ClCompile Include="src\Vector3.cpp" />
     <ClCompile Include="src\Vector3.cpp" />
@@ -176,12 +177,14 @@
     <ClInclude Include="src\RenderTarget.h" />
     <ClInclude Include="src\RenderTarget.h" />
     <ClInclude Include="src\Scene.h" />
     <ClInclude Include="src\Scene.h" />
     <ClInclude Include="src\SceneLoader.h" />
     <ClInclude Include="src\SceneLoader.h" />
+    <ClInclude Include="src\ScreenDisplayer.h" />
     <ClInclude Include="src\Slider.h" />
     <ClInclude Include="src\Slider.h" />
     <ClInclude Include="src\SpriteBatch.h" />
     <ClInclude Include="src\SpriteBatch.h" />
     <ClInclude Include="src\Technique.h" />
     <ClInclude Include="src\Technique.h" />
     <ClInclude Include="src\TextBox.h" />
     <ClInclude Include="src\TextBox.h" />
     <ClInclude Include="src\Texture.h" />
     <ClInclude Include="src\Texture.h" />
     <ClInclude Include="src\Theme.h" />
     <ClInclude Include="src\Theme.h" />
+    <ClInclude Include="src\ThemeStyle.h" />
     <ClInclude Include="src\TimeListener.h" />
     <ClInclude Include="src\TimeListener.h" />
     <ClInclude Include="src\Touch.h" />
     <ClInclude Include="src\Touch.h" />
     <ClInclude Include="src\Transform.h" />
     <ClInclude Include="src\Transform.h" />

+ 9 - 0
gameplay/gameplay.vcxproj.filters

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

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

@@ -14,6 +14,12 @@
 		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
 		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
 		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
 		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
 		4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4234D99D14686C52003031B3 /* Cocoa.framework */; };
 		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 */; };
 		42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42554E9F152BC35C000ED910 /* PhysicsCollisionShape.cpp */; };
 		42554EA2152BC35C000ED910 /* 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 */; };
 		42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 42554EA0152BC35C000ED910 /* PhysicsCollisionShape.h */; };
@@ -387,6 +393,9 @@
 		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.h; sourceTree = SOURCE_ROOT; };
 		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.h; sourceTree = SOURCE_ROOT; };
 		4234D99A14686C52003031B3 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4234D99A14686C52003031B3 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4234D99D14686C52003031B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		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; };
 		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; };
 		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; };
 		428390971489D6E800E2B2F5 /* SceneLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SceneLoader.cpp; path = src/SceneLoader.cpp; sourceTree = SOURCE_ROOT; };
@@ -839,6 +848,7 @@
 				42CD0E2E147D8FF50000361E /* Scene.h */,
 				42CD0E2E147D8FF50000361E /* Scene.h */,
 				428390971489D6E800E2B2F5 /* SceneLoader.cpp */,
 				428390971489D6E800E2B2F5 /* SceneLoader.cpp */,
 				428390981489D6E800E2B2F5 /* SceneLoader.h */,
 				428390981489D6E800E2B2F5 /* SceneLoader.h */,
+				4251B12E152D049B002F6199 /* ScreenDisplayer.h */,
 				5BD52646150F822A004C9099 /* Slider.cpp */,
 				5BD52646150F822A004C9099 /* Slider.cpp */,
 				5BD52647150F822A004C9099 /* Slider.h */,
 				5BD52647150F822A004C9099 /* Slider.h */,
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
@@ -852,6 +862,8 @@
 				5BD5264C150F822A004C9099 /* TimeListener.h */,
 				5BD5264C150F822A004C9099 /* TimeListener.h */,
 				5BD5264A150F822A004C9099 /* Theme.cpp */,
 				5BD5264A150F822A004C9099 /* Theme.cpp */,
 				5BD5264B150F822A004C9099 /* Theme.h */,
 				5BD5264B150F822A004C9099 /* Theme.h */,
+				4251B12F152D049B002F6199 /* ThemeStyle.cpp */,
+				4251B130152D049B002F6199 /* ThemeStyle.h */,
 				4208DEED14A407D500D3C511 /* Touch.h */,
 				4208DEED14A407D500D3C511 /* Touch.h */,
 				42CD0E35147D8FF50000361E /* Transform.cpp */,
 				42CD0E35147D8FF50000361E /* Transform.cpp */,
 				42CD0E36147D8FF50000361E /* Transform.h */,
 				42CD0E36147D8FF50000361E /* Transform.h */,
@@ -1044,6 +1056,8 @@
 				5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
 				5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
 				5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */,
 				5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */,
 				42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
 				42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
+				4251B131152D049B002F6199 /* ScreenDisplayer.h in Headers */,
+				4251B135152D049B002F6199 /* ThemeStyle.h in Headers */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -1139,6 +1153,8 @@
 				5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */,
 				5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */,
 				5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */,
 				5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */,
 				42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
 				42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
+				4251B132152D049B002F6199 /* ScreenDisplayer.h in Headers */,
+				4251B136152D049B002F6199 /* ThemeStyle.h in Headers */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -1292,6 +1308,7 @@
 				5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
 				5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
 				5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 				5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 				42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 				42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
+				4251B133152D049B002F6199 /* ThemeStyle.cpp in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -1381,6 +1398,7 @@
 				5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */,
 				5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */,
 				5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 				5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 				42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 				42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
+				4251B134152D049B002F6199 /* ThemeStyle.cpp in Sources */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

+ 9 - 29
gameplay/src/Animation.cpp

@@ -59,9 +59,9 @@ Animation::~Animation()
 }
 }
 
 
 Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
 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);
+    _curve->addRef();
     // get property component count, and ensure the property exists on the AnimationTarget by getting the property component count.
     // get property component count, and ensure the property exists on the AnimationTarget by getting the property component count.
     assert(_target->getAnimationPropertyComponentCount(propertyId));
     assert(_target->getAnimationPropertyComponentCount(propertyId));
 
 
@@ -71,46 +71,24 @@ Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int p
 }
 }
 
 
 Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
 Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
-    : _animation(animation), _target(target), _propertyId(copy._propertyId), _duration(copy._duration)
+    : _animation(animation), _target(target), _propertyId(copy._propertyId), _curve(copy._curve), _duration(copy._duration)
 {
 {
-    _curveRef = copy._curveRef;
-    _curveRef->addRef();
-
+    _curve->addRef();
     _animation->addRef();
     _animation->addRef();
     _target->addChannel(this);
     _target->addChannel(this);
 }
 }
 
 
 Animation::Channel::~Channel()
 Animation::Channel::~Channel()
 {
 {
-    SAFE_RELEASE(_curveRef);
+    SAFE_RELEASE(_curve);
     SAFE_RELEASE(_animation);
     SAFE_RELEASE(_animation);
 }
 }
 
 
 Curve* Animation::Channel::getCurve() const
 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;
     return _curve;
 }
 }
 
 
-Animation::CurveRef::CurveRef(Curve* curve)
-    : _curve(curve)
-{
-}
-
-Animation::CurveRef::~CurveRef()
-{
-    SAFE_DELETE(_curve);
-}
-
 const char* Animation::getId() const
 const char* Animation::getId() const
 {
 {
     return _id.c_str();
     return _id.c_str();
@@ -301,7 +279,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
     assert(propertyComponentCount > 0);
 
 
-    Curve* curve = new Curve(keyCount, propertyComponentCount);
+    Curve* curve = Curve::create(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
     if (target->_targetType == AnimationTarget::TRANSFORM)
         setTransformRotationOffset(curve, propertyId);
         setTransformRotationOffset(curve, propertyId);
 
 
@@ -328,6 +306,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
     SAFE_DELETE(normalizedKeyTimes);
 
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
+    curve->release();
     addChannel(channel);
     addChannel(channel);
     return channel;
     return channel;
 }
 }
@@ -337,7 +316,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
     assert(propertyComponentCount > 0);
     assert(propertyComponentCount > 0);
 
 
-    Curve* curve = new Curve(keyCount, propertyComponentCount);
+    Curve* curve = Curve::create(keyCount, propertyComponentCount);
     if (target->_targetType == AnimationTarget::TRANSFORM)
     if (target->_targetType == AnimationTarget::TRANSFORM)
         setTransformRotationOffset(curve, propertyId);
         setTransformRotationOffset(curve, propertyId);
     
     
@@ -364,6 +343,7 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
     SAFE_DELETE(normalizedKeyTimes);
 
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
+    curve->release();
     addChannel(channel);
     addChannel(channel);
     return channel;
     return channel;
 }
 }

+ 1 - 21
gameplay/src/Animation.h

@@ -96,26 +96,6 @@ public:
 
 
 private:
 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.
      * Defines a channel which holds the target, target property, curve values, and duration.
      *
      *
@@ -141,7 +121,7 @@ private:
         Animation* _animation;                // Reference to the animation this channel belongs to.
         Animation* _animation;                // Reference to the animation this channel belongs to.
         AnimationTarget* _target;             // The target of this channel.
         AnimationTarget* _target;             // The target of this channel.
         int _propertyId;                      // The target property this channel targets.
         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).
         unsigned long _duration;              // The length of the animation (in milliseconds).
     };
     };
 
 

+ 5 - 2
gameplay/src/Button.h

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

+ 7 - 7
gameplay/src/CheckBox.cpp

@@ -68,8 +68,8 @@ bool CheckBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int cont
         {
         {
             if (_state == Control::ACTIVE)
             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;
                     _checked = !_checked;
                     notifyListeners(Control::Listener::VALUE_CHANGED);
                     notifyListeners(Control::Listener::VALUE_CHANGED);
@@ -123,7 +123,7 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     // Left, v-center.
     // Left, v-center.
     // TODO: Set an alignment for icons.
     // TODO: Set an alignment for icons.
     const Theme::Border border = getBorder(_state);
     const Theme::Border border = getBorder(_state);
-    const Theme::Padding padding = _style->getPadding();
+    const Theme::Padding padding = getPadding();
     float opacity = getOpacity(_state);
     float opacity = getOpacity(_state);
 
 
     if (_checked)
     if (_checked)
@@ -143,8 +143,8 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             size.set(_imageSize);
             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);
         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);
             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);
         spriteBatch->draw(pos.x, pos.y, size.x, size.y, unselected.u1, unselected.v1, unselected.u2, unselected.v2, unselectedColor, _clip);
     }
     }

+ 2 - 2
gameplay/src/CheckBox.h

@@ -14,7 +14,7 @@ namespace gameplay
  *
  *
  * The following properties are available for checkboxes:
  * The following properties are available for checkboxes:
  *
  *
- * checkBox <CheckBox ID>
+ * checkBox <checkBoxID>
  * {
  * {
  *      style       = <Style ID>
  *      style       = <Style ID>
  *      position    = <x, y>
  *      position    = <x, y>
@@ -24,7 +24,7 @@ namespace gameplay
  *      iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.
  *      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;
     friend class Container;
 
 

+ 1 - 1
gameplay/src/Container.cpp

@@ -295,7 +295,7 @@ namespace gameplay
                 continue;
                 continue;
             }
             }
 
 
-            const Rectangle& bounds = control->getBounds();
+            const Rectangle& bounds = control->getClipBounds();
             if (control->getState() != Control::NORMAL ||
             if (control->getState() != Control::NORMAL ||
                 (evt == Touch::TOUCH_PRESS &&
                 (evt == Touch::TOUCH_PRESS &&
                  x >= xPos + bounds.x &&
                  x >= xPos + bounds.x &&

+ 9 - 4
gameplay/src/Container.h

@@ -20,10 +20,11 @@ namespace gameplay
  *      position = <x, y>               // Position of the container on-screen, measured in pixels.
  *      position = <x, y>               // Position of the container on-screen, measured in pixels.
  *      size     = <width, height>      // Size of the container, 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{}
  *      button{}
  *      checkBox{}
  *      checkBox{}
  *      radioButton{}
  *      radioButton{}
@@ -33,6 +34,7 @@ namespace gameplay
 class Container : public Control
 class Container : public Control
 {
 {
 public:
 public:
+
     /**
     /**
      * Get this container's layout.
      * Get this container's layout.
      *
      *
@@ -103,7 +105,9 @@ public:
     std::vector<Control*> getControls() const;
     std::vector<Control*> getControls() const;
 
 
 protected:
 protected:
+
     Container();
     Container();
+
     virtual ~Container();
     virtual ~Container();
 
 
     /**
     /**
@@ -207,6 +211,7 @@ protected:
     std::vector<Control*> _controls;    // List of controls within this container.
     std::vector<Control*> _controls;    // List of controls within this container.
 
 
 private:
 private:
+
     Container(const Container& copy);
     Container(const Container& copy);
 };
 };
 
 

+ 101 - 133
gameplay/src/Control.cpp

@@ -5,8 +5,8 @@
 namespace gameplay
 namespace gameplay
 {
 {
     Control::Control()
     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)
         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;
                 std::list<Listener*>* list = itr->second;
                 SAFE_DELETE(list);
                 SAFE_DELETE(list);
@@ -36,8 +36,11 @@ namespace gameplay
     {
     {
         _style = style;
         _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::getStateFromString(properties->getString("state"));
 
 
@@ -51,87 +54,59 @@ namespace gameplay
         return _id.c_str();
         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;
         _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();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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;
         _dirty = true;
@@ -145,10 +120,10 @@ namespace gameplay
     void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
     void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setBorder(top, bottom, left, right);
         }
         }
@@ -164,10 +139,10 @@ namespace gameplay
     void Control::setSkinRegion(const Rectangle& region, unsigned char states)
     void Control::setSkinRegion(const Rectangle& region, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setSkinRegion(region, _style->_tw, _style->_th);
         }
         }
@@ -188,10 +163,10 @@ namespace gameplay
     void Control::setSkinColor(const Vector4& color, unsigned char states)
     void Control::setSkinColor(const Vector4& color, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setSkinColor(color);
         }
         }
@@ -229,10 +204,10 @@ namespace gameplay
     void Control::setImageRegion(const char* id, const Rectangle& region, unsigned char states)
     void Control::setImageRegion(const char* id, const Rectangle& region, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             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)
     void Control::setImageColor(const char* id, const Vector4& color, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setImageColor(id, color);
         }
         }
@@ -272,10 +247,10 @@ namespace gameplay
     void Control::setCursorRegion(const Rectangle& region, unsigned char states)
     void Control::setCursorRegion(const Rectangle& region, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setCursorRegion(region, _style->_tw, _style->_th);
         }
         }
@@ -291,10 +266,10 @@ namespace gameplay
     void Control::setCursorColor(const Vector4& color, unsigned char states)
     void Control::setCursorColor(const Vector4& color, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setCursorColor(color);
         }
         }
@@ -315,10 +290,10 @@ namespace gameplay
     void Control::setFont(Font* font, unsigned char states)
     void Control::setFont(Font* font, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setFont(font);
         }
         }
@@ -334,10 +309,10 @@ namespace gameplay
     void Control::setFontSize(unsigned int fontSize, unsigned char states)
     void Control::setFontSize(unsigned int fontSize, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setFontSize(fontSize);
         }
         }
@@ -353,10 +328,10 @@ namespace gameplay
     void Control::setTextColor(const Vector4& color, unsigned char states)
     void Control::setTextColor(const Vector4& color, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setTextColor(color);
         }
         }
@@ -372,10 +347,10 @@ namespace gameplay
     void Control::setTextAlignment(Font::Justify alignment, unsigned char states)
     void Control::setTextAlignment(Font::Justify alignment, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setTextAlignment(alignment);
         }
         }
@@ -391,10 +366,10 @@ namespace gameplay
     void Control::setTextRightToLeft(bool rightToLeft, unsigned char states)
     void Control::setTextRightToLeft(bool rightToLeft, unsigned char states)
     {
     {
         overrideStyle();
         overrideStyle();
-        Theme::Style::Overlay* overlays[MAX_OVERLAYS] = { 0 };
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
         getOverlays(states, overlays);
         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);
             overlays[i]->setTextRightToLeft(rightToLeft);
         }
         }
@@ -407,9 +382,9 @@ namespace gameplay
         return getOverlay(state)->getTextRightToLeft();
         return getOverlay(state)->getTextRightToLeft();
     }
     }
 
 
-    const Rectangle& Control::getBounds() const
+    const Rectangle& Control::getClipBounds() const
     {
     {
-        return _bounds;
+        return _clipBounds;
     }
     }
 
 
     const Rectangle& Control::getClip() const
     const Rectangle& Control::getClip() const
@@ -417,13 +392,6 @@ namespace gameplay
         return _clip;
         return _clip;
     }
     }
 
 
-    void Control::setAutoSize(bool width, bool height)
-    {
-        _autoWidth = width;
-        _autoHeight = height;
-        _dirty = true;
-    }
-
     void Control::setStyle(Theme::Style* style)
     void Control::setStyle(Theme::Style* style)
     {
     {
         if (style != _style)
         if (style != _style)
@@ -529,7 +497,7 @@ namespace gameplay
             _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
             _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())
         if (itr == _listeners->end())
         {
         {
             _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
             _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
@@ -558,8 +526,8 @@ namespace gameplay
             notifyListeners(Listener::RELEASE);
             notifyListeners(Listener::RELEASE);
 
 
             // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
             // 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);
                 notifyListeners(Listener::CLICK);
             }
             }
@@ -577,7 +545,7 @@ namespace gameplay
     {
     {
         if (_listeners)
         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())
             if (itr != _listeners->end())
             {
             {
                 std::list<Listener*>* listenerList = itr->second;
                 std::list<Listener*>* listenerList = itr->second;
@@ -592,10 +560,10 @@ namespace gameplay
     void Control::update(const Rectangle& clip)
     void Control::update(const Rectangle& clip)
     {
     {
         // Calculate the bounds.
         // 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 clipX2 = clip.x + clip.width;
         float x2 = x + width;
         float x2 = x + width;
@@ -611,7 +579,7 @@ namespace gameplay
             height = clipY2 - y;
             height = clipY2 - y;
         }
         }
 
 
-        _bounds.set(_position.x, _position.y, width, height);
+        _clipBounds.set(_bounds.x, _bounds.y, width, height);
 
 
         // Calculate the clipping viewport.
         // Calculate the clipping viewport.
         const Theme::Border& border = getBorder(_state);
         const Theme::Border& border = getBorder(_state);
@@ -619,8 +587,8 @@ namespace gameplay
 
 
         x +=  border.left + padding.left;
         x +=  border.left + padding.left;
         y +=  border.top + padding.top;
         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);
         _textBounds.set(x, y, width, height);
 
 
@@ -653,7 +621,7 @@ namespace gameplay
 
 
     void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
     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.
         // Get the border and background images for this control's current state.
         //Theme::UVs topLeft, top, topRight, left, center, right, bottomLeft, bottom, bottomRight;
         //Theme::UVs topLeft, top, topRight, left, center, right, bottomLeft, bottom, bottomRight;
@@ -673,18 +641,18 @@ namespace gameplay
         Vector4 skinColor = getSkinColor(_state);
         Vector4 skinColor = getSkinColor(_state);
         skinColor.w *= getOpacity(_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 midX = pos.x + border.left;
         float midY = pos.y + border.top;
         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.
         // Draw themed border sprites.
         if (!border.left && !border.right && !border.top && !border.bottom)
         if (!border.left && !border.right && !border.top && !border.bottom)
         {
         {
             // No border, just draw the image.
             // 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
         else
         {
         {
@@ -697,7 +665,7 @@ namespace gameplay
             if (border.left)
             if (border.left)
                 spriteBatch->draw(pos.x, midY, border.left, midHeight, left.u1, left.v1, left.u2, left.v2, skinColor, clip);
                 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)
             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);
                     center.u1, center.v1, center.u2, center.v2, skinColor, clip);
             if (border.right)
             if (border.right)
                 spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, skinColor, clip);
                 spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, skinColor, clip);
@@ -781,24 +749,24 @@ namespace gameplay
         switch(propertyId)
         switch(propertyId)
         {
         {
         case ANIMATE_POSITION:
         case ANIMATE_POSITION:
-            value->setFloat(0, _position.x);
-            value->setFloat(1, _position.y);
+            value->setFloat(0, _bounds.x);
+            value->setFloat(1, _bounds.y);
             break;
             break;
         case ANIMATE_SIZE:
         case ANIMATE_SIZE:
-            value->setFloat(0, _size.x);
-            value->setFloat(1, _size.y);
+            value->setFloat(0, _clipBounds.width);
+            value->setFloat(1, _clipBounds.height);
             break;
             break;
         case ANIMATE_POSITION_X:
         case ANIMATE_POSITION_X:
-            value->setFloat(0, _position.x);
+            value->setFloat(0, _bounds.x);
             break;
             break;
         case ANIMATE_POSITION_Y:
         case ANIMATE_POSITION_Y:
-            value->setFloat(0, _position.y);
+            value->setFloat(0, _bounds.y);
             break;
             break;
         case ANIMATE_SIZE_WIDTH:
         case ANIMATE_SIZE_WIDTH:
-            value->setFloat(0, _size.x);
+            value->setFloat(0, _clipBounds.width);
             break;
             break;
         case ANIMATE_SIZE_HEIGHT:
         case ANIMATE_SIZE_HEIGHT:
-            value->setFloat(0, _size.y);
+            value->setFloat(0, _clipBounds.height);
             break;
             break;
         case ANIMATE_OPACITY:
         case ANIMATE_OPACITY:
         default:
         default:
@@ -845,9 +813,9 @@ namespace gameplay
         }
         }
         else
         else
         {
         {
-            x = Curve::lerp(blendWeight, _position.x, x);
+            x = Curve::lerp(blendWeight, _bounds.x, x);
         }
         }
-        _position.x = x;
+        _bounds.x = x;
         _dirty = true;
         _dirty = true;
     }
     }
     
     
@@ -859,9 +827,9 @@ namespace gameplay
         }
         }
         else
         else
         {
         {
-            y = Curve::lerp(blendWeight, _position.y, y);
+            y = Curve::lerp(blendWeight, _bounds.y, y);
         }
         }
-        _position.y = y;
+        _bounds.y = y;
         _dirty = true;
         _dirty = true;
     }
     }
     
     
@@ -873,9 +841,9 @@ namespace gameplay
         }
         }
         else
         else
         {
         {
-            width = Curve::lerp(blendWeight, _size.x, width);
+            width = Curve::lerp(blendWeight, _clipBounds.width, width);
         }
         }
-        _size.x = width;
+        _clipBounds.width = width;
         _dirty = true;
         _dirty = true;
     }
     }
 
 
@@ -887,9 +855,9 @@ namespace gameplay
         }
         }
         else
         else
         {
         {
-            height = Curve::lerp(blendWeight, _size.y, height);
+            height = Curve::lerp(blendWeight, _clipBounds.height, height);
         }
         }
-        _size.y = height;
+        _clipBounds.height = height;
         _dirty = true;
         _dirty = true;
     }
     }
 
 

+ 93 - 41
gameplay/src/Control.h

@@ -6,14 +6,10 @@
 #include "Vector2.h"
 #include "Vector2.h"
 #include "SpriteBatch.h"
 #include "SpriteBatch.h"
 #include "Theme.h"
 #include "Theme.h"
+#include "ThemeStyle.h"
 #include "Touch.h"
 #include "Touch.h"
 #include "Keyboard.h"
 #include "Keyboard.h"
 
 
-/**
- * Default duration of UI animations.
- */
-#define DEFAULT_UI_ANIMATION_DURATION 200L
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -34,13 +30,31 @@ public:
      */
      */
     enum State
     enum State
     {
     {
+        /**
+         * State of an enabled but inactive control.
+         */
         NORMAL = 0x01,
         NORMAL = 0x01,
+
+        /**
+         * State of a control currently in focus.
+         */
         FOCUS = 0x02,
         FOCUS = 0x02,
+
+        /**
+         * State of a control that is currently being acted on,
+         * e.g. through touch or mouse-click events.
+         */
         ACTIVE = 0x04,
         ACTIVE = 0x04,
+
+        /**
+         * State of a control that has been disabled.
+         */
         DISABLED = 0x08,
         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;
     static const unsigned char STATE_ALL = NORMAL | FOCUS | ACTIVE | DISABLED;
 
 
     class Listener
     class Listener
@@ -48,13 +62,40 @@ public:
     public:
     public:
         enum EventType
         enum EventType
         {
         {
+            /**
+             * Mouse-down or touch-press event.
+             */
             PRESS           = 0x01,
             PRESS           = 0x01,
+
+            /**
+             * Mouse-up or touch-release event.
+             */
             RELEASE         = 0x02,
             RELEASE         = 0x02,
+
+            /**
+             * Event triggered after consecutive PRESS and RELEASE events take place
+             * within the bounds of a control.
+             */
             CLICK           = 0x04,
             CLICK           = 0x04,
+
+            /**
+             * Event triggered when the value of a slider, check box, or radio button
+             * changes.
+             */
             VALUE_CHANGED   = 0x08,
             VALUE_CHANGED   = 0x08,
+
+            /**
+             * Event triggered when the contents of a text box are modified.
+             */
             TEXT_CHANGED    = 0x10
             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;
         virtual void controlEvent(Control* control, EventType evt) = 0;
     };
     };
 
 
@@ -106,33 +147,61 @@ public:
      * @param x The x coordinate.
      * @param x The x coordinate.
      * @param y The y 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;
+
+    // Themed properties.
     /**
     /**
      * Set the size of this control's border.
      * Set the size of this control's border.
      *
      *
@@ -422,7 +491,7 @@ public:
      *               One or more members of the Control::State enum, ORed together.
      *               One or more members of the Control::State enum, ORed together.
      * @param duration The duration to animate opacity by.
      * @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. 
      * Get the opacity of this control for a given state. 
@@ -437,13 +506,12 @@ public:
     // Controls must state the names of the images they use, for the purposes of a future UI editor.
     // 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;
     //virtual std::vector<std::string> getImageNames() = 0;
 
 
-    // Control state.
     /**
     /**
      * Get the bounds of this control, relative to its parent container, after clipping.
      * Get the bounds of this control, relative to its parent container, after clipping.
      *
      *
      * @return The bounds of this control.
      * @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.
      * Get the content area of this control, in screen coordinates, after clipping.
@@ -452,18 +520,6 @@ public:
      */
      */
     const Rectangle& getClip() const;
     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.
      * Change this control's state.
      *
      *
@@ -650,18 +706,14 @@ protected:
 
 
     std::string _id;
     std::string _id;
     State _state;           // Determines overlay used during draw().
     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 _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.
     Rectangle _clip;        // Clipping window of this control's content, after clipping.
-    bool _autoWidth;
-    bool _autoHeight;
     bool _dirty;
     bool _dirty;
     bool _consumeTouchEvents;
     bool _consumeTouchEvents;
     Theme::Style* _style;
     Theme::Style* _style;
-    typedef std::map<Listener::EventType, std::list<Listener*>*> ListenerMap;
-    ListenerMap* _listeners;
+    std::map<Listener::EventType, std::list<Listener*>*>* _listeners;
 
 
 private:
 private:
     // Animation blending bits.
     // Animation blending bits.

+ 5 - 0
gameplay/src/Curve.cpp

@@ -54,6 +54,11 @@ using std::strcmp;
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+Curve* Curve::create(unsigned int pointCount, unsigned int componentCount)
+{
+    return new Curve(pointCount, componentCount);
+}
+
 Curve::Curve(unsigned int pointCount, unsigned int componentCount)
 Curve::Curve(unsigned int pointCount, unsigned int componentCount)
     : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
     : _pointCount(pointCount), _componentCount(componentCount), _componentSize(sizeof(float)*componentCount), _quaternionOffset(NULL), _points(NULL)
 {
 {

+ 25 - 11
gameplay/src/Curve.h

@@ -1,13 +1,15 @@
 #ifndef CURVE_H_
 #ifndef CURVE_H_
 #define CURVE_H_
 #define CURVE_H_
 
 
+#include "Ref.h"
+
 namespace gameplay
 namespace gameplay
 {
 {
 
 
 /**
 /**
  * Represents an n-dimensional curve.
  * Represents an n-dimensional curve.
  */
  */
-class Curve
+class Curve : public Ref
 {
 {
     friend class Animation;
     friend class Animation;
     friend class AnimationClip;
     friend class AnimationClip;
@@ -272,19 +274,13 @@ public:
         BOUNCE_OUT_IN
         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 pointCount The number of points in the curve.
      * @param componentCount The number of float component values per key value.
      * @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.
      * Gets the number of points in the curve.
@@ -396,10 +392,28 @@ private:
     Curve();
     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);
     Curve(const Curve& copy);
 
 
+    /**
+     * Destructor.
+     */
+    ~Curve();
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    Curve& operator=(const Curve&);
+
     /**
     /**
      * Bezier interpolation function.
      * Bezier interpolation function.
      */
      */

+ 8 - 9
gameplay/src/Form.cpp

@@ -136,9 +136,9 @@ namespace gameplay
         if (_node && !_quad)
         if (_node && !_quad)
         {
         {
             // Set this Form up to be 3D by initializing a quad, projection matrix and viewport.
             // 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);
             _theme->setProjectionMatrix(_projectionMatrix);
             
             
             _node->setModel(_quad);
             _node->setModel(_quad);
@@ -147,7 +147,7 @@ namespace gameplay
 
 
     void Form::update()
     void Form::update()
     {
     {
-        Container::update(Rectangle(0, 0, _size.x, _size.y));
+        Container::update(Rectangle(0, 0, _bounds.width, _bounds.height));
     }
     }
 
 
     void Form::draw()
     void Form::draw()
@@ -171,7 +171,7 @@ namespace gameplay
                 Game* game = Game::getInstance();
                 Game* game = Game::getInstance();
                 Rectangle prevViewport = game->getViewport();
                 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);
                 draw(_theme->getSpriteBatch(), _clip);
 
 
@@ -199,7 +199,7 @@ namespace gameplay
 
 
         // Draw the form's border and background.
         // Draw the form's border and background.
         // We don't pass the form's position to itself or it will be applied twice!
         // 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.
         // Draw each control's border and background.
         for (it = _controls.begin(); it < _controls.end(); it++)
         for (it = _controls.begin(); it < _controls.end(); it++)
@@ -244,7 +244,6 @@ namespace gameplay
         // Set the common render state block for the material
         // Set the common render state block for the material
         RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
         RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
         stateBlock->setDepthWrite(true);
         stateBlock->setDepthWrite(true);
-        //material->setStateBlock(_theme->getSpriteBatch()->getStateBlock());
         material->setStateBlock(stateBlock);
         material->setStateBlock(stateBlock);
 
 
         // Bind the WorldViewProjection matrix
         // Bind the WorldViewProjection matrix
@@ -259,7 +258,7 @@ namespace gameplay
         // Use the FrameBuffer to texture the quad.
         // Use the FrameBuffer to texture the quad.
         if (!_frameBuffer->getRenderTarget())
         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);
             _frameBuffer->setRenderTarget(rt);
             SAFE_RELEASE(rt);
             SAFE_RELEASE(rt);
         }
         }
@@ -327,7 +326,7 @@ namespace gameplay
                             m.transformPoint(&point);
                             m.transformPoint(&point);
 
 
                             // Pass the touch event on.
                             // Pass the touch event on.
-                            const Rectangle& bounds = form->getBounds();
+                            const Rectangle& bounds = form->getClipBounds();
                             if (form->getState() == Control::FOCUS ||
                             if (form->getState() == Control::FOCUS ||
                                 (evt == Touch::TOUCH_PRESS &&
                                 (evt == Touch::TOUCH_PRESS &&
                                  point.x >= bounds.x &&
                                  point.x >= bounds.x &&
@@ -346,7 +345,7 @@ namespace gameplay
                 else
                 else
                 {
                 {
                     // Simply compare with the form's bounds.
                     // Simply compare with the form's bounds.
-                    const Rectangle& bounds = form->getBounds();
+                    const Rectangle& bounds = form->getClipBounds();
                     if (form->getState() == Control::FOCUS ||
                     if (form->getState() == Control::FOCUS ||
                         (evt == Touch::TOUCH_PRESS &&
                         (evt == Touch::TOUCH_PRESS &&
                          x >= bounds.x &&
                          x >= bounds.x &&

+ 3 - 3
gameplay/src/Game.cpp

@@ -130,9 +130,9 @@ void Game::shutdown()
         SAFE_DELETE(_audioListener);
         SAFE_DELETE(_audioListener);
 
 
         RenderState::finalize();
         RenderState::finalize();
+        
+        _state = UNINITIALIZED;
     }
     }
-
-    _state = UNINITIALIZED;
 }
 }
 
 
 void Game::pause()
 void Game::pause()
@@ -159,7 +159,7 @@ void Game::resume()
     }
     }
 }
 }
 
 
-void Game::exit()
+void Game::end()
 {
 {
     shutdown();
     shutdown();
 }
 }

+ 3 - 46
gameplay/src/Game.h

@@ -119,9 +119,9 @@ public:
     void resume();
     void resume();
 
 
     /**
     /**
-     * Exits the game.
+     * Ends the game.
      */
      */
-    void exit();
+    void end();
 
 
     /**
     /**
      * Platform frame delagate.
      * Platform frame delagate.
@@ -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.
     // 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"
 #include "Game.inl"

+ 0 - 14
gameplay/src/Game.inl

@@ -71,18 +71,4 @@ inline void Game::displayKeyboard(bool display)
     Platform::displayKeyboard(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));
-}
-
 }
 }

+ 4 - 7
gameplay/src/Label.cpp

@@ -69,16 +69,13 @@ namespace gameplay
         if (_text.size() <= 0)
         if (_text.size() <= 0)
             return;
             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.
         // Draw the text.
         font->begin();
         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();
         font->end();
 
 
         _dirty = false;
         _dirty = false;

+ 1 - 1
gameplay/src/Node.cpp

@@ -909,7 +909,7 @@ PhysicsCollisionObject* Node::setCollisionObject(PhysicsCollisionObject::Type ty
 
 
     case PhysicsCollisionObject::CHARACTER:
     case PhysicsCollisionObject::CHARACTER:
         {
         {
-            _collisionObject = new PhysicsCharacter(this, shape);
+            _collisionObject = new PhysicsCharacter(this, shape, rigidBodyParameters ? rigidBodyParameters->mass : 1.0f);
         }
         }
         break;
         break;
     }
     }

+ 24 - 20
gameplay/src/PhysicsCharacter.cpp

@@ -55,11 +55,11 @@ protected:
     btScalar _minSlopeDot;
     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),
     : 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),
     _fallVelocity(0, 0, 0), _currentVelocity(0,0,0), _normalizedVelocity(0,0,0),
     _colliding(false), _collisionNormal(0,0,0), _currentPosition(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);
 
 
@@ -94,8 +94,20 @@ PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
         return NULL;
         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.
     // Create the physics character.
-    PhysicsCharacter* character = new PhysicsCharacter(node, *shape);
+    PhysicsCharacter* character = new PhysicsCharacter(node, *shape, mass);
     SAFE_DELETE(shape);
     SAFE_DELETE(shape);
 
 
     return character;
     return character;
@@ -493,14 +505,14 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
 
 
         if (callback.hasHit())
         if (callback.hasHit())
         {
         {
-            /*Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
+            Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
             PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
             PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
             if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
             if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
             {
             {
                 PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
                 PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
                 normal.normalize();
                 normal.normalize();
-                rb->applyImpulse(-normal);
-            }*/
+                rb->applyImpulse(_mass * -normal * velocity.length());
+            }
 
 
             updateTargetPositionFromCollision(targetPosition, callback.m_hitNormalWorld);
             updateTargetPositionFromCollision(targetPosition, callback.m_hitNormalWorld);
 
 
@@ -592,9 +604,6 @@ btVector3 perpindicularComponent(const btVector3& direction, const btVector3& no
 
 
 void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPosition, const btVector3& collisionNormal)
 void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPosition, const btVector3& collisionNormal)
 {
 {
-    //btScalar tangentMag = 0.0;
-    //btScalar normalMag = 1.0;
-
     btVector3 movementDirection = targetPosition - _currentPosition;
     btVector3 movementDirection = targetPosition - _currentPosition;
     btScalar movementLength = movementDirection.length();
     btScalar movementLength = movementDirection.length();
 
 
@@ -605,21 +614,16 @@ void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPositi
         btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
         btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
         reflectDir.normalize();
         reflectDir.normalize();
 
 
-        //btVector3 parallelDir = parallelComponent(reflectDir, collisionNormal);
         btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
         btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
-
         targetPosition = _currentPosition;
         targetPosition = _currentPosition;
-        /*if (tangentMag != 0.0)
-        {
-            btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength);
-            targetPosition +=  parComponent;
-        }*/
 
 
-        //if (normalMag != 0.0)
-        //{
-            btVector3 perpComponent = perpindicularDir * btScalar (/*normalMag **/ movementLength);
+        // 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;
             targetPosition += perpComponent;
-        //}
+        }
     }
     }
 }
 }
 
 

+ 3 - 1
gameplay/src/PhysicsCharacter.h

@@ -288,8 +288,9 @@ private:
      *
      *
      * @param node Scene node that represents the character.
      * @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.
      * Destructor.
@@ -338,6 +339,7 @@ private:
     float _slopeAngle;
     float _slopeAngle;
     float _cosSlopeAngle;
     float _cosSlopeAngle;
     bool _physicsEnabled;
     bool _physicsEnabled;
+    float _mass;
 };
 };
 
 
 }
 }

+ 3 - 4
gameplay/src/PlatformMacOS.mm

@@ -67,7 +67,7 @@ static View* __view = NULL;
 -(void)windowWillClose:(NSNotification*)note 
 -(void)windowWillClose:(NSNotification*)note 
 {
 {
     [lock lock];
     [lock lock];
-    _game->exit();
+    _game->end();
     [lock unlock];
     [lock unlock];
     [[NSApplication sharedApplication] terminate:self];
     [[NSApplication sharedApplication] terminate:self];
 }
 }
@@ -88,10 +88,9 @@ static View* __view = NULL;
     [lock lock];
     [lock lock];
 
 
     [[self openGLContext] makeCurrentContext];
     [[self openGLContext] makeCurrentContext];
-    
     CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);
     CGLLockContext((CGLContextObj)[[self openGLContext] CGLContextObj]);
     
     
-    if (_game && _game->getState() == Game::RUNNING)       
+    if (_game && _game->getState() == Game::RUNNING)  
         _game->frame();
         _game->frame();
     
     
     CGLFlushDrawable((CGLContextObj)[[self openGLContext] CGLContextObj]);
     CGLFlushDrawable((CGLContextObj)[[self openGLContext] CGLContextObj]);
@@ -176,7 +175,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     CVDisplayLinkStop(displayLink);
     CVDisplayLinkStop(displayLink);
     CVDisplayLinkRelease(displayLink);
     CVDisplayLinkRelease(displayLink);
     
     
-    _game->exit();
+    _game->end();
     
     
     [lock unlock];
     [lock unlock];
 
 

+ 13 - 7
gameplay/src/RadioButton.cpp

@@ -48,6 +48,11 @@ RadioButton* RadioButton::create(Theme::Style* style, Properties* properties)
     return radioButton;
     return radioButton;
 }
 }
 
 
+bool RadioButton::isSelected() const
+{
+    return _selected;
+}
+
 void RadioButton::setImageSize(float width, float height)
 void RadioButton::setImageSize(float width, float height)
 {
 {
     _imageSize.set(width, 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 (_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)
                     if (!_selected)
                     {
                     {
@@ -110,6 +115,7 @@ void RadioButton::clearSelected(const std::string& groupId)
         {
         {
             radioButton->_selected = false;
             radioButton->_selected = false;
             radioButton->_dirty = true;
             radioButton->_dirty = true;
+            radioButton->notifyListeners(Listener::VALUE_CHANGED);
         }
         }
     }
     }
 }
 }
@@ -119,7 +125,7 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     // Left, v-center.
     // Left, v-center.
     // TODO: Set an alignment for radio button images.
     // TODO: Set an alignment for radio button images.
     const Theme::Border border = getBorder(_state);
     const Theme::Border border = getBorder(_state);
-    const Theme::Padding padding = _style->getPadding();
+    const Theme::Padding padding = getPadding();
     float opacity = getOpacity(_state);
     float opacity = getOpacity(_state);
 
 
     if (_selected)
     if (_selected)
@@ -139,8 +145,8 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             size.set(_imageSize);
             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);
         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);
             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);
         spriteBatch->draw(pos.x, pos.y, size.x, size.y, unselected.u1, unselected.v1, unselected.u2, unselected.v2, unselectedColor, _clip);
     }
     }

+ 1 - 1
gameplay/src/RadioButton.h

@@ -36,7 +36,7 @@ public:
      *
      *
      * @return Whether this radio button is currently selected.
      * @return Whether this radio button is currently selected.
      */
      */
-    bool isSelected();
+    bool isSelected() const;
 
 
     /**
     /**
      * Set the size to draw the radio button icon.
      * Set the size to draw the radio button icon.

+ 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

+ 14 - 14
gameplay/src/Slider.cpp

@@ -91,8 +91,8 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
     case Touch::TOUCH_MOVE:
     case Touch::TOUCH_MOVE:
     case Touch::TOUCH_RELEASE:
     case Touch::TOUCH_RELEASE:
         if (_state == ACTIVE &&
         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.
             // Horizontal case.
             const Theme::Border& border = getBorder(_state);
             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);
             const Rectangle& maxCapRegion = getImageRegion("maxCap", _state);
 
 
             float markerPosition = ((float)x - maxCapRegion.width - border.left - padding.left) /
             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)
             if (markerPosition > 1.0f)
             {
             {
@@ -113,7 +113,7 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
             }
             }
 
 
             float oldValue = _value;
             float oldValue = _value;
-            _value = markerPosition * _max;
+            _value = (markerPosition * (_max - _min)) + _min;
             if (_step > 0.0f)
             if (_step > 0.0f)
             {
             {
                 float stepDistance = _step / (_max - _min);
                 float stepDistance = _step / (_max - _min);
@@ -167,23 +167,23 @@ void Slider::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     trackColor.w *= opacity;
     trackColor.w *= opacity;
 
 
     // Draw order: track, caps, marker.
     // 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.y = midY - minCapRegion.height * 0.5f;
     pos.x -= minCapRegion.width * 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.
     // 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;
     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);
 }
 }
 
 
 }
 }

+ 52 - 42
gameplay/src/TextBox.cpp

@@ -66,8 +66,8 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
             _dirty = true;
             _dirty = true;
             return _consumeTouchEvents;
             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;
             _state = NORMAL;
             Game::getInstance()->displayKeyboard(false);
             Game::getInstance()->displayKeyboard(false);
@@ -77,8 +77,8 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
         break;
         break;
     case Touch::TOUCH_MOVE:
     case Touch::TOUCH_MOVE:
         if (_state == FOCUS &&
         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);
             setCursorLocation(x, y);
             _dirty = true;
             _dirty = true;
@@ -86,8 +86,8 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
         }
         }
         break;
         break;
     case Touch::TOUCH_RELEASE:
     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);
             setCursorLocation(x, y);
             _state = FOCUS;
             _state = FOCUS;
@@ -126,66 +126,71 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     }
                     }
                     case Keyboard::KEY_DELETE:
                     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, _cursorLocation, &_cursorLocation,
+                            textAlignment, true, rightToLeft);
                         _text.erase(textIndex, 1);
                         _text.erase(textIndex, 1);
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         _dirty = true;
                         notifyListeners(Listener::TEXT_CHANGED);
                         notifyListeners(Listener::TEXT_CHANGED);
                         break;
                         break;
                     }
                     }
                     case Keyboard::KEY_LEFT_ARROW:
                     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* 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, _cursorLocation, &_cursorLocation,
+                            textAlignment, true, rightToLeft);
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex - 1,
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex - 1,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         _dirty = true;
                         break;
                         break;
                     }
                     }
                     case Keyboard::KEY_RIGHT_ARROW:
                     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* 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, _cursorLocation, &_cursorLocation,
+                            textAlignment, true, rightToLeft);
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         _dirty = true;
                         break;
                         break;
                     }
                     }
                     case Keyboard::KEY_UP_ARROW:
                     case Keyboard::KEY_UP_ARROW:
                     {
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
 
 
                         _cursorLocation.y -= fontSize;
                         _cursorLocation.y -= fontSize;
                         font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
                         font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         _dirty = true;
                         break;
                         break;
                     }
                     }
                     case Keyboard::KEY_DOWN_ARROW:
                     case Keyboard::KEY_DOWN_ARROW:
                     {
                     {
-                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                        Font* font = overlay->getFont();
-                        unsigned int fontSize = overlay->getFontSize();
+                        Font* font = getFont(_state);
+                        unsigned int fontSize = getFontSize(_state);
+                        Font::Justify textAlignment = getTextAlignment(_state);
+                        bool rightToLeft = getTextRightToLeft(_state);
 
 
                         _cursorLocation.y += fontSize;
                         _cursorLocation.y += fontSize;
                         font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
                         font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            textAlignment, true, rightToLeft);
                         _dirty = true;
                         _dirty = true;
                         break;
                         break;
                     }
                     }
@@ -195,11 +200,13 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
 
 
             case Keyboard::KEY_CHAR:
             case Keyboard::KEY_CHAR:
             {
             {
-                Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-                Font* font = overlay->getFont();
-                unsigned int fontSize = overlay->getFontSize();
+                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, _cursorLocation, &_cursorLocation,
                 unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
-                    overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                    textAlignment, true, rightToLeft);
 
 
                 switch (key)
                 switch (key)
                 {
                 {
@@ -210,7 +217,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                             --textIndex;
                             --textIndex;
                             _text.erase(textIndex, 1);
                             _text.erase(textIndex, 1);
                             font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
                             font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
-                                overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                                textAlignment, true, rightToLeft);
 
 
                             _dirty = true;
                             _dirty = true;
                         }
                         }
@@ -226,7 +233,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
 
 
                         // Get new location of cursor.
                         // Get new location of cursor.
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
-                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                            textAlignment, true, rightToLeft);
                 
                 
                         _dirty = true;
                         _dirty = true;
                         break;
                         break;
@@ -250,10 +257,13 @@ void TextBox::update(const Rectangle& clip)
     // Get index into string and cursor location from the last recorded touch location.
     // Get index into string and cursor location from the last recorded touch location.
     if (_state == FOCUS)
     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, _cursorLocation, &_cursorLocation,
+            textAlignment, true, rightToLeft);
     }
     }
 }
 }
 
 

+ 2 - 466
gameplay/src/Theme.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "Base.h"
 #include "Theme.h"
 #include "Theme.h"
+#include "ThemeStyle.h"
 
 
 namespace gameplay
 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;
         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.
      * Theme utility methods.

+ 51 - 224
gameplay/src/Theme.h

@@ -11,9 +11,6 @@
 namespace gameplay
 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.
  * 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
  * Once loaded, the appearance properties can be retrieved from their style IDs and set on other
@@ -54,7 +51,7 @@ static const unsigned int MAX_OVERLAY_REGIONS = 9;
  *    }
  *    }
  *   
  *   
  *    // Defines the border and background of a Control.
  *    // Defines the border and background of a Control.
- *    Skin <SkinID>
+ *    Skin <skinID>
  *    {
  *    {
  *        // The corners and edges of the given region will be used as border sprites.
  *        // The corners and edges of the given region will be used as border sprites.
  *        border
  *        border
@@ -125,40 +122,23 @@ class Theme: public Ref
     friend class Skin;
     friend class Skin;
 
 
 public:
 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.
+     * Class representing a set of themed attributes that can be
+     * assigned to a control.
      *
      *
-     * @param id ID of the style (as specified in the Theme file).
-     *
-     * @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.
      * Struct representing the UV coordinates of a rectangular image.
      */
      */
-    typedef class UVs
+    struct UVs
     {
     {
-    public:
         UVs();
         UVs();
+
         UVs(float u1, float v1, float u2, float v2);
         UVs(float u1, float v1, float u2, float v2);
 
 
         static const UVs& empty();
         static const UVs& empty();
@@ -167,15 +147,14 @@ public:
         float v1;
         float v1;
         float u2;
         float u2;
         float v2;
         float v2;
-    } UVs;
+    };
 
 
     /**
     /**
      * Struct representing margin, border, and padding areas by
      * Struct representing margin, border, and padding areas by
      * the width or height of each side.
      * the width or height of each side.
      */
      */
-    typedef class SideRegions
+    typedef struct SideRegions
     {
     {
-    public:
         SideRegions() : top(0), bottom(0), left(0), right(0) {}
         SideRegions() : top(0), bottom(0), left(0), right(0) {}
 
 
         static const SideRegions& empty();
         static const SideRegions& empty();
@@ -186,12 +165,20 @@ public:
         float right;
         float right;
     } Margin, Border, Padding;
     } 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
     class Image : public Ref
     {
     {
         friend class Theme;
         friend class Theme;
         friend class Control;
         friend class Control;
 
 
     public:
     public:
+
         const char* getId() const;
         const char* getId() const;
 
 
         const UVs& getUVs() const;
         const UVs& getUVs() const;
@@ -201,7 +188,9 @@ public:
         const Vector4& getColor() const;
         const Vector4& getColor() const;
 
 
     private:
     private:
+
         Image(float tw, float th, const Rectangle& region, const Vector4& color);
         Image(float tw, float th, const Rectangle& region, const Vector4& color);
+
         ~Image();
         ~Image();
 
 
         static Image* create(float tw, float th, Properties* properties, const Vector4& defaultColor);
         static Image* create(float tw, float th, Properties* properties, const Vector4& defaultColor);
@@ -212,19 +201,28 @@ public:
         Vector4 _color;
         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
     class ImageList : public Ref
     {
     {
         friend class Theme;
         friend class Theme;
         friend class Control;
         friend class Control;
 
 
     public:
     public:
+
         const char* getId() const;
         const char* getId() const;
 
 
         Image* getImage(const char* imageId) const;
         Image* getImage(const char* imageId) const;
 
 
     private:
     private:
+
         ImageList(const Vector4& color);
         ImageList(const Vector4& color);
+
         ImageList(const ImageList& copy);
         ImageList(const ImageList& copy);
+
         ~ImageList();
         ~ImageList();
 
 
         static ImageList* create(float tw, float th, Properties* properties);
         static ImageList* create(float tw, float th, Properties* properties);
@@ -242,6 +240,7 @@ public:
         friend class Theme;
         friend class Theme;
 
 
     public:
     public:
+
         enum SkinArea
         enum SkinArea
         {
         {
             TOP_LEFT, TOP, TOP_RIGHT,
             TOP_LEFT, TOP, TOP_RIGHT,
@@ -280,8 +279,9 @@ public:
         const Vector4& getColor() const;
         const Vector4& getColor() const;
 
 
     private:
     private:
+
         Skin(float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color);
         Skin(float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color);
-        //Skin(const Skin& copy);
+        
         ~Skin();
         ~Skin();
 
 
         static Skin* create(const char* id, float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color);
         static Skin* create(const char* id, float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color);
@@ -290,217 +290,44 @@ public:
     
     
         std::string _id;
         std::string _id;
         Theme::Border _border;
         Theme::Border _border;
-        UVs _uvs[MAX_OVERLAY_REGIONS];
+        UVs _uvs[9];
         Vector4 _color;
         Vector4 _color;
         Rectangle _region;
         Rectangle _region;
         float _tw, _th;
         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.
      * Constructor.
      */
      */
     Theme();
     Theme();
 
 
     /**
     /**
-     * Copy Constructor.
+     * Constructor.
      */
      */
-    Theme(const Theme* theme);
+    Theme(const Theme& theme);
 
 
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
     ~Theme();
     ~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);
     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);
     void lookUpSprites(const Properties* overlaySpace, ImageList** imageList, Image** mouseCursor, Skin** skin);
 
 
     std::string _path;
     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;
+    }
+}
+
+}

+ 225 - 0
gameplay/src/ThemeStyle.h

@@ -0,0 +1,225 @@
+#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
+ * the above classes to determine the border, background, cursor, and icon settings to use for
+ * a particular state.
+ */
+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;
+    };
+
+    /**
+     * 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);
+
+private:
+
+    /**
+     * 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();
+        
+    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)
     void VerticalLayout::update(const Container* container)
     {
     {
         // Need border, padding.
         // Need border, padding.
-        Theme::Style* style = container->getStyle();
+        //Theme::Style* style = container->getStyle();
         Theme::Border border = container->getBorder(container->getState());
         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;
         float yPosition = 0;
 
 
@@ -77,12 +71,12 @@ namespace gameplay
         {
         {
             Control* control = controls.at(i);
             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;
             yPosition += margin.top;
 
 
-            control->setPosition(0, yPosition, 0L);
+            control->setPosition(0, yPosition);
             if (control->isDirty())
             if (control->isDirty())
             {
             {
                 control->update(container->getClip());
                 control->update(container->getClip());

+ 3 - 0
gameplay/src/gameplay.h

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