Przeglądaj źródła

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

Steve Grenier 13 lat temu
rodzic
commit
c37cf6c49f
66 zmienionych plików z 1051 dodań i 1009 usunięć
  1. 6 7
      gameplay-encoder/README.md
  2. 10 10
      gameplay-encoder/gameplay-bundle.txt
  3. 2 2
      gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj
  4. 3 3
      gameplay-template/gameplay-template.xcodeproj/project.pbxproj
  5. 7 7
      gameplay.sln
  6. 1 1
      gameplay/android/jni/Android.mk
  7. 2 3
      gameplay/gameplay.vcxproj
  8. 6 12
      gameplay/gameplay.vcxproj.filters
  9. 14 14
      gameplay/gameplay.xcodeproj/project.pbxproj
  10. 1 1
      gameplay/src/AbsoluteLayout.h
  11. 28 1
      gameplay/src/Animation.cpp
  12. 17 2
      gameplay/src/Animation.h
  13. 9 12
      gameplay/src/AnimationTarget.cpp
  14. 118 119
      gameplay/src/Bundle.cpp
  15. 24 24
      gameplay/src/Bundle.h
  16. 15 13
      gameplay/src/Button.h
  17. 3 3
      gameplay/src/CheckBox.cpp
  18. 17 15
      gameplay/src/CheckBox.h
  19. 1 0
      gameplay/src/Container.cpp
  20. 29 27
      gameplay/src/Container.h
  21. 132 12
      gameplay/src/Control.cpp
  22. 9 0
      gameplay/src/Control.h
  23. 10 10
      gameplay/src/Font.cpp
  24. 6 6
      gameplay/src/Font.h
  25. 24 14
      gameplay/src/Form.cpp
  26. 27 29
      gameplay/src/Form.h
  27. 9 0
      gameplay/src/FrameBuffer.h
  28. 2 2
      gameplay/src/Joint.h
  29. 0 2
      gameplay/src/Label.cpp
  30. 15 13
      gameplay/src/Label.h
  31. 10 7
      gameplay/src/Layout.cpp
  32. 6 6
      gameplay/src/Matrix.cpp
  33. 5 5
      gameplay/src/Mesh.h
  34. 2 1
      gameplay/src/MeshBatch.cpp
  35. 3 0
      gameplay/src/MeshBatch.h
  36. 6 6
      gameplay/src/MeshBatch.inl
  37. 2 2
      gameplay/src/MeshSkin.h
  38. 2 2
      gameplay/src/Model.h
  39. 18 4
      gameplay/src/Node.cpp
  40. 25 2
      gameplay/src/Node.h
  41. 12 149
      gameplay/src/PhysicsCharacter.cpp
  42. 2 110
      gameplay/src/PhysicsCharacter.h
  43. 2 2
      gameplay/src/PhysicsCollisionShape.cpp
  44. 4 4
      gameplay/src/PhysicsController.cpp
  45. 1 1
      gameplay/src/PhysicsGhostObject.cpp
  46. 2 2
      gameplay/src/PhysicsRigidBody.cpp
  47. 6 22
      gameplay/src/PlatformQNX.cpp
  48. 67 70
      gameplay/src/Properties.h
  49. 1 1
      gameplay/src/Quaternion.h
  50. 2 2
      gameplay/src/RadioButton.cpp
  51. 17 15
      gameplay/src/RadioButton.h
  52. 3 0
      gameplay/src/RenderState.h
  53. 4 0
      gameplay/src/RenderTarget.h
  54. 42 31
      gameplay/src/SceneLoader.cpp
  55. 3 2
      gameplay/src/SceneLoader.h
  56. 17 16
      gameplay/src/Slider.h
  57. 1 1
      gameplay/src/SpriteBatch.h
  58. 32 1
      gameplay/src/TextBox.cpp
  59. 15 13
      gameplay/src/TextBox.h
  60. 1 1
      gameplay/src/Theme.cpp
  61. 109 107
      gameplay/src/Theme.h
  62. 4 4
      gameplay/src/ThemeStyle.cpp
  63. 3 2
      gameplay/src/ThemeStyle.h
  64. 60 51
      gameplay/src/Transform.cpp
  65. 14 2
      gameplay/src/Transform.h
  66. 1 1
      gameplay/src/gameplay.h

+ 6 - 7
gameplay-encoder/README.md

@@ -1,6 +1,6 @@
 ## gameplay-encoder
 Command-line tool for encoding games assets like true-type fonts and 3D scene files
-into a binary package file format for the gameplay 3D game framework runtime. 
+into a simple binary-based bundle file format for the gameplay 3D game framework runtime. 
 
 ## TrueType Font Support
 TrueType Fonts conversion is enabled/built-in by default into gameplay-encoder via freetype 2 library.
@@ -30,7 +30,7 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
   * Example: copy /Y "C:\Program Files\Autodesk\FBX\FbxSdk\2012.2\lib\vs2010\x86\fbxsdk-2012.2d.dll" "$(TargetDir)"
 - Build gameplay-encoder
 
-### Building FBX Support on Mac OS X using XCode 4
+### Building FBX Support on Mac OS X using XCode 4.3.2+
 - Download and install the FBX SDK for Mac OS X (http://www.autodesk.com/fbx)
 - Edit the project properties of target "gameplay-encoder".
 - Add Preprocessor Macro "USE_FBX" to both Debug/Release sections. (Build Settings)
@@ -41,12 +41,11 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
   * Example: libiconv.dylib, Cocoa.framework, SystemConfiguration.framework
 - Build gameplay-encoder
 
-## Binary Format
-The gameplay binary package format is well defined in the gameplay-encoder/gameplay-binary.txt file.
+## Bundle File Format
+The gameplay bundle file format is well defined in the gameplay-encoder/gameplay-bundle.txt file.
 
-## Binary Loading
-Binary package files can easily be loaded using the gameplay/Package.h which is part
-of the GamePlay runtime framework.
+## Bundle File Loading
+Bundle files can easily be loaded using the gameplay/Bundle.h which is part of the gameplay runtime framework.
 
 ## Disclaimer
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 

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

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

+ 2 - 2
gameplay-encoder/gameplay-encoder.xcodeproj/project.pbxproj

@@ -499,7 +499,7 @@
 		42475CF1147208A100610A6A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
 				CLANG_CXX_LIBRARY = "compiler-default";
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";
@@ -531,7 +531,7 @@
 		42475CF2147208A100610A6A /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
 				CLANG_CXX_LIBRARY = "compiler-default";
 				GCC_C_LANGUAGE_STANDARD = "compiler-default";

+ 3 - 3
gameplay-template/gameplay-template.xcodeproj/project.pbxproj

@@ -43,7 +43,7 @@
 
 /* Begin PBXFileReference section */
 		42438B521491AD2000D218B8 /* libgameplay.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgameplay.a; path = "~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug/libgameplay.a"; sourceTree = "<group>"; };
-		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-macosx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-macosx.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-MacOSX.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		42C932C01491A0DB0098216A /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		42C932ED1491A4CB0098216A /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
 		42C932EF1491A5160098216A /* TemplateGame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TemplateGame.cpp; path = src/TemplateGame.cpp; sourceTree = SOURCE_ROOT; };
@@ -427,7 +427,7 @@
 		42C932DB1491A0DB0098216A /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				GCC_PRECOMPILE_PREFIX_HEADER = NO;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;
@@ -453,7 +453,7 @@
 		42C932DC1491A0DB0098216A /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				GCC_PRECOMPILE_PREFIX_HEADER = NO;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
 				GCC_WARN_UNUSED_VARIABLE = NO;

+ 7 - 7
gameplay.sln

@@ -20,7 +20,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample03-character", "gamep
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gameplay-encoder", "gameplay-encoder\gameplay-encoder.vcxproj", "{9D69B743-4872-4DD1-8E30-0087C64298D7}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample04-particles", "gameplay-samples\sample04-particles\sample04-particles.vcxproj", "{F47B5740-3C0C-BACE-4C2B-EE23A358D499}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample04-particles", "gameplay-samples\sample04-particles\sample04-particles.vcxproj", "{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}"
 	ProjectSection(ProjectDependencies) = postProject
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A} = {1032BA4B-57EB-4348-9E03-29DD63E80E4A}
 	EndProjectSection
@@ -67,12 +67,12 @@ Global
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.DebugMem|Win32.Build.0 = Debug|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.ActiveCfg = Release|Win32
 		{9D69B743-4872-4DD1-8E30-0087C64298D7}.Release|Win32.Build.0 = Release|Win32
-		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.Debug|Win32.ActiveCfg = Debug|Win32
-		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.Debug|Win32.Build.0 = Debug|Win32
-		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
-		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.DebugMem|Win32.Build.0 = DebugMem|Win32
-		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.Release|Win32.ActiveCfg = Release|Win32
-		{F47B5740-3C0C-BACE-4C2B-EE23A358D499}.Release|Win32.Build.0 = Release|Win32
+		{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}.Debug|Win32.Build.0 = Debug|Win32
+		{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}.Release|Win32.ActiveCfg = Release|Win32
+		{1D20D446-ED1A-C1A6-21EE-0A973D7DA6E3}.Release|Win32.Build.0 = Release|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
 		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32

+ 1 - 1
gameplay/android/jni/Android.mk

@@ -16,7 +16,7 @@ LOCAL_PATH := $(call my-dir)/../../src
 
 include $(CLEAR_VARS)
 LOCAL_MODULE    := libgameplay
-LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp gameplay-main-qnx.cpp gameplay-main-win32.cpp Image.cpp Joint.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp Package.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsMotionState.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp PlatformQNX.cpp PlatformWin32.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
+LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Bundle.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp Image.cpp Joint.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsMotionState.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
 LOCAL_CFLAGS := -D__ANDROID__ -I"../../external-deps/bullet/include" -I"../../external-deps/libpng/include"
 LOCAL_STATIC_LIBRARIES := android_native_app_glue
 

+ 2 - 3
gameplay/gameplay.vcxproj

@@ -60,7 +60,7 @@
     <ClCompile Include="src\MeshSkin.cpp" />
     <ClCompile Include="src\Model.cpp" />
     <ClCompile Include="src\Node.cpp" />
-    <ClCompile Include="src\Package.cpp" />
+    <ClCompile Include="src\Bundle.cpp" />
     <ClCompile Include="src\ParticleEmitter.cpp" />
     <ClCompile Include="src\PhysicsCharacter.cpp" />
     <ClCompile Include="src\PhysicsCollisionObject.cpp" />
@@ -151,7 +151,7 @@
     <ClInclude Include="src\MeshSkin.h" />
     <ClInclude Include="src\Model.h" />
     <ClInclude Include="src\Node.h" />
-    <ClInclude Include="src\Package.h" />
+    <ClInclude Include="src\Bundle.h" />
     <ClInclude Include="src\ParticleEmitter.h" />
     <ClInclude Include="src\PhysicsCharacter.h" />
     <ClInclude Include="src\PhysicsCollisionObject.h" />
@@ -221,7 +221,6 @@
     <None Include="res\shaders\solid.vsh" />
     <None Include="res\shaders\textured.fsh" />
     <None Include="res\shaders\textured.vsh" />
-    <None Include="res\textures\particle-default.png" />
     <None Include="src\BoundingBox.inl" />
     <None Include="src\BoundingSphere.inl" />
     <None Include="src\Curve.inl" />

+ 6 - 12
gameplay/gameplay.vcxproj.filters

@@ -10,9 +10,6 @@
     <Filter Include="res\shaders">
       <UniqueIdentifier>{be0b36f1-49ed-4a06-9f1f-57c654a554fe}</UniqueIdentifier>
     </Filter>
-    <Filter Include="res\textures">
-      <UniqueIdentifier>{7c4ef2fb-63f2-4d5a-b31e-0dc78329abfd}</UniqueIdentifier>
-    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="src\Animation.cpp">
@@ -75,9 +72,6 @@
     <ClCompile Include="src\Node.cpp">
       <Filter>src</Filter>
     </ClCompile>
-    <ClCompile Include="src\Package.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
     <ClCompile Include="src\Plane.cpp">
       <Filter>src</Filter>
     </ClCompile>
@@ -279,6 +273,9 @@
     <ClCompile Include="src\Layout.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\Bundle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -350,9 +347,6 @@
     <ClInclude Include="src\Node.h">
       <Filter>src</Filter>
     </ClInclude>
-    <ClInclude Include="src\Package.h">
-      <Filter>src</Filter>
-    </ClInclude>
     <ClInclude Include="src\Plane.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -551,6 +545,9 @@
     <ClInclude Include="src\ThemeStyle.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\Bundle.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">
@@ -619,9 +616,6 @@
     <None Include="src\PlatformMacOSX.mm">
       <Filter>src</Filter>
     </None>
-    <None Include="res\textures\particle-default.png">
-      <Filter>res\textures</Filter>
-    </None>
     <None Include="src\Curve.inl">
       <Filter>src</Filter>
     </None>

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

@@ -13,6 +13,10 @@
 		4208DEEA14A4079F00D3C511 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEE714A4079F00D3C511 /* Image.h */; };
 		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
 		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
+		422260D61537790F0011E3AB /* Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 422260D41537790F0011E3AB /* Bundle.cpp */; };
+		422260D71537790F0011E3AB /* Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 422260D41537790F0011E3AB /* Bundle.cpp */; };
+		422260D81537790F0011E3AB /* Bundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 422260D51537790F0011E3AB /* Bundle.h */; };
+		422260D91537790F0011E3AB /* Bundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 422260D51537790F0011E3AB /* Bundle.h */; };
 		4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4234D99D14686C52003031B3 /* Cocoa.framework */; };
 		4251B131152D049B002F6199 /* ScreenDisplayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4251B12E152D049B002F6199 /* ScreenDisplayer.h */; };
 		4251B132152D049B002F6199 /* ScreenDisplayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4251B12E152D049B002F6199 /* ScreenDisplayer.h */; };
@@ -99,8 +103,6 @@
 		42CD0E88147D8FF60000361E /* Model.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF6147D8FF50000361E /* Model.h */; };
 		42CD0E89147D8FF60000361E /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF7147D8FF50000361E /* Node.cpp */; };
 		42CD0E8A147D8FF60000361E /* Node.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF8147D8FF50000361E /* Node.h */; };
-		42CD0E8B147D8FF60000361E /* Package.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF9147D8FF50000361E /* Package.cpp */; };
-		42CD0E8C147D8FF60000361E /* Package.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFA147D8FF50000361E /* Package.h */; };
 		42CD0E8D147D8FF60000361E /* ParticleEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */; };
 		42CD0E8E147D8FF60000361E /* ParticleEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFC147D8FF50000361E /* ParticleEmitter.h */; };
 		42CD0E8F147D8FF60000361E /* Pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFD147D8FF50000361E /* Pass.cpp */; };
@@ -192,7 +194,6 @@
 		5B04C54C14BFCFE100EB0071 /* MeshSkin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF3147D8FF50000361E /* MeshSkin.cpp */; };
 		5B04C54D14BFCFE100EB0071 /* Model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF5147D8FF50000361E /* Model.cpp */; };
 		5B04C54E14BFCFE100EB0071 /* Node.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF7147D8FF50000361E /* Node.cpp */; };
-		5B04C54F14BFCFE100EB0071 /* Package.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DF9147D8FF50000361E /* Package.cpp */; };
 		5B04C55014BFCFE100EB0071 /* ParticleEmitter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */; };
 		5B04C55114BFCFE100EB0071 /* Pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFD147D8FF50000361E /* Pass.cpp */; };
 		5B04C55214BFCFE100EB0071 /* PhysicsConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */; };
@@ -264,7 +265,6 @@
 		5B04C59F14BFCFE100EB0071 /* MeshSkin.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF4147D8FF50000361E /* MeshSkin.h */; };
 		5B04C5A014BFCFE100EB0071 /* Model.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF6147D8FF50000361E /* Model.h */; };
 		5B04C5A114BFCFE100EB0071 /* Node.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DF8147D8FF50000361E /* Node.h */; };
-		5B04C5A214BFCFE100EB0071 /* Package.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFA147D8FF50000361E /* Package.h */; };
 		5B04C5A314BFCFE100EB0071 /* ParticleEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFC147D8FF50000361E /* ParticleEmitter.h */; };
 		5B04C5A414BFCFE100EB0071 /* Pass.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0DFE147D8FF50000361E /* Pass.h */; };
 		5B04C5A514BFCFE100EB0071 /* PhysicsConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E00147D8FF50000361E /* PhysicsConstraint.h */; };
@@ -391,6 +391,8 @@
 		4208DEE814A4079F00D3C511 /* Image.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Image.inl; path = src/Image.inl; sourceTree = SOURCE_ROOT; };
 		4208DEEB14A407B900D3C511 /* Keyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Keyboard.h; path = src/Keyboard.h; sourceTree = SOURCE_ROOT; };
 		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.h; sourceTree = SOURCE_ROOT; };
+		422260D41537790F0011E3AB /* Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Bundle.cpp; path = src/Bundle.cpp; sourceTree = SOURCE_ROOT; };
+		422260D51537790F0011E3AB /* Bundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Bundle.h; path = src/Bundle.h; sourceTree = SOURCE_ROOT; };
 		4234D99A14686C52003031B3 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4234D99D14686C52003031B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		4251B12E152D049B002F6199 /* ScreenDisplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenDisplayer.h; path = src/ScreenDisplayer.h; sourceTree = SOURCE_ROOT; };
@@ -478,8 +480,6 @@
 		42CD0DF6147D8FF50000361E /* Model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Model.h; path = src/Model.h; sourceTree = SOURCE_ROOT; };
 		42CD0DF7147D8FF50000361E /* Node.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Node.cpp; path = src/Node.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DF8147D8FF50000361E /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Node.h; path = src/Node.h; sourceTree = SOURCE_ROOT; };
-		42CD0DF9147D8FF50000361E /* Package.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Package.cpp; path = src/Package.cpp; sourceTree = SOURCE_ROOT; };
-		42CD0DFA147D8FF50000361E /* Package.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Package.h; path = src/Package.h; sourceTree = SOURCE_ROOT; };
 		42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ParticleEmitter.cpp; path = src/ParticleEmitter.cpp; sourceTree = SOURCE_ROOT; };
 		42CD0DFC147D8FF50000361E /* ParticleEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ParticleEmitter.h; path = src/ParticleEmitter.h; sourceTree = SOURCE_ROOT; };
 		42CD0DFD147D8FF50000361E /* Pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Pass.cpp; path = src/Pass.cpp; sourceTree = SOURCE_ROOT; };
@@ -707,6 +707,8 @@
 				42CD0DC7147D8FF50000361E /* BoundingSphere.cpp */,
 				42CD0DC8147D8FF50000361E /* BoundingSphere.h */,
 				42CD0DC9147D8FF50000361E /* BoundingSphere.inl */,
+				422260D41537790F0011E3AB /* Bundle.cpp */,
+				422260D51537790F0011E3AB /* Bundle.h */,
 				5BD52636150F822A004C9099 /* Button.cpp */,
 				5BD52637150F822A004C9099 /* Button.h */,
 				42CD0DCA147D8FF50000361E /* Camera.cpp */,
@@ -779,8 +781,6 @@
 				5BB0823C14C6FEC40019975F /* Mouse.h */,
 				42CD0DF7147D8FF50000361E /* Node.cpp */,
 				42CD0DF8147D8FF50000361E /* Node.h */,
-				42CD0DF9147D8FF50000361E /* Package.cpp */,
-				42CD0DFA147D8FF50000361E /* Package.h */,
 				42CD0DFB147D8FF50000361E /* ParticleEmitter.cpp */,
 				42CD0DFC147D8FF50000361E /* ParticleEmitter.h */,
 				42CD0DFD147D8FF50000361E /* Pass.cpp */,
@@ -998,7 +998,6 @@
 				42CD0E86147D8FF60000361E /* MeshSkin.h in Headers */,
 				42CD0E88147D8FF60000361E /* Model.h in Headers */,
 				42CD0E8A147D8FF60000361E /* Node.h in Headers */,
-				42CD0E8C147D8FF60000361E /* Package.h in Headers */,
 				42CD0E8E147D8FF60000361E /* ParticleEmitter.h in Headers */,
 				42CD0E90147D8FF60000361E /* Pass.h in Headers */,
 				42CD0E92147D8FF60000361E /* PhysicsConstraint.h in Headers */,
@@ -1055,6 +1054,7 @@
 				42554EA3152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
 				4251B131152D049B002F6199 /* ScreenDisplayer.h in Headers */,
 				4251B135152D049B002F6199 /* ThemeStyle.h in Headers */,
+				422260D81537790F0011E3AB /* Bundle.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1095,7 +1095,6 @@
 				5B04C59F14BFCFE100EB0071 /* MeshSkin.h in Headers */,
 				5B04C5A014BFCFE100EB0071 /* Model.h in Headers */,
 				5B04C5A114BFCFE100EB0071 /* Node.h in Headers */,
-				5B04C5A214BFCFE100EB0071 /* Package.h in Headers */,
 				5B04C5A314BFCFE100EB0071 /* ParticleEmitter.h in Headers */,
 				5B04C5A414BFCFE100EB0071 /* Pass.h in Headers */,
 				5B04C5A514BFCFE100EB0071 /* PhysicsConstraint.h in Headers */,
@@ -1151,6 +1150,7 @@
 				42554EA4152BC35C000ED910 /* PhysicsCollisionShape.h in Headers */,
 				4251B132152D049B002F6199 /* ScreenDisplayer.h in Headers */,
 				4251B136152D049B002F6199 /* ThemeStyle.h in Headers */,
+				422260D91537790F0011E3AB /* Bundle.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1254,7 +1254,6 @@
 				42CD0E85147D8FF60000361E /* MeshSkin.cpp in Sources */,
 				42CD0E87147D8FF60000361E /* Model.cpp in Sources */,
 				42CD0E89147D8FF60000361E /* Node.cpp in Sources */,
-				42CD0E8B147D8FF60000361E /* Package.cpp in Sources */,
 				42CD0E8D147D8FF60000361E /* ParticleEmitter.cpp in Sources */,
 				42CD0E8F147D8FF60000361E /* Pass.cpp in Sources */,
 				42CD0E91147D8FF60000361E /* PhysicsConstraint.cpp in Sources */,
@@ -1306,6 +1305,7 @@
 				42554EA1152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 				4251B133152D049B002F6199 /* ThemeStyle.cpp in Sources */,
 				4271C08E15337C8200B89DA7 /* Layout.cpp in Sources */,
+				422260D61537790F0011E3AB /* Bundle.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1344,7 +1344,6 @@
 				5B04C54C14BFCFE100EB0071 /* MeshSkin.cpp in Sources */,
 				5B04C54D14BFCFE100EB0071 /* Model.cpp in Sources */,
 				5B04C54E14BFCFE100EB0071 /* Node.cpp in Sources */,
-				5B04C54F14BFCFE100EB0071 /* Package.cpp in Sources */,
 				5B04C55014BFCFE100EB0071 /* ParticleEmitter.cpp in Sources */,
 				5B04C55114BFCFE100EB0071 /* Pass.cpp in Sources */,
 				5B04C55214BFCFE100EB0071 /* PhysicsConstraint.cpp in Sources */,
@@ -1397,6 +1396,7 @@
 				42554EA2152BC35C000ED910 /* PhysicsCollisionShape.cpp in Sources */,
 				4251B134152D049B002F6199 /* ThemeStyle.cpp in Sources */,
 				4271C08F15337C8200B89DA7 /* Layout.cpp in Sources */,
+				422260D71537790F0011E3AB /* Bundle.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1426,7 +1426,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				COPY_PHASE_STRIP = NO;
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";
 				GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -1474,7 +1474,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
-				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
 				COPY_PHASE_STRIP = YES;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				FRAMEWORK_SEARCH_PATHS = "$(inherited)";

+ 1 - 1
gameplay/src/AbsoluteLayout.h

@@ -29,7 +29,7 @@ protected:
     /**
      * Create an AbsoluteLayout.
      *
-     * @return an AbsoluteLayout object.
+     * @return An AbsoluteLayout object.
      */
     static AbsoluteLayout* create();
 

+ 28 - 1
gameplay/src/Animation.cpp

@@ -19,12 +19,18 @@ Animation::Animation(const char* id, AnimationTarget* target, int propertyId, un
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
+    // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
+    release();
+    assert(getRefCount() == 1);
 }
 
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, unsigned int type)
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0), _defaultClip(NULL), _clips(NULL)
 {
     createChannel(target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
+    // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
+    release();
+    assert(getRefCount() == 1);
 }
 
 Animation::Animation(const char* id)
@@ -67,6 +73,7 @@ Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int p
     assert(_target->getAnimationPropertyComponentCount(propertyId));
     _curve->addRef();
     _target->addChannel(this);
+    _animation->addRef();
 }
 
 Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
@@ -74,6 +81,7 @@ Animation::Channel::Channel(const Channel& copy, Animation* animation, Animation
 {
     _curve->addRef();
     _target->addChannel(this);
+    _animation->addRef();
 }
 
 Animation::Channel::~Channel()
@@ -138,6 +146,19 @@ AnimationClip* Animation::getClip(const char* id)
     }
 }
 
+AnimationClip* Animation::getClip(unsigned int index) const
+{
+    if (_clips)
+        return _clips->at(index);
+
+    return NULL;
+}
+
+unsigned int Animation::getClipCount() const
+{
+    return _clips ? _clips->size() : 0;
+}
+
 void Animation::play(const char* clipId)
 {
     // If id is NULL, play the default clip.
@@ -388,9 +409,15 @@ void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId
     return;
 }
 
-Animation* Animation::clone()
+Animation* Animation::clone(Channel* channel, AnimationTarget* target)
 {
     Animation* animation = new Animation(getId());
+
+    Animation::Channel* channelCopy = new Animation::Channel(*channel, animation, target);
+    animation->addChannel(channelCopy);
+    // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
+    animation->release();
+    assert(animation->getRefCount() == 1);
     return animation;
 }
 

+ 17 - 2
gameplay/src/Animation.h

@@ -24,7 +24,7 @@ class Animation : public Ref
 {
     friend class AnimationClip;
     friend class AnimationTarget;
-    friend class Package;
+    friend class Bundle;
 
 public:
     
@@ -66,6 +66,18 @@ public:
      * @return The AnimationClip with the specified ID; NULL if an AnimationClip with the given ID is not found.
      */
     AnimationClip* getClip(const char* clipId = NULL);
+
+    /**
+     * Returns the AnimationClip at the given index.
+     *
+     * @param index Index of the clip to return.
+     */
+    AnimationClip* getClip(unsigned int index) const;
+
+    /**
+     * Returns the number of animation clips in this animation.
+     */
+    unsigned int getClipCount() const;
     
     /**
      * Plays the AnimationClip with the specified name. 
@@ -201,9 +213,12 @@ private:
     /**
      * Clones this animation.
      * 
+     * @param channel The channel to clone and add to the animation.
+     * @param target The target of the animation.
+     * 
      * @return The newly created animation.
      */
-    Animation* clone();
+    Animation* clone(Channel* channel, AnimationTarget* target);
     
     AnimationController* _controller;       // The AnimationController that this Animation will run on.
     std::string _id;                        // The Animation's ID.

+ 9 - 12
gameplay/src/AnimationTarget.cpp

@@ -397,21 +397,18 @@ void AnimationTarget::cloneInto(AnimationTarget* target, NodeCloneContext &conte
             Animation::Channel* channel = *it;
             assert(channel->_animation);
 
-            bool animationCloned = false;
-
-            // Don't clone the Animaton if it is already in the clone context.
             Animation* animation = context.findClonedAnimation(channel->_animation);
-            if (animation == NULL)
+            if (animation != NULL)
             {
-                animation = channel->_animation->clone();
-                animationCloned = true;
+                Animation::Channel* channelCopy = new Animation::Channel(*channel, animation, target);
+                animation->addChannel(channelCopy);
+            }
+            else
+            {
+                // Clone the animation and register it with the context so that it only gets cloned once.
+                animation = channel->_animation->clone(channel, target);
+                context.registerClonedAnimation(channel->_animation, animation);
             }
-            assert(animation);
-
-            context.registerClonedAnimation(channel->_animation, animation);
-            
-            Animation::Channel* channelCopy = new Animation::Channel(*channel, animation, target);
-            animation->addChannel(channelCopy);
         }
     }
 }

+ 118 - 119
gameplay/src/Package.cpp → gameplay/src/Bundle.cpp

@@ -1,50 +1,50 @@
 #include "Base.h"
-#include "Package.h"
+#include "Bundle.h"
 #include "FileSystem.h"
 #include "MeshPart.h"
 #include "Scene.h"
 #include "Joint.h"
 
-#define GPB_PACKAGE_VERSION_MAJOR 1
-#define GPB_PACKAGE_VERSION_MINOR 1
-
-#define PACKAGE_TYPE_SCENE 1
-#define PACKAGE_TYPE_NODE 2
-#define PACKAGE_TYPE_ANIMATIONS 3
-#define PACKAGE_TYPE_ANIMATION 4
-#define PACKAGE_TYPE_ANIMATION_CHANNEL 5
-#define PACKAGE_TYPE_MMODEL 10
-#define PACKAGE_TYPE_MATERIAL 16
-#define PACKAGE_TYPE_EFFECT 18
-#define PACKAGE_TYPE_CAMERA 32
-#define PACKAGE_TYPE_LIGHT 33
-#define PACKAGE_TYPE_MESH 34
-#define PACKAGE_TYPE_MESHPART 35
-#define PACKAGE_TYPE_MESHSKIN 36
-#define PACKAGE_TYPE_FONT 128
+#define BUNDLE_VERSION_MAJOR            1
+#define BUNDLE_VERSION_MINOR            1
+
+#define BUNDLE_TYPE_SCENE               1
+#define BUNDLE_TYPE_NODE                2
+#define BUNDLE_TYPE_ANIMATIONS          3
+#define BUNDLE_TYPE_ANIMATION           4
+#define BUNDLE_TYPE_ANIMATION_CHANNEL   5
+#define BUNDLE_TYPE_MODEL               10
+#define BUNDLE_TYPE_MATERIAL            16
+#define BUNDLE_TYPE_EFFECT              18
+#define BUNDLE_TYPE_CAMERA              32
+#define BUNDLE_TYPE_LIGHT               33
+#define BUNDLE_TYPE_MESH                34
+#define BUNDLE_TYPE_MESHPART            35
+#define BUNDLE_TYPE_MESHSKIN            36
+#define BUNDLE_TYPE_FONT                128
 
 // For sanity checking string reads
-#define PACKAGE_MAX_STRING_LENGTH 5000
+#define BUNDLE_MAX_STRING_LENGTH        5000
 
 namespace gameplay
 {
 
-static std::vector<Package*> __packageCache;
+static std::vector<Bundle*> __bundleCache;
 
-Package::Package(const char* path) :
+Bundle::Bundle(const char* path) :
     _path(path), _referenceCount(0), _references(NULL), _file(NULL)
 {
 }
 
-Package::~Package()
+Bundle::~Bundle()
 {
     clearLoadSession();
 
-    // Remove this Package from the cache
-    std::vector<Package*>::iterator itr = std::find(__packageCache.begin(), __packageCache.end(), this);
-    if (itr != __packageCache.end())
+    // Remove this Bundle from the cache
+    std::vector<Bundle*>::iterator itr = std::find(__bundleCache.begin(), __bundleCache.end(), this);
+    if (itr != __bundleCache.end())
     {
-        __packageCache.erase(itr);
+        __bundleCache.erase(itr);
     }
 
     SAFE_DELETE_ARRAY(_references);
@@ -57,7 +57,7 @@ Package::~Package()
 }
 
 template <class T>
-bool Package::readArray(unsigned int* length, T** ptr)
+bool Bundle::readArray(unsigned int* length, T** ptr)
 {
     if (!read(length))
     {
@@ -76,7 +76,7 @@ bool Package::readArray(unsigned int* length, T** ptr)
 }
 
 template <class T>
-bool Package::readArray(unsigned int* length, std::vector<T>* values)
+bool Bundle::readArray(unsigned int* length, std::vector<T>* values)
 {
     if (!read(length))
     {
@@ -94,7 +94,7 @@ bool Package::readArray(unsigned int* length, std::vector<T>* values)
 }
 
 template <class T>
-bool Package::readArray(unsigned int* length, std::vector<T>* values, unsigned int readSize)
+bool Bundle::readArray(unsigned int* length, std::vector<T>* values, unsigned int readSize)
 {
     assert(sizeof(T) >= readSize);
 
@@ -122,7 +122,7 @@ std::string readString(FILE* fp)
     }
 
     // Sanity check to detect if string length is far too big
-    assert(length < PACKAGE_MAX_STRING_LENGTH);
+    assert(length < BUNDLE_MAX_STRING_LENGTH);
 
     std::string str;
     if (length > 0)
@@ -136,12 +136,12 @@ std::string readString(FILE* fp)
     return str;
 }
 
-Package* Package::create(const char* path)
+Bundle* Bundle::create(const char* path)
 {
-    // Search the cache for this package
-    for (unsigned int i = 0, count = __packageCache.size(); i < count; ++i)
+    // Search the cache for this bundle
+    for (unsigned int i = 0, count = __bundleCache.size(); i < count; ++i)
     {
-        Package* p = __packageCache[i];
+        Bundle* p = __bundleCache[i];
         if (p->_path == path)
         {
             // Found a match
@@ -150,7 +150,7 @@ Package* Package::create(const char* path)
         }
     }
 
-    // Open the package
+    // Open the bundle
     FILE* fp = FileSystem::openFile(path, "rb");
     if (!fp)
     {
@@ -162,16 +162,16 @@ Package* Package::create(const char* path)
     char sig[9];
     if (fread(sig, 1, 9, fp) != 9 || memcmp(sig, "«GPB»\r\n\x1A\n", 9) != 0)
     {
-        LOG_ERROR_VARG("Invalid package header: %s", path);
+        LOG_ERROR_VARG("Invalid bundle header: %s", path);
         fclose(fp);
         return NULL;
     }
 
     // Read version
     unsigned char ver[2];
-    if (fread(ver, 1, 2, fp) != 2 || ver[0] != GPB_PACKAGE_VERSION_MAJOR || ver[1] != GPB_PACKAGE_VERSION_MINOR)
+    if (fread(ver, 1, 2, fp) != 2 || ver[0] != BUNDLE_VERSION_MAJOR || ver[1] != BUNDLE_VERSION_MINOR)
     {
-        LOG_ERROR_VARG("Unsupported version (%d.%d) for package: %s (expected %d.%d)", (int)ver[0], (int)ver[1], path, GPB_PACKAGE_VERSION_MAJOR, GPB_PACKAGE_VERSION_MINOR);
+        LOG_ERROR_VARG("Unsupported version (%d.%d) for bundle: %s (expected %d.%d)", (int)ver[0], (int)ver[1], path, BUNDLE_VERSION_MAJOR, BUNDLE_VERSION_MINOR);
         fclose(fp);
         return NULL;
     }
@@ -199,15 +199,15 @@ Package* Package::create(const char* path)
     }
 
     // Keep file open for faster reading later
-    Package* pkg = new Package(path);
-    pkg->_referenceCount = refCount;
-    pkg->_references = refs;
-    pkg->_file = fp;
+    Bundle* bundle = new Bundle(path);
+    bundle->_referenceCount = refCount;
+    bundle->_references = refs;
+    bundle->_file = fp;
 
-    return pkg;
+    return bundle;
 }
 
-Package::Reference* Package::find(const char* id) const
+Bundle::Reference* Bundle::find(const char* id) const
 {
     // Search the ref table for the given id (case-sensitive)
     for (unsigned int i = 0; i < _referenceCount; ++i)
@@ -222,7 +222,7 @@ Package::Reference* Package::find(const char* id) const
     return NULL;
 }
 
-void Package::clearLoadSession()
+void Bundle::clearLoadSession()
 {
     for (unsigned int i = 0, count = _meshSkins.size(); i < count; ++i)
     {
@@ -231,12 +231,12 @@ void Package::clearLoadSession()
     _meshSkins.clear();
 }
 
-const char* Package::getIdFromOffset() const
+const char* Bundle::getIdFromOffset() const
 {
     return getIdFromOffset((unsigned int) ftell(_file));
 }
 
-const char* Package::getIdFromOffset(unsigned int offset) const
+const char* Bundle::getIdFromOffset(unsigned int offset) const
 {
     // Search the ref table for the given offset
     if (offset > 0)
@@ -252,32 +252,32 @@ const char* Package::getIdFromOffset(unsigned int offset) const
     return NULL;
 }
 
-Package::Reference* Package::seekTo(const char* id, unsigned int type)
+Bundle::Reference* Bundle::seekTo(const char* id, unsigned int type)
 {
     Reference* ref = find(id);
     if (ref == NULL)
     {
-        LOG_ERROR_VARG("No object with name '%s' in package '%s'.", id, _path.c_str());
+        LOG_ERROR_VARG("No object with name '%s' in bundle '%s'.", id, _path.c_str());
         return NULL;
     }
 
     if (ref->type != type)
     {
-        LOG_ERROR_VARG("Object '%s' in package '%s' has type %d (expected type %d).", id, _path.c_str(), (int)ref->type, (int)type);
+        LOG_ERROR_VARG("Object '%s' in bundle '%s' has type %d (expected type %d).", id, _path.c_str(), (int)ref->type, (int)type);
         return NULL;
     }
 
     // Seek to the offset of this object
     if (fseek(_file, ref->offset, SEEK_SET) != 0)
     {
-        LOG_ERROR_VARG("Failed to seek to object '%s' in package '%s'.", id, _path.c_str());
+        LOG_ERROR_VARG("Failed to seek to object '%s' in bundle '%s'.", id, _path.c_str());
         return NULL;
     }
 
     return ref;
 }
 
-Package::Reference* Package::seekToFirstType(unsigned int type)
+Bundle::Reference* Bundle::seekToFirstType(unsigned int type)
 {
     // for each Reference
     for (unsigned int i = 0; i < _referenceCount; ++i)
@@ -288,7 +288,7 @@ Package::Reference* Package::seekToFirstType(unsigned int type)
             // Found a match
             if (fseek(_file, ref->offset, SEEK_SET) != 0)
             {
-                LOG_ERROR_VARG("Failed to seek to object '%s' in package '%s'.", ref->id.c_str(), _path.c_str());
+                LOG_ERROR_VARG("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 return NULL;
             }
             return ref;
@@ -297,38 +297,38 @@ Package::Reference* Package::seekToFirstType(unsigned int type)
     return NULL;
 }
 
-bool Package::read(unsigned int* ptr)
+bool Bundle::read(unsigned int* ptr)
 {
     return fread(ptr, sizeof(unsigned int), 1, _file) == 1;
 }
 
-bool Package::read(unsigned char* ptr)
+bool Bundle::read(unsigned char* ptr)
 {
     return fread(ptr, sizeof(unsigned char), 1, _file) == 1;
 }
 
-bool Package::read(float* ptr)
+bool Bundle::read(float* ptr)
 {
     return fread(ptr, sizeof(float), 1, _file) == 1;
 }
 
-bool Package::readMatrix(float* m)
+bool Bundle::readMatrix(float* m)
 {
     return (fread(m, sizeof(float), 16, _file) == 16);
 }
 
-Scene* Package::loadScene(const char* id)
+Scene* Bundle::loadScene(const char* id)
 {
     clearLoadSession();
 
     Reference* ref = NULL;
     if (id)
     {
-        ref = seekTo(id, PACKAGE_TYPE_SCENE);
+        ref = seekTo(id, BUNDLE_TYPE_SCENE);
     }
     else
     {
-        ref = seekToFirstType(PACKAGE_TYPE_SCENE);
+        ref = seekToFirstType(BUNDLE_TYPE_SCENE);
     }
     if (!ref)
     {
@@ -393,12 +393,12 @@ Scene* Package::loadScene(const char* id)
     for (unsigned int i = 0; i < _referenceCount; ++i)
     {
         Reference* ref = &_references[i];
-        if (ref->type == PACKAGE_TYPE_ANIMATIONS)
+        if (ref->type == BUNDLE_TYPE_ANIMATIONS)
         {
             // Found a match
             if (fseek(_file, ref->offset, SEEK_SET) != 0)
             {
-                LOG_ERROR_VARG("Failed to seek to object '%s' in package '%s'.", ref->id.c_str(), _path.c_str());
+                LOG_ERROR_VARG("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 return NULL;
             }
             readAnimations(scene);
@@ -410,7 +410,7 @@ Scene* Package::loadScene(const char* id)
     return scene;
 }
 
-Node* Package::loadNode(const char* id)
+Node* Bundle::loadNode(const char* id)
 {
     assert(id);
 
@@ -426,7 +426,7 @@ Node* Package::loadNode(const char* id)
     return node;
 }
 
-Node* Package::loadNode(const char* id, Scene* sceneContext, Node* nodeContext)
+Node* Bundle::loadNode(const char* id, Scene* sceneContext, Node* nodeContext)
 {
     assert(id);
 
@@ -446,7 +446,7 @@ Node* Package::loadNode(const char* id, Scene* sceneContext, Node* nodeContext)
     if (node == NULL)
     {
         // If not yet found, search the ref table and read
-        Reference* ref = seekTo(id, PACKAGE_TYPE_NODE);
+        Reference* ref = seekTo(id, BUNDLE_TYPE_NODE);
         if (ref == NULL)
         {
             return NULL;
@@ -458,7 +458,7 @@ Node* Package::loadNode(const char* id, Scene* sceneContext, Node* nodeContext)
     return node;
 }
 
-Node* Package::readNode(Scene* sceneContext, Node* nodeContext)
+Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
 {
     const char* id = getIdFromOffset();
 
@@ -545,12 +545,12 @@ Node* Package::readNode(Scene* sceneContext, Node* nodeContext)
     return node;
 }
 
-Camera* Package::readCamera()
+Camera* Bundle::readCamera()
 {
     unsigned char cameraType;
     if (!read(&cameraType))
     {
-        LOG_ERROR_VARG("Failed to load camera type in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load camera type in bundle '%s'.", _path.c_str());
     }
 
     if (cameraType == 0)
@@ -562,21 +562,21 @@ Camera* Package::readCamera()
     float aspectRatio;
     if (!read(&aspectRatio))
     {
-        LOG_ERROR_VARG("Failed to load camera aspectRatio in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load camera aspectRatio in bundle '%s'.", _path.c_str());
     }
 
     // near plane
     float nearPlane;
     if (!read(&nearPlane))
     {
-        LOG_ERROR_VARG("Failed to load camera near plane in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load camera near plane in bundle '%s'.", _path.c_str());
     }
 
     // far plane
     float farPlane;
     if (!read(&farPlane))
     {
-        LOG_ERROR_VARG("Failed to load camera far plane in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load camera far plane in bundle '%s'.", _path.c_str());
     }
 
     Camera* camera = NULL;
@@ -586,7 +586,7 @@ Camera* Package::readCamera()
         float fieldOfView;
         if (!read(&fieldOfView))
         {
-            LOG_ERROR_VARG("Failed to load camera field of view in package '%s'.", _path.c_str());
+            LOG_ERROR_VARG("Failed to load camera field of view in bundle '%s'.", _path.c_str());
         }
 
         camera = Camera::createPerspective(fieldOfView, aspectRatio, nearPlane, farPlane);
@@ -597,30 +597,30 @@ Camera* Package::readCamera()
         float zoomX;
         if (!read(&zoomX))
         {
-            LOG_ERROR_VARG("Failed to load camera zoomX in package '%s'.", _path.c_str());
+            LOG_ERROR_VARG("Failed to load camera zoomX in bundle '%s'.", _path.c_str());
         }
 
         float zoomY;
         if (!read(&zoomY))
         {
-            LOG_ERROR_VARG("Failed to load camera zoomY in package '%s'.", _path.c_str());
+            LOG_ERROR_VARG("Failed to load camera zoomY in bundle '%s'.", _path.c_str());
         }
 
         camera = Camera::createOrthographic(zoomX, zoomY, aspectRatio, nearPlane, farPlane);
     }
     else
     {
-        LOG_ERROR_VARG("Failed to load camera type in package '%s'. Invalid camera type.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load camera type in bundle '%s'. Invalid camera type.", _path.c_str());
     }
     return camera;
 }
 
-Light* Package::readLight()
+Light* Bundle::readLight()
 {
     unsigned char type;
     if (!read(&type))
     {
-        LOG_ERROR_VARG("Failed to load light %s in package '%s'.", "type", _path.c_str());
+        LOG_ERROR_VARG("Failed to load light %s in bundle '%s'.", "type", _path.c_str());
     }
 
     if (type == 0)
@@ -632,7 +632,7 @@ Light* Package::readLight()
     float red, blue, green;
     if (!read(&red) || !read(&blue) || !read(&green))
     {
-        LOG_ERROR_VARG("Failed to load light %s in package '%s'.", "color", _path.c_str());
+        LOG_ERROR_VARG("Failed to load light %s in bundle '%s'.", "color", _path.c_str());
     }
     Vector3 color(red, blue, green);
 
@@ -646,7 +646,7 @@ Light* Package::readLight()
         float range;
         if (!read(&range))
         {
-            LOG_ERROR_VARG("Failed to load point light %s in package '%s'.", "point", _path.c_str());
+            LOG_ERROR_VARG("Failed to load point light %s in bundle '%s'.", "point", _path.c_str());
         }
         light = Light::createPoint(color, range);
     }
@@ -655,18 +655,18 @@ Light* Package::readLight()
         float range, innerAngle, outerAngle;
         if (!read(&range) || !read(&innerAngle) || !read(&outerAngle))
         {
-            LOG_ERROR_VARG("Failed to load spot light %s in package '%s'.", "spot", _path.c_str());
+            LOG_ERROR_VARG("Failed to load spot light %s in bundle '%s'.", "spot", _path.c_str());
         }
         light = Light::createSpot(color, range, innerAngle, outerAngle);
     }
     else
     {
-        LOG_ERROR_VARG("Failed to load light %s in package '%s'.", "type", _path.c_str());
+        LOG_ERROR_VARG("Failed to load light %s in bundle '%s'.", "type", _path.c_str());
     }
     return light;
 }
 
-Model* Package::readModel(Scene* sceneContext, Node* nodeContext, const char* nodeId)
+Model* Bundle::readModel(Scene* sceneContext, Node* nodeContext, const char* nodeId)
 {
     // Read mesh
     Mesh* mesh = NULL;
@@ -683,7 +683,7 @@ Model* Package::readModel(Scene* sceneContext, Node* nodeContext, const char* no
             unsigned char hasSkin;
             if (!read(&hasSkin))
             {
-                LOG_ERROR_VARG("Failed to load hasSkin in package '%s'.", _path.c_str());
+                LOG_ERROR_VARG("Failed to load hasSkin in bundle '%s'.", _path.c_str());
                 return NULL;
             }
             if (hasSkin)
@@ -698,7 +698,7 @@ Model* Package::readModel(Scene* sceneContext, Node* nodeContext, const char* no
             unsigned int materialCount;
             if (!read(&materialCount))
             {
-                LOG_ERROR_VARG("Failed to load materialCount in package '%s'.", _path.c_str());
+                LOG_ERROR_VARG("Failed to load materialCount in bundle '%s'.", _path.c_str());
                 return NULL;
             }
             if (materialCount > 0)
@@ -712,7 +712,7 @@ Model* Package::readModel(Scene* sceneContext, Node* nodeContext, const char* no
     return NULL;
 }
 
-MeshSkin* Package::readMeshSkin(Scene* sceneContext, Node* nodeContext)
+MeshSkin* Bundle::readMeshSkin(Scene* sceneContext, Node* nodeContext)
 {
     MeshSkin* meshSkin = new MeshSkin();
 
@@ -720,7 +720,7 @@ MeshSkin* Package::readMeshSkin(Scene* sceneContext, Node* nodeContext)
     float bindShape[16];
     if (!readMatrix(bindShape))
     {
-        LOG_ERROR_VARG("Failed to load MeshSkin in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load MeshSkin in bundle '%s'.", _path.c_str());
         SAFE_DELETE(meshSkin);
         return NULL;
     }
@@ -733,7 +733,7 @@ MeshSkin* Package::readMeshSkin(Scene* sceneContext, Node* nodeContext)
     unsigned int jointCount;
     if (!read(&jointCount))
     {
-        LOG_ERROR_VARG("Failed to load MeshSkin in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load MeshSkin in bundle '%s'.", _path.c_str());
         SAFE_DELETE(meshSkin);
         SAFE_DELETE(skinData);
         return NULL;
@@ -756,7 +756,7 @@ MeshSkin* Package::readMeshSkin(Scene* sceneContext, Node* nodeContext)
     unsigned int jointsBindPosesCount;
     if (!read(&jointsBindPosesCount))
     {
-        LOG_ERROR_VARG("Failed to load MeshSkin in package '%s'.", _path.c_str());
+        LOG_ERROR_VARG("Failed to load MeshSkin in bundle '%s'.", _path.c_str());
         SAFE_DELETE(meshSkin);
         SAFE_DELETE(skinData);
         return NULL;
@@ -769,7 +769,7 @@ MeshSkin* Package::readMeshSkin(Scene* sceneContext, Node* nodeContext)
         {
             if (!readMatrix(m))
             {
-                LOG_ERROR_VARG("Failed to load MeshSkin in package '%s'.", _path.c_str());
+                LOG_ERROR_VARG("Failed to load MeshSkin in bundle '%s'.", _path.c_str());
                 SAFE_DELETE(meshSkin);
                 SAFE_DELETE(skinData);
                 return NULL;
@@ -784,7 +784,7 @@ MeshSkin* Package::readMeshSkin(Scene* sceneContext, Node* nodeContext)
     return meshSkin;
 }
 
-void Package::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
+void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
 {
     const unsigned int skinCount = _meshSkins.size();
     for (unsigned int i = 0; i < skinCount; ++i)
@@ -834,7 +834,7 @@ void Package::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
     _meshSkins.clear();
 }
 
-void Package::readAnimation(Scene* scene)
+void Bundle::readAnimation(Scene* scene)
 {
     const std::string animationId = readString(_file);
 
@@ -854,7 +854,7 @@ void Package::readAnimation(Scene* scene)
     }
 }
 
-void Package::readAnimations(Scene* scene)
+void Bundle::readAnimations(Scene* scene)
 {
     // read the number of animations in this object
     unsigned int animationCount;
@@ -870,7 +870,7 @@ void Package::readAnimations(Scene* scene)
     }
 }
 
-Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, const char* animationId)
+Animation* Bundle::readAnimationChannel(Scene* scene, Animation* animation, const char* animationId)
 {
     const char* id = animationId;
 
@@ -969,25 +969,24 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
         else
         {
             animation->createChannel(target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
-            animation->addRef();
         }
     }
 
     return animation;
 }
 
-Mesh* Package::loadMesh(const char* id)
+Mesh* Bundle::loadMesh(const char* id)
 {
     return loadMesh(id, false);
 }
 
-Mesh* Package::loadMesh(const char* id, const char* nodeId)
+Mesh* Bundle::loadMesh(const char* id, const char* nodeId)
 {
     // Save the file position
     long position = ftell(_file);
 
     // Seek to the specified Mesh
-    Reference* ref = seekTo(id, PACKAGE_TYPE_MESH);
+    Reference* ref = seekTo(id, BUNDLE_TYPE_MESH);
     if (ref == NULL)
     {
         return NULL;
@@ -1041,7 +1040,7 @@ Mesh* Package::loadMesh(const char* id, const char* nodeId)
     return mesh;
 }
 
-Package::MeshData* Package::readMeshData()
+Bundle::MeshData* Bundle::readMeshData()
 {
     // Read vertex format/elements
     unsigned int vertexElementCount;
@@ -1146,7 +1145,7 @@ Package::MeshData* Package::readMeshData()
     return meshData;
 }
 
-Package::MeshData* Package::readMeshData(const char* url)
+Bundle::MeshData* Bundle::readMeshData(const char* url)
 {
     assert(url);
 
@@ -1154,7 +1153,7 @@ Package::MeshData* Package::readMeshData(const char* url)
     if (len == 0)
         return NULL;
 
-    // Parse URL (formatted as 'package#id')
+    // Parse URL (formatted as 'bundle#id')
     std::string urlstring(url);
     unsigned int pos = urlstring.find('#');
     if (pos == std::string::npos)
@@ -1163,28 +1162,28 @@ Package::MeshData* Package::readMeshData(const char* url)
     std::string file = urlstring.substr(0, pos);
     std::string id = urlstring.substr(pos + 1);
 
-    // Load package
-    Package* pkg = Package::create(file.c_str());
-    if (pkg == NULL)
+    // Load bundle
+    Bundle* bundle = Bundle::create(file.c_str());
+    if (bundle == NULL)
         return NULL;
 
-    // Seek to mesh with specified ID in package
-    Reference* ref = pkg->seekTo(id.c_str(), PACKAGE_TYPE_MESH);
+    // Seek to mesh with specified ID in bundle
+    Reference* ref = bundle->seekTo(id.c_str(), BUNDLE_TYPE_MESH);
     if (ref == NULL)
         return NULL;
 
     // Read mesh data from current file position
-    MeshData* meshData = pkg->readMeshData();
+    MeshData* meshData = bundle->readMeshData();
 
-    SAFE_RELEASE(pkg);
+    SAFE_RELEASE(bundle);
 
     return meshData;
 }
 
-Font* Package::loadFont(const char* id)
+Font* Bundle::loadFont(const char* id)
 {
     // Seek to the specified Font
-    Reference* ref = seekTo(id, PACKAGE_TYPE_FONT);
+    Reference* ref = seekTo(id, BUNDLE_TYPE_FONT);
     if (ref == NULL)
     {
         return NULL;
@@ -1281,7 +1280,7 @@ Font* Package::loadFont(const char* id)
     return font;
 }
 
-void Package::setTransform(const float* values, Transform* transform)
+void Bundle::setTransform(const float* values, Transform* transform)
 {
     // Load array into transform
     Matrix matrix(values);
@@ -1293,46 +1292,46 @@ void Package::setTransform(const float* values, Transform* transform)
     transform->setRotation(rotation);
 }
 
-bool Package::contains(const char* id) const
+bool Bundle::contains(const char* id) const
 {
     return (find(id) != NULL);
 }
 
-unsigned int Package::getObjectCount() const
+unsigned int Bundle::getObjectCount() const
 {
     return _referenceCount;
 }
 
-const char* Package::getObjectID(unsigned int index) const
+const char* Bundle::getObjectID(unsigned int index) const
 {
     return (index >= _referenceCount ? NULL : _references[index].id.c_str());
 }
 
-Package::Reference::Reference()
+Bundle::Reference::Reference()
     : type(0), offset(0)
 {
 }
 
-Package::Reference::~Reference()
+Bundle::Reference::~Reference()
 {
 }
 
-Package::MeshPartData::MeshPartData() :
+Bundle::MeshPartData::MeshPartData() :
     indexCount(0), indexData(NULL)
 {
 }
 
-Package::MeshPartData::~MeshPartData()
+Bundle::MeshPartData::~MeshPartData()
 {
     SAFE_DELETE_ARRAY(indexData);
 }
 
-Package::MeshData::MeshData(const VertexFormat& vertexFormat)
+Bundle::MeshData::MeshData(const VertexFormat& vertexFormat)
     : vertexFormat(vertexFormat), vertexCount(0), vertexData(NULL)
 {
 }
 
-Package::MeshData::~MeshData()
+Bundle::MeshData::~MeshData()
 {
     SAFE_DELETE_ARRAY(vertexData);
 

+ 24 - 24
gameplay/src/Package.h → gameplay/src/Bundle.h

@@ -1,5 +1,5 @@
-#ifndef PACKAGE_H_
-#define PACKAGE_H_
+#ifndef BUNDLE_H_
+#define BUNDLE_H_
 
 #include "Mesh.h"
 #include "Font.h"
@@ -10,29 +10,29 @@ namespace gameplay
 {
 
 /**
- * Represents a gameplay binary package file (.gpb) that contains a
- * collection of game resources that can be loaded.
+ * Represents a gameplay bundle file (.gpb) that contains a
+ * collection of binary game assets that can be loaded.
  */
-class Package : public Ref
+class Bundle : public Ref
 {
     friend class PhysicsController;
 
 public:
 
     /**
-     * Returns a Package for the given resource path.
+     * Returns a Bundle for the given resource path.
      *
-     * The specified path must reference a valid gameplay binary file.
-     * If the package is already loaded, the existing package is returned
+     * The specified path must reference a valid gameplay bundle file.
+     * If the bundle is already loaded, the existing bundle is returned
      * with its reference count incremented. When no longer needed, the
      * release() method must be called. Note that calling release() does
-     * NOT free any actual game objects created/returned from the Package
+     * NOT free any actual game objects created/returned from the Bundle
      * instance and those objects must be released separately.
      */
-    static Package* create(const char* path);
+    static Bundle* create(const char* path);
 
     /**
-     * Loads the scene with the specified ID from the package.
+     * Loads the scene with the specified ID from the bundle.
      * If id is NULL then the first scene found is loaded.
      * 
      * @param id The ID of the scene to load (NULL to load the first scene).
@@ -42,16 +42,16 @@ public:
     Scene* loadScene(const char* id = NULL);
 
     /**
-     * Loads a node with the specified ID from the package.
+     * Loads a node with the specified ID from the bundle.
      *
-     * @param id The ID of the node to load in the package.
+     * @param id The ID of the node to load in the bundle.
      * 
      * @return The loaded node, or NULL if the node could not be loaded.
      */
     Node* loadNode(const char* id);
 
     /**
-     * Loads a mesh with the specified ID from the package.
+     * Loads a mesh with the specified ID from the bundle.
      *
      * @param id The ID of the mesh to load.
      * 
@@ -60,7 +60,7 @@ public:
     Mesh* loadMesh(const char* id);
 
     /**
-     * Loads a font with the specified ID from the package.
+     * Loads a font with the specified ID from the bundle.
      *
      * @param id The ID of the font to load.
      * 
@@ -69,7 +69,7 @@ public:
     Font* loadFont(const char* id);
 
     /**
-     * Determines if this package contains a top-level object with the given ID.
+     * Determines if this bundle contains a top-level object with the given ID.
      *
      * This method performs a case-sensitive comparison.
      *
@@ -78,12 +78,12 @@ public:
     bool contains(const char* id) const;
 
     /**
-     * Returns the number of top-level objects in this package.
+     * Returns the number of top-level objects in this bundle.
      */
     unsigned int getObjectCount() const;
 
     /**
-     * Returns the unique identifier of the top-level object at the specified index in this package.
+     * Returns the unique identifier of the top-level object at the specified index in this bundle.
      *
      * @param index The index of the object.
      * 
@@ -143,12 +143,12 @@ private:
         std::vector<MeshPartData*> parts;
     };
 
-    Package(const char* path);
+    Bundle(const char* path);
 
     /**
      * Destructor.
      */
-    ~Package();
+    ~Bundle();
 
     /**
      * Finds a reference by ID.
@@ -156,7 +156,7 @@ private:
     Reference* find(const char* id) const;
 
     /**
-     * Resets any load session specific state for the package.
+     * Resets any load session specific state for the bundle.
      */
     void clearLoadSession();
 
@@ -206,7 +206,7 @@ private:
     Node* loadNode(const char* id, Scene* sceneContext, Node* nodeContext);
 
     /**
-     * Loads a mesh with the specified ID from the package.
+     * Loads a mesh with the specified ID from the bundle.
      *
      * @param id The ID of the mesh to load.
      * @param nodeId The id of the mesh's model's parent node.
@@ -331,8 +331,8 @@ private:
     /**
      * Reads mesh data for the specified URL.
      *
-     * The specified URL should be formatted as 'package#id', where
-     * 'package' is the package file containing the mesh and 'id' is the ID
+     * The specified URL should be formatted as 'bundle#id', where
+     * 'bundle' is the bundle file containing the mesh and 'id' is the ID
      * of the mesh to read data for.
      *
      * @param url The URL to read mesh data from.

+ 15 - 13
gameplay/src/Button.h

@@ -13,19 +13,21 @@ namespace gameplay
  * Defines a button UI control. This is essentially a label that can have a callback method set on it.
  *
  * The following properties are available for buttons:
- *
- * button <buttonID>
- * {
- *      style       = <styleID>
- *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
- *      position    = <x, y>
- *      autoWidth   = <bool>
- *      autoHeight  = <bool>
- *      size        = <width, height>
- *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
- *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
- *      text        = <string>
- * }
+
+ @verbatim
+    button <buttonID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+    }
+ @endverbatim
  */
 class Button : public Label
 {

+ 3 - 3
gameplay/src/CheckBox.cpp

@@ -23,7 +23,7 @@ CheckBox* CheckBox::create(Theme::Style* style, Properties* properties)
 {
     CheckBox* checkBox = new CheckBox();
     checkBox->initialize(style, properties);
-    properties->getVector2("iconSize", &checkBox->_imageSize);
+    properties->getVector2("imageSize", &checkBox->_imageSize);
     checkBox->_checked = properties->getBool("checked");
 
     return checkBox;
@@ -123,8 +123,8 @@ void CheckBox::update(const Rectangle& clip)
     }
     float iconWidth = size.x;
 
-    _textBounds.x += iconWidth;
-    _textBounds.width -= iconWidth;
+    _textBounds.x += iconWidth + 5;
+    _textBounds.width -= iconWidth + 5;
 }
 
 void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)

+ 17 - 15
gameplay/src/CheckBox.h

@@ -13,21 +13,23 @@ namespace gameplay
  * Defines a checkbox UI control.  This is a button that toggles between two icons when clicked.
  *
  * The following properties are available for checkboxes:
- *
- * checkBox <checkBoxID>
- * {
- *      style       = <styleID>
- *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
- *      position    = <x, y>
- *      autoWidth   = <bool>
- *      autoHeight  = <bool>
- *      size        = <width, height>
- *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
- *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
- *      text        = <string>
- *      checked     = <bool>
- *      iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.
- * }
+
+ @verbatim
+    checkBox <checkBoxID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+         checked     = <bool>
+         iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.
+    }
+ @endverbatim
  */
 class CheckBox : public Button
 {

+ 1 - 0
gameplay/src/Container.cpp

@@ -76,6 +76,7 @@ namespace gameplay
             {
                  controlStyle = theme->getStyle(controlStyleName);
             }
+            assert(controlStyle);
 
             std::string controlName(controlSpace->getNamespace());
             std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);

+ 29 - 27
gameplay/src/Container.h

@@ -11,33 +11,35 @@ namespace gameplay
  * A container is a UI control that can contain other controls.
  *
  * The following properties are available for containers:
- *
- * container <containerID>
- * {
- *      // Container properties.
- *      layout   = <Layout::Type>        // A value from the Layout::Type enum.  E.g.: LAYOUT_VERTICAL
- *      style    = <styleID>           // A style from the form's theme.
- *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
- *      position    = <x, y>    // Position of the container on-screen, measured in pixels.
- *      autoWidth   = <bool>
- *      autoHeight  = <bool>
- *      size        = <width, height>   // Size of the container, measured in pixels.
- *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
- *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
- *   
- *      // All the nested controls within this container.
- *      container 
- *      { 
- *          ...
- *      }
- * 
- *      label { }
- *      textBox { }
- *      button { }
- *      checkBox { }
- *      radioButton { }
- *      slider { }
- * }
+
+ @verbatim
+    container <containerID>
+    {
+         // Container properties.
+         layout   = <Layout::Type>        // A value from the Layout::Type enum.  E.g.: LAYOUT_VERTICAL
+         style    = <styleID>           // A style from the form's theme.
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>    // Position of the container on-screen, measured in pixels.
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>   // Size of the container, measured in pixels.
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+  
+         // All the nested controls within this container.
+         container 
+         { 
+             ...
+         }
+
+         label { }
+         textBox { }
+         button { }
+         checkBox { }
+         radioButton { }
+         slider { }
+    }
+ @endverbatim
  */
 class Container : public Control
 {

+ 132 - 12
gameplay/src/Control.cpp

@@ -36,6 +36,7 @@ namespace gameplay
     {
         _style = style;
 
+        // Properties not defined by the style.
         _alignment = getAlignment(properties->getString("alignment"));
         _autoWidth = properties->getBool("autoWidth");
         _autoHeight = properties->getBool("autoHeight");
@@ -68,6 +69,35 @@ namespace gameplay
         const char* id = properties->getId();
         if (id)
             _id = id;
+
+        // Potentially override themed properties for all states.
+        overrideThemedProperties(properties, STATE_ALL);
+
+        // Override themed properties on specific states.
+        Properties* stateSpace = properties->getNextNamespace();
+        while (stateSpace != NULL)
+        {
+            std::string stateName(stateSpace->getNamespace());
+            std::transform(stateName.begin(), stateName.end(), stateName.begin(), (int(*)(int))toupper);
+            if (stateName == "STATENORMAL")
+            {
+                overrideThemedProperties(stateSpace, NORMAL);
+            }
+            else if (stateName == "STATEFOCUS")
+            {
+                overrideThemedProperties(stateSpace, FOCUS);
+            }
+            else if (stateName == "STATEACTIVE")
+            {
+                overrideThemedProperties(stateSpace, ACTIVE);
+            }
+            else if (stateName == "STATEDISABLED")
+            {
+                overrideThemedProperties(stateSpace, DISABLED);
+            }
+
+            stateSpace = properties->getNextNamespace();
+        }
     }
 
     const char* Control::getID() const
@@ -614,16 +644,12 @@ namespace gameplay
         float clipX2 = clip.x + clip.width;
         float x2 = x + width;
         if (x2 > clipX2)
-        {
             width = clipX2 - x;
-        }
 
         float clipY2 = clip.y + clip.height;
         float y2 = y + height;
         if (y2 > clipY2)
-        {
             height = clipY2 - y;
-        }
 
         _clipBounds.set(_bounds.x, _bounds.y, width, height);
 
@@ -641,32 +667,27 @@ namespace gameplay
         clipX2 = clip.x + clip.width;
         x2 = x + width;
         if (x2 > clipX2)
-        {
             width = clipX2 - x;
-        }
 
         clipY2 = clip.y + clip.height;
         y2 = y + height;
         if (y2 > clipY2)
-        {
             height = clipY2 - y;
-        }
 
         if (x < clip.x)
-        {
             x = clip.x;
-        }
 
         if (y < clip.y)
-        {
             y = clip.y;
-        }
 
         _clip.set(x, y, width, height);
     }
 
     void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
     {
+        if (_bounds.width <= 0 || _bounds.height <= 0)
+            return;
+
         Vector2 pos(clip.x + _bounds.x, clip.y + _bounds.y);
 
         // Get the border and background images for this control's current state.
@@ -972,6 +993,105 @@ namespace gameplay
         _styleOverridden = true;
     }
 
+    void Control::overrideThemedProperties(Properties* properties, unsigned char states)
+    {
+        Theme::ImageList* imageList = NULL;
+        Theme::Image* cursor = NULL;
+        Theme::Skin* skin = NULL;
+        _style->_theme->lookUpSprites(properties, &imageList, &cursor, &skin);
+
+        if (imageList)
+        {
+            setImageList(imageList, states);
+        }
+
+        if (cursor)
+        {
+            setCursor(cursor, states);
+        }
+
+        if (skin)
+        {
+            setSkin(skin, states);
+        }
+
+        if (properties->exists("font"))
+        {
+            Font* font = Font::create(properties->getString("font"));
+            setFont(font, states);
+            font->release();
+        }
+
+        if (properties->exists("fontSize"))
+        {
+            setFontSize(properties->getInt("fontSize"), states);
+        }
+
+        if (properties->exists("textColor"))
+        {
+            Vector4 textColor(0, 0, 0, 1);
+            properties->getColor("textColor", &textColor);
+            setTextColor(textColor, states);
+        }
+
+        if (properties->exists("textAlignment"))
+        {
+            setTextAlignment(Font::getJustify(properties->getString("textAlignment")), states);
+        }
+
+        if (properties->exists("rightToLeft"))
+        {
+            setTextRightToLeft(properties->getBool("rightToLeft"), states);
+        }
+
+        if (properties->exists("opacity"))
+        {
+            setOpacity(properties->getFloat("opacity"), states);
+        }
+    }
+
+    void Control::setImageList(Theme::ImageList* imageList, unsigned char states)
+    {
+        overrideStyle();
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+        getOverlays(states, overlays);
+
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
+        {
+            overlays[i]->setImageList(imageList);
+        }
+
+        _dirty = true;
+    }
+
+    void Control::setCursor(Theme::Image* cursor, unsigned char states)
+    {
+        overrideStyle();
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+        getOverlays(states, overlays);
+
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
+        {
+            overlays[i]->setCursor(cursor);
+        }
+
+        _dirty = true;
+    }
+
+    void Control::setSkin(Theme::Skin* skin, unsigned char states)
+    {
+        overrideStyle();
+        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+        getOverlays(states, overlays);
+
+        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
+        {
+            overlays[i]->setSkin(skin);
+        }
+
+        _dirty = true;
+    }
+
     Control::Alignment Control::getAlignment(const char* alignment)
     {
         if (!alignment)

+ 9 - 0
gameplay/src/Control.h

@@ -23,6 +23,7 @@ class Control : public Ref, public AnimationTarget
     friend class Layout;
     friend class AbsoluteLayout;
     friend class VerticalLayout;
+    friend class FlowLayout;
 
 public:
 
@@ -827,6 +828,14 @@ private:
     Theme::Style::Overlay* getOverlay(Control::State state) const;
 
     void overrideStyle();
+
+    void overrideThemedProperties(Properties* properties, unsigned char states);
+
+    void setImageList(Theme::ImageList* imageList, unsigned char states = STATE_ALL);
+
+    void setCursor(Theme::Image* cursor, unsigned char states = STATE_ALL);
+
+    void setSkin(Theme::Skin* skin, unsigned char states = STATE_ALL);
     
     void addSpecificListener(Control::Listener* listener, Listener::EventType eventType);
     

+ 10 - 10
gameplay/src/Font.cpp

@@ -2,7 +2,7 @@
 #include "Font.h"
 #include "Game.h"
 #include "FileSystem.h"
-#include "Package.h"
+#include "Bundle.h"
 
 // Default font vertex shader
 #define FONT_VSH \
@@ -78,9 +78,9 @@ Font* Font::create(const char* path, const char* id)
         }
     }
 
-    // Load the package.
-    Package* pkg = Package::create(path);
-    if (pkg == NULL)
+    // Load the bundle.
+    Bundle* bundle = Bundle::create(path);
+    if (bundle == NULL)
     {
         return NULL;
     }
@@ -89,20 +89,20 @@ Font* Font::create(const char* path, const char* id)
 
     if (id == NULL)
     {
-        // Get the ID of the first/only object in the package (assume it's a Font).
+        // Get the ID of the first/only object in the bundle (assume it's a Font).
         const char* id;
-        if (pkg->getObjectCount() != 1 || (id = pkg->getObjectID(0)) == NULL)
+        if (bundle->getObjectCount() != 1 || (id = bundle->getObjectID(0)) == NULL)
         {
             return NULL;
         }
 
-        // Load the font using the ID of the first object in the package.
-        font = pkg->loadFont(pkg->getObjectID(0));
+        // Load the font using the ID of the first object in the bundle.
+        font = bundle->loadFont(bundle->getObjectID(0));
     }
     else
     {
         // Load the font with the given ID.
-        font = pkg->loadFont(id);
+        font = bundle->loadFont(id);
     }
 
     if (font)
@@ -111,7 +111,7 @@ Font* Font::create(const char* path, const char* id)
         __fontCache.push_back(font);
     }
 
-    SAFE_RELEASE(pkg);
+    SAFE_RELEASE(bundle);
 
     return font;
 }

+ 6 - 6
gameplay/src/Font.h

@@ -11,7 +11,7 @@ namespace gameplay
  */
 class Font : public Ref
 {
-    friend class Package;
+    friend class Bundle;
     friend class TextBox;
 
 public:
@@ -77,17 +77,17 @@ public:
     };
 
     /**
-     * Creates a font from the given package.
+     * Creates a font from the given bundle.
      *
-     * If the 'id' parameter is NULL, it is assumed that the Package at 'path'
-     * contains exactly one Font resource. If the Package does not meet this criteria,
+     * If the 'id' parameter is NULL, it is assumed that the Bundle at 'path'
+     * contains exactly one Font resource. If the Bundle does not meet this criteria,
      * NULL is returned.
      *
      * If a font for the given path has already been loaded, the existing font will be
      * returned with its reference count increased.
      *
-     * @param path The path to a package file containing a font resource.
-     * @param id An optional ID of the font resource within the package (NULL for the first/only resource).
+     * @param path The path to a bundle file containing a font resource.
+     * @param id An optional ID of the font resource within the bundle (NULL for the first/only resource).
      * 
      * @return The specified font.
      */

+ 24 - 14
gameplay/src/Form.cpp

@@ -201,36 +201,46 @@ namespace gameplay
     {
         std::vector<Control*>::const_iterator it;
 
-        // Batch all themed border and background sprites.
+        // Batch for all themed border and background sprites.
         spriteBatch->begin();
 
+        // Batch each font individually.
+        std::set<Font*>::const_iterator fontIter;
+        for (fontIter = _theme->_fonts.begin(); fontIter != _theme->_fonts.end(); fontIter++)
+        {
+            Font* font = *fontIter;
+            if (font)
+            {
+                font->begin();
+            }
+        }
+
         // Draw the form's border and background.
         // We don't pass the form's position to itself or it will be applied twice!
         Control::drawBorder(spriteBatch, Rectangle(0, 0, _bounds.width, _bounds.height));
 
-        // Draw each control's border and background.
         for (it = _controls.begin(); it < _controls.end(); it++)
         {
             Control* control = *it;
 
-            //if (!_node || (*it)->isDirty())
-            {
-                control->drawBorder(spriteBatch, clip);
+            // Draw this control's border and background.
+            control->drawBorder(spriteBatch, clip);
 
-                // Add all themed foreground sprites (checkboxes etc.) to the same batch.
-                control->drawImages(spriteBatch, clip);
-            }
+            // Add all themed foreground sprites (checkboxes etc.) to the same batch.
+            control->drawImages(spriteBatch, clip);
+
+            control->drawText(clip);
         }
+
+        // Done all batching.
         spriteBatch->end();
 
-        // Draw all control foregrounds / text.
-        for (it = _controls.begin(); it < _controls.end(); it++)
+        for (fontIter = _theme->_fonts.begin(); fontIter != _theme->_fonts.end(); fontIter++)
         {
-            Control* control = *it;
-
-            //if (!_node || (*it)->isDirty())
+            Font* font = *fontIter;
+            if (font)
             {
-                control->drawText(clip);
+                font->end();
             }
         }
 

+ 27 - 29
gameplay/src/Form.h

@@ -26,35 +26,33 @@ public:
     /**
      * Create from properties file.
      * The top-most namespace in the file must be named 'form'.  The following properties are available for forms:
-     *
-     * form <formID>
-     * {
-     *      // Form properties.
-     *      theme    = <Path to .theme File>    // See Theme.h.
-     *      layout   = <Layout::Type>           // A value from the Layout::Type enum.  e.g.: LAYOUT_VERTICAL
-     *      style    = <styleID>                // A style from the referenced theme.
-     *      position = <x, y>                   // Position of the form on-screen, measured in pixels.
-     *      size     = <width, height>          // Size of the form, measured in pixels.
-     *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
-     *      autoWidth   = <bool>                // Will result in a form the width of the display.
-     *      autoHeight  = <bool>                // Will result in a form the height of the display.
-     *      size        = <width, height>
-     *      width       = <width>               // Can be used in place of 'size', e.g. with 'autoHeight = true'
-     *      height      = <height>              // Can be used in place of 'size', e.g. with 'autoWidth = true'
-     *   
-     *      // All the nested controls within this form.
-     *      container 
-     *      {
-     *          ...
-     *      }
-     *      label { }
-     *      textBox { }
-     *      button { }
-     *      checkBox { }
-     *      radioButton { }
-     *      slider { }
-     * }
-     *
+
+ @verbatim
+    form <formID>
+    {
+        // Form properties.
+        theme       = <Path to .theme File> // See Theme.h.
+        layout      = <Layout::Type>        // A value from the Layout::Type enum.  e.g.: LAYOUT_VERTICAL
+        style       = <styleID>             // A style from the referenced theme.
+        position   = <x, y>                // Position of the form on-screen, measured in pixels.
+        alignment  = <Control::Alignment>  // Note: 'position' will be ignored.
+        autoWidth  = <bool>                // Will result in a form the width of the display.
+        autoHeight = <bool>                // Will result in a form the height of the display.
+        size       = <width, height>       // Size of the form, measured in pixels.
+        width      = <width>               // Can be used in place of 'size', e.g. with 'autoHeight = true'
+        height     = <height>              // Can be used in place of 'size', e.g. with 'autoWidth = true'
+      
+        // All the nested controls within this form.
+        container { }
+        label { }
+        textBox { }
+        button { }
+        checkBox { }
+        radioButton { }
+        slider { }
+    }
+ @endverbatim
+
      * @param path Path to the properties file to create a new form from.
      */
     static Form* create(const char* path);

+ 9 - 0
gameplay/src/FrameBuffer.h

@@ -8,6 +8,15 @@
 namespace gameplay
 {
 
+/**
+ * Defines a video output off all graphics buffer containing a complete frame of data.
+ * This consists of a RenderTarget and DepthStencilTarget holding the color, depth and
+ * stencil data in the rendering frame. 
+ * 
+ * to change the default Game framebuffer call Game::setFrameBuffer(myFrameBuffer);
+ * To restore back to the default call Game::setFrameBuffer(NULL).
+ * This is useful for rendering shadows and other post-processing effects.
+ */
 class FrameBuffer : public Ref
 {
 public:

+ 2 - 2
gameplay/src/Joint.h

@@ -7,7 +7,7 @@ namespace gameplay
 {
 
 class MeshSkin;
-class Package;
+class Bundle;
 
 /**
  * Defines a basic hierachial structure of transformation spaces.
@@ -16,7 +16,7 @@ class Joint : public Node
 {
     friend class Node;
     friend class MeshSkin;
-    friend class Package;
+    friend class Bundle;
 
 public:
 

+ 0 - 2
gameplay/src/Label.cpp

@@ -74,9 +74,7 @@ namespace gameplay
         textColor.w *= getOpacity(_state);
 
         // Draw the text.
-        font->begin();
         font->drawText(_text.c_str(), _textBounds, textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_clip);
-        font->end();
 
         _dirty = false;
     }

+ 15 - 13
gameplay/src/Label.h

@@ -11,19 +11,21 @@ namespace gameplay
  * A label is the most basic type of control, capable only of rendering text within its border.
  *
  * The following properties are available for labels:
- *
- * label <labelID>
- * {
- *      style       = <styleID>
- *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
- *      position    = <x, y>
- *      autoWidth   = <bool>
- *      autoHeight  = <bool>
- *      size        = <width, height>
- *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
- *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
- *      text        = <string>
- * }
+
+ @verbatim
+    label <labelID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+    }
+ @endverbatim
  */
 class Label : public Control
 {

+ 10 - 7
gameplay/src/Layout.cpp

@@ -11,38 +11,41 @@ namespace gameplay
             control->_autoWidth || control->_autoHeight)
         {
             Rectangle controlBounds = control->getBounds();
-            const Rectangle& containerBounds = container->getClip();
+            const Rectangle& containerBounds = container->getClipBounds();
             const Theme::Border& containerBorder = container->getBorder(container->getState());
             const Theme::Padding& containerPadding = container->getPadding();
 
+            float clipWidth = containerBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right;
+            float clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
+
             if (control->_autoWidth)
             {
-                controlBounds.width = containerBounds.width;
+                controlBounds.width = clipWidth;
             }
 
             if (control->_autoHeight)
             {
-                controlBounds.height = containerBounds.height;
+                controlBounds.height = clipHeight;
             }
 
             // Vertical alignment
             if ((control->_alignment & Control::ALIGN_BOTTOM) == Control::ALIGN_BOTTOM)
             {
-                controlBounds.y = containerBounds.height - controlBounds.height;
+                controlBounds.y = clipHeight - controlBounds.height;
             }
             else if ((control->_alignment & Control::ALIGN_VCENTER) == Control::ALIGN_VCENTER)
             {
-                controlBounds.y = containerBounds.height * 0.5f - controlBounds.height * 0.5f;
+                controlBounds.y = clipHeight * 0.5f - controlBounds.height * 0.5f;
             }
 
             // Horizontal alignment
             if ((control->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
             {
-                controlBounds.x = containerBounds.width - controlBounds.width;
+                controlBounds.x = clipWidth - controlBounds.width;
             }
             else if ((control->_alignment & Control::ALIGN_HCENTER) == Control::ALIGN_HCENTER)
             {
-                controlBounds.x = containerBounds.width * 0.5f - controlBounds.width * 0.5f;
+                controlBounds.x = clipWidth * 0.5f - controlBounds.width * 0.5f;
             }
 
             control->setBounds(controlBounds);

+ 6 - 6
gameplay/src/Matrix.cpp

@@ -554,18 +554,18 @@ void Matrix::getLeftVector(Vector3* dst) const
 {
     assert(dst);
 
-    dst->x = -m[0];
-    dst->y = -m[1];
-    dst->z = -m[2];
+    dst->x = m[0];
+    dst->y = m[1];
+    dst->z = m[2];
 }
 
 void Matrix::getRightVector(Vector3* dst) const
 {
     assert(dst);
 
-    dst->x = m[0];
-    dst->y = m[1];
-    dst->z = m[2];
+    dst->x = -m[0];
+    dst->y = -m[1];
+    dst->z = -m[2];
 }
 
 void Matrix::getForwardVector(Vector3* dst) const

+ 5 - 5
gameplay/src/Mesh.h

@@ -21,7 +21,7 @@ class Model;
 class Mesh : public Ref
 {
     friend class Model;
-    friend class Package;
+    friend class Bundle;
 
 public:
 
@@ -126,8 +126,8 @@ public:
     /**
      * Returns a URL from which the mesh was loaded from.
      *
-     * For meshes loaded from a Package, this URL will point
-     * to the file and ID of the mesh within the package. For
+     * For meshes loaded from a Bundle, this URL will point
+     * to the file and ID of the mesh within the bundle. For
      * all other meshes, an empty string will be returned.
      */
     const char* getUrl() const;
@@ -230,7 +230,7 @@ public:
     /**
      * Returns the bounding box for the points in this mesh.
      * 
-     * Only meshes loaded from package files are imported with valid
+     * Only meshes loaded from bundle files are imported with valid
      * bounding volumes. Programmatically created meshes will contain
      * empty bounding volumes until the setBoundingBox and/or
      * setBoundingSphere methods are called to specify the mesh's
@@ -259,7 +259,7 @@ public:
     /**
      * Returns the bounding sphere for the points in the mesh.
      *
-     * Only meshes loaded from package files are imported with valid
+     * Only meshes loaded from bundle files are imported with valid
      * bounding volumes. Programmatically created meshes will contain
      * empty bounding volumes until the setBoundingBox and/or
      * setBoundingSphere methods are called to specify the mesh's

+ 2 - 1
gameplay/src/MeshBatch.cpp

@@ -151,7 +151,7 @@ bool MeshBatch::resize(unsigned int capacity)
 
     return true;
 }
-
+    
 void MeshBatch::begin()
 {
     _vertexCount = 0;
@@ -193,5 +193,6 @@ void MeshBatch::draw()
         pass->unbind();
     }
 }
+    
 
 }

+ 3 - 0
gameplay/src/MeshBatch.h

@@ -7,6 +7,9 @@
 namespace gameplay
 {
 
+/**
+ * Defines a class for rendering multiple mesh into a single draw call on the graphics device.
+ */
 class MeshBatch
 {
 public:

+ 6 - 6
gameplay/src/MeshBatch.inl

@@ -12,12 +12,12 @@ template <class T>
 void MeshBatch::add(T* vertices, unsigned int vertexCount, unsigned short* indices, unsigned int indexCount)
 {
     assert(sizeof(T) == _vertexFormat.getVertexSize());
-
+    
     unsigned int newVertexCount = _vertexCount + vertexCount;
     unsigned int newIndexCount = _indexCount + indexCount;
     if (_primitiveType == Mesh::TRIANGLE_STRIP && _vertexCount > 0)
         newIndexCount += 2; // need an extra 2 indices for connecting strips with degenerate triangles
-
+    
     // Do we need to grow the batch?
     while (newVertexCount > _vertexCapacity || (_indexed && newIndexCount > _indexCapacity))
     {
@@ -26,11 +26,11 @@ void MeshBatch::add(T* vertices, unsigned int vertexCount, unsigned short* indic
         if (!resize(_capacity + _growSize))
             return; // failed to grow
     }
-
+    
     // Copy vertex data
     unsigned int vBytes = vertexCount * _vertexFormat.getVertexSize();
     memcpy(_verticesPtr, vertices, vBytes);
-
+    
     // Copy index data
     if (_indexed)
     {
@@ -49,7 +49,7 @@ void MeshBatch::add(T* vertices, unsigned int vertexCount, unsigned short* indic
                 _indicesPtr[1] = _vertexCount;
                 _indicesPtr += 2;
             }
-
+            
             // Loop through all indices and insert them, their their value offset by
             // 'vertexCount' so that they are relative to the first newly insertted vertex
             for (unsigned int i = 0; i < indexCount; ++i)
@@ -60,7 +60,7 @@ void MeshBatch::add(T* vertices, unsigned int vertexCount, unsigned short* indic
         _indicesPtr += indexCount;
         _indexCount = newIndexCount;
     }
-
+    
     _verticesPtr += vBytes;
     _vertexCount = newVertexCount;
 }

+ 2 - 2
gameplay/src/MeshSkin.h

@@ -7,7 +7,7 @@
 namespace gameplay
 {
 
-class Package;
+class Bundle;
 class Model;
 class Joint;
 class Node;
@@ -17,7 +17,7 @@ class Node;
  */
 class MeshSkin : public Transform::Listener
 {
-    friend class Package;
+    friend class Bundle;
     friend class Model;
     friend class Joint;
 

+ 2 - 2
gameplay/src/Model.h

@@ -8,7 +8,7 @@
 namespace gameplay
 {
 
-class Package;
+class Bundle;
 class MeshSkin;
 class Node;
 class NodeCloneContext;
@@ -21,7 +21,7 @@ class Model : public Ref
 {
     friend class Node;
     friend class Mesh;
-    friend class Package;
+    friend class Bundle;
 
 public:
 

+ 18 - 4
gameplay/src/Node.cpp

@@ -15,6 +15,7 @@
 // Node property flags
 #define NODE_FLAG_VISIBLE 1
 #define NODE_FLAG_TRANSPARENT 2
+#define NODE_FLAG_DYNAMIC 4
 
 namespace gameplay
 {
@@ -235,6 +236,19 @@ void Node::setTransparent(bool transparent)
         _nodeFlags &= ~NODE_FLAG_TRANSPARENT;
 }
 
+bool Node::isDynamic() const
+{
+    return ((_nodeFlags & NODE_FLAG_DYNAMIC) == NODE_FLAG_DYNAMIC);
+}
+
+void Node::setDynamic(bool dynamic)
+{
+    if (dynamic)
+        _nodeFlags |= NODE_FLAG_DYNAMIC;
+    else
+        _nodeFlags &= ~NODE_FLAG_DYNAMIC;
+}
+
 void* Node::getUserPointer() const
 {
     return (_userData ? _userData->pointer : NULL);
@@ -1004,8 +1018,8 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
     // Check if the properties is valid.
     if (!properties || 
         !(strcmp(properties->getNamespace(), "character") == 0 || 
-        strcmp(properties->getNamespace(), "ghost") == 0 || 
-        strcmp(properties->getNamespace(), "rigidbody") == 0))
+        strcmp(properties->getNamespace(), "ghostObject") == 0 || 
+        strcmp(properties->getNamespace(), "rigidBody") == 0))
     {
         WARN("Failed to load collision object from properties object: must be non-null object and have namespace equal to \'character\', \'ghost\', or \'rigidbody\'.");
         return NULL;
@@ -1015,11 +1029,11 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
     {
         _collisionObject = PhysicsCharacter::create(this, properties);
     }
-    else if (strcmp(properties->getNamespace(), "ghost") == 0)
+    else if (strcmp(properties->getNamespace(), "ghostObject") == 0)
     {
         _collisionObject = PhysicsGhostObject::create(this, properties);
     }
-    else if (strcmp(properties->getNamespace(), "rigidbody") == 0)
+    else if (strcmp(properties->getNamespace(), "rigidBody") == 0)
     {
         _collisionObject = PhysicsRigidBody::create(this, properties);
     }

+ 25 - 2
gameplay/src/Node.h

@@ -16,7 +16,7 @@
 namespace gameplay
 {
 
-class Package;
+class Bundle;
 class Scene;
 class Form;
 
@@ -26,7 +26,7 @@ class Form;
 class Node : public Transform, public Ref
 {
     friend class Scene;
-    friend class Package;
+    friend class Bundle;
     friend class MeshSkin;
 
 public:
@@ -148,6 +148,26 @@ public:
      */
     void setTransparent(bool transparent);
 
+    /**
+     * Returns whether this node is dynamic.
+     *
+     * The dynamic propery can be used to flag nodes as being non-static.
+     * This can be useful for modifying behavior or rendering/material
+     * logic at runtime for static vs dynamic (moving) objects. An
+     * example would be determing whether to use static or  dyanmic
+     * lighting materials for node models during loading.
+     *
+     * @return Whether this node is dynamic (false by default).
+     */
+    bool isDynamic() const;
+
+    /**
+     * Sets whether this node is dynamic.
+     *
+     * @param dynamic Whether the node is dynamic.
+     */
+    void setDynamic(bool dynamic);
+
     /**
      * Returns the user pointer for this node.
      *
@@ -613,6 +633,9 @@ private:
 
 protected:
 
+    /**
+     * Defines a pointer and cleanup callback to custom user data that can be store in a Node.
+     */
     struct UserData
     {
         UserData() : pointer(NULL), cleanupCallback(NULL) {}

+ 12 - 149
gameplay/src/PhysicsCharacter.cpp

@@ -99,6 +99,8 @@ PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
     // Load the character's parameters.
     properties->rewind();
     float mass = 1.0f;
+    float maxStepHeight = 0.1f;
+    float maxSlopeAngle = 0.0f;
     const char* name = NULL;
     while ((name = properties->getNextProperty()) != NULL)
     {
@@ -106,10 +108,20 @@ PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
         {
             mass = properties->getFloat();
         }
+        else if (strcmp(name, "maxStepHeight") == 0)
+        {
+            maxStepHeight = properties->getFloat();
+        }
+        else if (strcmp(name, "maxSlopeAngle") == 0)
+        {
+            maxSlopeAngle = properties->getFloat();
+        }
     }
 
     // Create the physics character.
     PhysicsCharacter* character = new PhysicsCharacter(node, *shape, mass);
+    character->setMaxStepHeight(maxStepHeight);
+    character->setMaxSlopeAngle(maxSlopeAngle);
     SAFE_DELETE(shape);
 
     return character;
@@ -156,120 +168,6 @@ void PhysicsCharacter::setMaxSlopeAngle(float angle)
     _cosSlopeAngle = std::cos(MATH_DEG_TO_RAD(angle));
 }
 
-void PhysicsCharacter::addAnimation(const char* name, AnimationClip* clip, float moveSpeed)
-{
-    CharacterAnimation a;
-    a.name = name;
-    a.clip = clip;
-    a.moveSpeed = moveSpeed;
-    a.layer = 0;
-    a.playing = false;
-    a.animationFlags = ANIMATION_STOP;
-    a.prev = NULL;
-    _animations[name] = a;
-}
-
-AnimationClip* PhysicsCharacter::getAnimation(const char* name)
-{
-    if (name)
-    {
-        // Lookup the specified animation
-        std::map<const char*, CharacterAnimation>::iterator aitr = _animations.find(name);
-        if (aitr != _animations.end())
-        {
-            return aitr->second.clip;
-        }
-    }
-    return NULL;
-}
-
-void PhysicsCharacter::play(const char* name, AnimationFlags flags, float speed, unsigned int blendDuration, unsigned int layer)
-{
-    CharacterAnimation* animation = NULL;
-    if (name)
-    {
-        // Lookup the specified animation
-        std::map<const char*, CharacterAnimation>::iterator aitr = _animations.find(name);
-        if (aitr == _animations.end())
-            return; // invalid animation name
-
-        animation = &(aitr->second);
-
-        // Set animation flags
-        animation->clip->setRepeatCount(flags & ANIMATION_REPEAT ? AnimationClip::REPEAT_INDEFINITE : 1);
-        animation->clip->setSpeed(speed);
-        animation->animationFlags = flags;
-        animation->layer = layer;
-        animation->blendDuration = blendDuration;
-        animation->prev = NULL;
-
-        // If the animation is already marked playing, do nothing more
-        if (animation->playing)
-            return;
-    }
-
-    play(animation, layer);
-}
-
-void PhysicsCharacter::play(CharacterAnimation* animation, unsigned int layer)
-{
-    // Is there already an animation playing on this layer?
-    std::map<unsigned int, CharacterAnimation*>::iterator litr = _layers.find(layer);
-    CharacterAnimation* prevAnimation = (litr == _layers.end() ? NULL : litr->second);
-    if (prevAnimation && prevAnimation->playing)
-    {
-        // An animation is already playing on this layer
-        if (animation)
-        {
-            if (animation->animationFlags == ANIMATION_RESUME)
-                animation->prev = prevAnimation;
-
-            if (animation->blendDuration > 0L)
-            {
-                // Crossfade from current animation into the new one
-                prevAnimation->clip->crossFade(animation->clip, animation->blendDuration);
-            }
-            else
-            {
-                // Stop the previous animation (no blending)
-                prevAnimation->clip->stop();
-
-                // Play the new animation
-                animation->clip->play();
-            }
-        }
-        else
-        {
-            // No new animaton specified - stop current animation on this layer
-            prevAnimation->clip->stop();
-        }
-
-        prevAnimation->playing = false;
-    }
-    else if (animation)
-    {
-        // No animations currently playing - just play the new one
-        animation->clip->play();
-    }
-
-    // Update animaton and layers
-    if (animation)
-    {
-        animation->playing = true;
-
-        // Update layer to point to the new animation
-        if (litr != _layers.end())
-            litr->second = animation;
-        else
-            _layers[layer] = animation;
-    }
-    else if (litr != _layers.end())
-    {
-        // Remove layer sine we stopped the animation previously on it
-        _layers.erase(litr);
-    }
-}
-
 void PhysicsCharacter::setVelocity(const Vector3& velocity)
 {
     _moveVelocity.setValue(velocity.x, velocity.y, velocity.z);
@@ -432,45 +330,10 @@ void PhysicsCharacter::stepUp(btCollisionWorld* collisionWorld, btScalar time)
 
 void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, float time)
 {
-    // Process currently playing movements+animations and determine final move location
-    float animationMoveSpeed = 0.0f;
-    unsigned int animationCount = 0;
-    for (std::map<unsigned int, CharacterAnimation*>::iterator itr = _layers.begin(); itr != _layers.end(); ++itr)
-    {
-        CharacterAnimation* animation = itr->second;
-
-        // If the animation is not playing, ignore it
-        if (!animation->playing)
-            continue;
-
-        AnimationClip* clip = animation->clip;
-
-        // Did the clip finish playing (but we still have it marked playing)?
-        if (!clip->isPlaying())
-        {
-            // If the animaton was flaged the ANIMATION_RESUME bit, start the previously playing animation
-            if ((animation->animationFlags == ANIMATION_RESUME) && animation->prev)
-            {
-                play(animation->prev, animation->prev->layer);
-            }
-
-            animation->playing = false;
-
-            continue;
-        }
-
-        animationMoveSpeed += animation->moveSpeed;
-        ++animationCount;
-    }
-
     updateCurrentVelocity();
 
     // Calculate final velocity
     btVector3 velocity(_currentVelocity);
-    if (animationCount > 0)
-    {
-        velocity *= animationMoveSpeed;
-    }
     velocity *= time; // since velocity is in meters per second
 
     if (velocity.isZero())

+ 2 - 110
gameplay/src/PhysicsCharacter.h

@@ -18,10 +18,6 @@ namespace gameplay
  * PhysicsCharacter class. This results in a more responsive and typical game
  * character than would be possible if trying to move a character by applying
  * physical simulation with forces.
- *
- * This class can also be used to control animations for a character. Animation
- * clips can be setup for typical character animations, such as walk, run, jump,
- * etc; and the controller will handle blending between these animations as needed.
  */
 class PhysicsCharacter : public PhysicsGhostObject, public btActionInterface
 {
@@ -29,27 +25,6 @@ class PhysicsCharacter : public PhysicsGhostObject, public btActionInterface
 
 public:
 
-    /**
-     * Flags for controlling how a character animation is played back.
-     */
-    enum AnimationFlags
-    {
-        /**
-         * Plays an animation once and then stops.
-         */
-        ANIMATION_STOP,
-
-        /**
-         * Play an animation once and then resumes the previous playing animation.
-         */
-        ANIMATION_RESUME,
-
-        /**
-         * Plays an animation and repeats it indefinitely.
-         */
-         ANIMATION_REPEAT
-    };
-
     /**
      * @see PhysicsCollisionObject#getType
      */
@@ -110,74 +85,13 @@ public:
      */
     void setMaxSlopeAngle(float angle);
 
-    /**
-     * Configures a new animation for this character.
-     *
-     * This method registers an animation for the character, with an associated movement speed.
-     * The moveSpeed specifies how fast the character moves while the animation is playing.
-     * The final velocity of the character is the product of the current move velocity and
-     * the currently playing animation(s) moveSpeed.
-     *
-     * @param name Name of the animation.
-     * @param animationClip Animation clip associated with the new character animation.
-     * @param moveSpeed Base movement speed (meters per second) associated with the animation.
-     */
-    void addAnimation(const char* name, AnimationClip* animationClip, float moveSpeed);
-
-    /**
-     * Returns the animation with the specified name.
-     *
-     * @return The specified animation clip.
-     */
-    AnimationClip* getAnimation(const char* name);
-
-    /**
-     * Plays the specified animation.
-     *
-     * There are some limiations and considerations that should be ponited out when
-     * playing animations:
-     * <li>You should avoid playing multiple animations concurrently that have the same target.
-     * For example, two animations targetting the character's joints should not be played 
-     * concurrently, but it is fine to play one animation that targets the joints and another
-     * that targets the character's Node.
-     * <li>When playing an animation that targets the transform of the character's Node
-     * (such as a motion path animation), the character's velocity vector should be set to
-     * Vector3::zero() so that the PhysicsCharacter stops applying motion directly
-     * and instead relies on the motion animation to control the character.
-     *
-     * The optional animation layer can be used to group animations on separate layers.
-     * Each animation layer can have at most one active animation. Playing multiple
-     * animations concurrently can be achieved by putting the different animations
-     * on separate layers. For example, a motion path animation that targets the
-     * character's Node can be put on one layer, while a running animation that targets
-     * a character's Joints can be put on a separate layer. This allows a character's
-     * movement to be animated at the same time as the run animation is playing.
-     *
-     * @param name Animation name, or NULL to stop all character animations on the given layer.
-     * @param flags Animation flags from the AnimationFlags enumeration.
-     * @param animationSpeed Optional animation speed (default is 1.0).
-     * @param blendDuration Optional number of milliseconds to crossfade between the
-     *      currently playing animation on the given layer and the new animation.
-     * @param layer Optional animation layer.
-     */
-    void play(const char* name, AnimationFlags flags, float animationSpeed = 1.0f, unsigned int blendDuration = 0, unsigned int layer = 0);
-
     /**
      * Sets the velocity of the character.
      *
      * Calling this function sets the velocity (speed and direction) for the character.
      * The velocity is maintained until this method is called again. The final velocity
-     * of the character is determined by product of the current velocity vector(s)
-     * and the current character animation's move speed. Therefore, specifying a
-     * normalized (unit-length) velocity vector results in the character speed being
-     * controled entirely by the current animation's velocity; whereas the speed of
-     * the character can be augmented by modifying the magnitude of the velocity vector.
-
-     * Note that a zero velocity vector and/or a zero animation move speed will
-     * result in no character movement (the character will be stationary). A zero
-     * velocity vector should be used when playing an animation that targets the
-     * character's transform directly (such as a motion path animation), since these
-     * animations will overwrite any transformations on the character's node.
+     * of the character is determined by product of the current velocity, right and
+     * forward vectors.
      *
      * @param velocity Movement velocity.
      */
@@ -219,9 +133,6 @@ public:
      * The forward velocity is defined by the character's current orientation
      * (it is the forward vector from the character's current world transform).
      *
-     * The specified velocity acts as a multiplier on the currently playing animation's
-     * velocity (or, if there is no animation playing, it directly impacts velocity).
-     *
      * Note that a negative velocity (i.e. -1.0f) will move the character backwards.
      *
      * @param velocity Optional velocity modifier.
@@ -234,9 +145,6 @@ public:
      * The right velocity is defined by the character's current orientation
      * (it is the right vector from the character's current world transform).
      *
-     * The specified velocity acts as a multiplier on the currently playing animation's
-     * velocity (or, if there is no animation playing, it directly impacts velocity).
-     *
      * Note that a negative velocity (i.e. -1.0f) will move the character left.
      *
      * @param velocity Optional velocity modifier.
@@ -269,18 +177,6 @@ protected:
 
 private:
 
-    struct CharacterAnimation
-    {
-        const char* name;
-        AnimationClip* clip;
-        float moveSpeed;
-        unsigned int layer;
-        bool playing;
-        AnimationFlags animationFlags;
-        unsigned int blendDuration;
-        CharacterAnimation* prev;
-    };
-
     /**
      * Creates a new PhysicsCharacter.
      *
@@ -311,8 +207,6 @@ private:
 
     void updateCurrentVelocity();
 
-    void play(CharacterAnimation* animation, unsigned int layer);
-
     void stepUp(btCollisionWorld* collisionWorld, btScalar time);
 
     void stepDown(btCollisionWorld* collisionWorld, btScalar time);
@@ -332,8 +226,6 @@ private:
     bool _colliding;
     btVector3 _collisionNormal;
     btVector3 _currentPosition;
-    std::map<const char*, CharacterAnimation> _animations;
-    std::map<unsigned int, CharacterAnimation*> _layers;
     btManifoldArray _manifoldArray;
     float _stepHeight;
     float _slopeAngle;

+ 2 - 2
gameplay/src/PhysicsCollisionShape.cpp

@@ -121,8 +121,8 @@ PhysicsCollisionShape::Definition* PhysicsCollisionShape::Definition::create(Nod
     assert(properties);
     if (!properties || 
         !(strcmp(properties->getNamespace(), "character") == 0 || 
-        strcmp(properties->getNamespace(), "ghost") == 0 || 
-        strcmp(properties->getNamespace(), "rigidbody") == 0))
+        strcmp(properties->getNamespace(), "ghostObject") == 0 || 
+        strcmp(properties->getNamespace(), "rigidBody") == 0))
     {
         WARN("Failed to load physics collision shape from properties object: must be non-null object and have namespace equal to \'character\', \'ghost\', or \'rigidbody\'.");
         return NULL;

+ 4 - 4
gameplay/src/PhysicsController.cpp

@@ -5,7 +5,7 @@
 #include "PhysicsMotionState.h"
 #include "Game.h"
 #include "MeshPart.h"
-#include "Package.h"
+#include "Bundle.h"
 
 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
 
@@ -927,7 +927,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         return NULL;
     }
 
-    // The mesh must have a valid URL (i.e. it must have been loaded from a Package)
+    // The mesh must have a valid URL (i.e. it must have been loaded from a Bundle)
     // in order to fetch mesh data for computing mesh rigid body.
     if (strlen(mesh->getUrl()) == 0)
     {
@@ -935,7 +935,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
         return NULL;
     }
 
-    Package::MeshData* data = Package::readMeshData(mesh->getUrl());
+    Bundle::MeshData* data = Bundle::readMeshData(mesh->getUrl());
     if (data == NULL)
     {
         return NULL;
@@ -968,7 +968,7 @@ PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3&
     {
         PHY_ScalarType indexType = PHY_UCHAR;
         int indexStride = 0;
-        Package::MeshPartData* meshPart = NULL;
+        Bundle::MeshPartData* meshPart = NULL;
         for (unsigned int i = 0; i < partCount; i++)
         {
             meshPart = data->parts[i];

+ 1 - 1
gameplay/src/PhysicsGhostObject.cpp

@@ -43,7 +43,7 @@ PhysicsGhostObject* PhysicsGhostObject::create(Node* node, Properties* propertie
 {
     // Check if the properties is valid and has a valid namespace.
     assert(properties);
-    if (!properties || !(strcmp(properties->getNamespace(), "ghost") == 0))
+    if (!properties || !(strcmp(properties->getNamespace(), "ghostObject") == 0))
     {
         WARN("Failed to load ghost object from properties object: must be non-null object and have namespace equal to \'ghost\'.");
         return NULL;

+ 2 - 2
gameplay/src/PhysicsRigidBody.cpp

@@ -145,9 +145,9 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
 {
     // Check if the properties is valid and has a valid namespace.
     assert(properties);
-    if (!properties || !(strcmp(properties->getNamespace(), "rigidbody") == 0))
+    if (!properties || !(strcmp(properties->getNamespace(), "rigidBody") == 0))
     {
-        WARN("Failed to load rigid body from properties object: must be non-null object and have namespace equal to \'rigidbody\'.");
+        WARN("Failed to load rigid body from properties object: must be non-null object and have namespace equal to \'rigidBody\'.");
         return NULL;
     }
 

+ 6 - 22
gameplay/src/PlatformQNX.cpp

@@ -804,14 +804,9 @@ int Platform::enterMessagePump()
                 {
                     case SCREEN_EVENT_MTOUCH_TOUCH:
                     {
-                        if (!__multiTouch)
+                        screen_get_mtouch_event(__screenEvent, &touchEvent, 0);
+                        if (__multiTouch || touchEvent.contact_id == 0)
                         {
-                            screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_POSITION, position);
-                           gameplay::Platform::touchEventInternal(Touch::TOUCH_PRESS, position[0], position[1], 0);
-                        }
-                        else
-                        {
-                            screen_get_mtouch_event(__screenEvent, &touchEvent, 0);
                             gameplay::Platform::touchEventInternal(Touch::TOUCH_PRESS, touchEvent.x, touchEvent.y, touchEvent.contact_id);
                         }
                         break;
@@ -819,14 +814,9 @@ int Platform::enterMessagePump()
 
                     case SCREEN_EVENT_MTOUCH_RELEASE:
                     {
-                        if (!__multiTouch)
-                        {
-                            screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_POSITION, position);
-                           gameplay::Platform::touchEventInternal(Touch::TOUCH_RELEASE, position[0], position[1], 0);
-                        }
-                        else
+                        screen_get_mtouch_event(__screenEvent, &touchEvent, 0);
+                        if (__multiTouch || touchEvent.contact_id == 0)
                         {
-                            screen_get_mtouch_event(__screenEvent, &touchEvent, 0);
                             gameplay::Platform::touchEventInternal(Touch::TOUCH_RELEASE, touchEvent.x, touchEvent.y, touchEvent.contact_id);
                         }
                         break;
@@ -834,18 +824,12 @@ int Platform::enterMessagePump()
 
                     case SCREEN_EVENT_MTOUCH_MOVE:
                     {
-                        if (!__multiTouch)
+                        screen_get_mtouch_event(__screenEvent, &touchEvent, 0);
+                        if (__multiTouch ||touchEvent.contact_id == 0)
                         {
-                            screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_POSITION, position);
-                           gameplay::Platform::touchEventInternal(Touch::TOUCH_MOVE, position[0], position[1], 0);
-                        }
-                        else
-                        {
-                            screen_get_mtouch_event(__screenEvent, &touchEvent, 0);
                             gameplay::Platform::touchEventInternal(Touch::TOUCH_MOVE, touchEvent.x, touchEvent.y, touchEvent.contact_id);
                         }
                         break;
-                        break;
                     }
 
                     case SCREEN_EVENT_POINTER:

+ 67 - 70
gameplay/src/Properties.h

@@ -22,48 +22,45 @@ namespace gameplay
  * Here's an example of a simple
  * file that uses all the available features of the markup language:
  
-\verbatim
---- File Start: example.properties ---
+ @verbatim
+    // This is a comment.
  
-// This is a comment.
+    // This property is in the default namespace:
+    integerProperty = 5
  
-// This property is in the default namespace:
-integerProperty = 5
- 
-// This line defines a namespace of type "mynamespace" without an ID:
-mynamespace
-{
-    // This namespace can be retrieved by searching for its ID, "spriteTexture":
-    texture spriteTexture 
+    // This line defines a namespace of type "mynamespace" without an ID:
+    mynamespace
     {
-        fileName = sprite.png
-        width = 64
-        height = 64
-    }
+        // This namespace can be retrieved by searching for its ID, "spriteTexture":
+        texture spriteTexture 
+        {
+            fileName = sprite.png
+            width = 64
+            height = 64
+        }
  
-    // This property is in the "space" namespace:
-    booleanProperty = true
+        // This property is in the "space" namespace:
+        booleanProperty = true
  
-    // It's legal to have a name without a value if you leave out the '=' character:
-    foo
+        // It's legal to have a name without a value if you leave out the '=' character:
+        foo
  
-    // In fact, the '=' character is optional if you'd rather write:
-    bar 23
+        // In fact, the '=' character is optional if you'd rather write:
+        bar 23
  
-    // But don't write this or you'll get an error:
-    // illegalProperty =
+        // But don't write this or you'll get an error:
+        // illegalProperty =
  
-    // Or this:
-    // = 15
+        // Or this:
+        // = 15
  
-    // Properties objects let you retrieve values as various types.
-    floatProperty = 3.333
-    stringProperty = This is a string.
-    vector3Property = 1.0, 5.0, 3.55
-    colorProperty = 1.0, 0.4, 0.0, 1.0
-}
---- File End ---
-\endverbatim
+        // Properties objects let you retrieve values as various types.
+        floatProperty = 3.333
+        stringProperty = This is a string.
+        vector3Property = 1.0, 5.0, 3.55
+        colorProperty = 1.0, 0.4, 0.0, 1.0
+    }
+ @endverbatim
  
  * Retrieving information out of a file like this could be done in two ways.  If the
  * available namespaces and name/value pairs are known in advance they can be queried by ID or name.
@@ -72,54 +69,54 @@ mynamespace
  * A namespace is stored and retrieved as a Properties object.
  * Reading the spriteTexture properties out of the file above in this way could be done with the following code:
  
-\verbatim
-// Create the top-level Properties object.
-Properties* properties = Properties::create("example.properties");
-// Retrieve the "spriteTexture" namespace.
-Properties* spriteTexture = properties->getNamespace("spriteTexture");
+ @verbatim
+    // Create the top-level Properties object.
+    Properties* properties = Properties::create("example.properties");
+    // Retrieve the "spriteTexture" namespace.
+    Properties* spriteTexture = properties->getNamespace("spriteTexture");
  
-// Get the values of known texture properties out of the namespace.
-const char* fileName = spriteTexture->getString("fileName");
-int width = spriteTexture->getInt("width");
-int height = spriteTexture->getInt("height");
+    // Get the values of known texture properties out of the namespace.
+    const char* fileName = spriteTexture->getString("fileName");
+    int width = spriteTexture->getInt("width");
+    int height = spriteTexture->getInt("height");
  
-// Deleting the top-level Properties object will clean up all nested namespaces.
-SAFE_DELETE(properties);
-\endverbatim
+    // Deleting the top-level Properties object will clean up all nested namespaces.
+    SAFE_DELETE(properties);
+ @endverbatim
 
  * On the other hand, if the structure of the file is not known in advance its 
  * namespaces and name/value pairs can be retrieved one by one using the getNextNamespace()
  * and getNextProperty() methods.  The following method prints the contents of any properties file
  * to the console:
  
-\verbatim
-void printProperties(Properties* properties)
-{
-    // Print the name and ID of the current namespace.
-    const char* spacename = properties->getNamespace();
-    const char* id = properties->getId();
-    WARN_VARG("Namespace: %s  ID: %s\n{", spacename, id);
- 
-    // Print all properties in this namespace.
-    const char* name = properties->getNextProperty();
-    const char* value = NULL;
-    while (name != NULL)
+ @verbatim
+    void printProperties(Properties* properties)
     {
-        value = properties->getString(name);
-        WARN_VARG("%s = %s", name, value);
-        name = properties->getNextProperty();
-    }
-    WARN("}\n");
+        // Print the name and ID of the current namespace.
+        const char* spacename = properties->getNamespace();
+        const char* id = properties->getId();
+        WARN_VARG("Namespace: %s  ID: %s\n{", spacename, id);
  
-    // Print the properties of every namespace within this one.
-    Properties* space = properties->getNextNamespace();
-    while (space != NULL)
-    {
-        printProperties(space);
-        space = properties->getNextNamespace();
+        // Print all properties in this namespace.
+        const char* name = properties->getNextProperty();
+        const char* value = NULL;
+        while (name != NULL)
+        {
+            value = properties->getString(name);
+            WARN_VARG("%s = %s", name, value);
+            name = properties->getNextProperty();
+        }
+        WARN("}\n");
+ 
+        // Print the properties of every namespace within this one.
+        Properties* space = properties->getNextNamespace();
+        while (space != NULL)
+        {
+            printProperties(space);
+            space = properties->getNextNamespace();
+        }
     }
-}
-\endverbatim
+ @endverbatim
 
  * Note that this method does not keep track of the namespace hierarchy, but could be
  * modified to do so.  Also note that nothing in a properties file indicates the type

+ 1 - 1
gameplay/src/Quaternion.h

@@ -16,7 +16,7 @@ class Matrix;
  * Quaternions are typically used as a replacement for euler angles and rotation matrices as a way to achieve smooth interpolation and avoid gimbal lock.
  *
  * Note that this quaternion class does not automatically keep the quaternion normalized. Therefore, care must be taken to normalize the quaternion when neccessary, by calling the normalize method.
- * The package provides three methods for doing quaternion interpolation: lerp, slerp, and squad.
+ * This class provides three methods for doing quaternion interpolation: lerp, slerp, and squad.
  *
  * lerp (linear interpolation): the interpolation curve gives a straight line in quaternion space. It is simple and fast to compute. The only problem is that it does not provide constant angular velocity. Note that a constant velocity is not necessarily a requirement for a curve;
  * slerp (spherical linear interpolation): the interpolation curve forms a great arc on the quaternion unit sphere. Slerp provides constant angular velocity;

+ 2 - 2
gameplay/src/RadioButton.cpp

@@ -198,8 +198,8 @@ void RadioButton::update(const Rectangle& clip)
     }
     float iconWidth = size.x;
 
-    _textBounds.x += iconWidth;
-    _textBounds.width -= iconWidth;
+    _textBounds.x += iconWidth + 5;
+    _textBounds.width -= iconWidth + 5;
 }
 
 }

+ 17 - 15
gameplay/src/RadioButton.h

@@ -15,21 +15,23 @@ namespace gameplay
  * from a group can be selected at one time.
  *
  * The following properties are available for radio buttons:
- *
- * radioButton <RadioButton ID>
- * {
- *      style       = <Style ID>
- *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
- *      position    = <x, y>
- *      autoWidth   = <bool>
- *      autoHeight  = <bool>
- *      size        = <width, height>
- *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
- *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
- *      text        = <string>
- *      group       = <string>
- *      iconSize    = <width, height>   // The size to draw the radio button icon, if different from its size in the texture.
- * }
+
+ @verbatim
+    radioButton <RadioButton ID>
+    {
+         style       = <Style ID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+         group       = <string>
+         iconSize    = <width, height>   // The size to draw the radio button icon, if different from its size in the texture.
+    }
+ @endverbatim
  */
 class RadioButton : public Button
 {

+ 3 - 0
gameplay/src/RenderState.h

@@ -11,6 +11,9 @@ class Node;
 class NodeCloneContext;
 class Pass;
 
+/**
+ * Defines the render state of the graphics device.
+ */
 class RenderState : public Ref
 {
     friend class Game;

+ 4 - 0
gameplay/src/RenderTarget.h

@@ -7,6 +7,10 @@
 namespace gameplay
 {
 
+/**
+ * Represents a linear area of display memory and usually reside 
+ * in the display memory of the display card.
+ */
 class RenderTarget : public Ref
 {
 public:

+ 42 - 31
gameplay/src/SceneLoader.cpp

@@ -1,6 +1,6 @@
 #include "Base.h"
 #include "Game.h"
-#include "Package.h"
+#include "Bundle.h"
 #include "SceneLoader.h"
 
 namespace gameplay
@@ -61,8 +61,9 @@ Scene* SceneLoader::load(const char* filePath)
         SceneNodeProperty::ROTATE |
         SceneNodeProperty::SCALE |
         SceneNodeProperty::TRANSLATE | 
-        SceneNodeProperty::TRANSPARENT);
-    applyNodeProperties(scene, sceneProperties, SceneNodeProperty::CHARACTER | SceneNodeProperty::GHOST | SceneNodeProperty::RIGIDBODY);
+        SceneNodeProperty::TRANSPARENT |
+        SceneNodeProperty::DYNAMIC);
+    applyNodeProperties(scene, sceneProperties, SceneNodeProperty::CHARACTER | SceneNodeProperty::GHOSTOBJECT | SceneNodeProperty::RIGIDBODY);
     createAnimations(scene);
 
     // Find the physics properties object.
@@ -195,7 +196,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
         snp._type == SceneNodeProperty::MATERIAL ||
         snp._type == SceneNodeProperty::PARTICLE ||
         snp._type == SceneNodeProperty::CHARACTER ||
-        snp._type == SceneNodeProperty::GHOST ||
+        snp._type == SceneNodeProperty::GHOSTOBJECT ||
         snp._type == SceneNodeProperty::RIGIDBODY)
     {
         // Check to make sure the referenced properties object was loaded properly.
@@ -250,7 +251,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             break;
         }
         case SceneNodeProperty::CHARACTER:
-        case SceneNodeProperty::GHOST:
+        case SceneNodeProperty::GHOSTOBJECT:
         case SceneNodeProperty::RIGIDBODY:
         {
             // Check to make sure the referenced properties object was loaded properly.
@@ -283,20 +284,20 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             {
                 WARN_VARG("Attempting to set a 'character' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
             }
-            else if (snp._type == SceneNodeProperty::GHOST && strcmp(p->getNamespace(), "ghost") != 0)
+            else if (snp._type == SceneNodeProperty::GHOSTOBJECT && strcmp(p->getNamespace(), "ghostObject") != 0)
             {
-                WARN_VARG("Attempting to set a 'ghost' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                WARN_VARG("Attempting to set a 'ghostObject' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
             }
-            else if (snp._type == SceneNodeProperty::RIGIDBODY && strcmp(p->getNamespace(), "rigidbody") != 0)
+            else if (snp._type == SceneNodeProperty::RIGIDBODY && strcmp(p->getNamespace(), "rigidBody") != 0)
             {
-                WARN_VARG("Attempting to set a 'rigidbody' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                WARN_VARG("Attempting to set a 'rigidBody' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
             }
             else
             {
                 // If the scene file specifies a rigid body model, use it for creating the collision object.
                 Properties* np = sceneProperties->getNamespace(sceneNode._nodeID);
                 const char* name = NULL;
-                if (np && (name = np->getString("rigidbodymodel")))
+                if (np && (name = np->getString("rigidBodyModel")))
                 {
                     Node* modelNode = node->getScene()->findNode(name);
                     if (!modelNode)
@@ -307,13 +308,14 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                             WARN_VARG("Node '%s' does not have a model; attempting to use its model for collision object creation.", name);
                         else
                         {
-                            // Temporarily set rigidbody model on model so it's used during collision object creation.
+                            // Temporarily set rigidBody model on model so it's used during collision object creation.
                             Model* model = node->getModel();
+                            assert(model);
                         
                             // Up ref count to prevent node from releasing the model when we swap it.
                             model->addRef(); 
                         
-                            // Create collision object with new rigidbodymodel set.
+                            // Create collision object with new rigidBodyModel set.
                             node->setModel(modelNode->getModel());
                             node->setCollisionObject(p);
 
@@ -369,6 +371,11 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             node->setTransparent(true);
             break;
         }
+        case SceneNodeProperty::DYNAMIC:
+        {
+            node->setDynamic(true);
+            break;
+        }
         default:
             WARN_VARG("Unsupported node property type: %d.", snp._type);
             break;
@@ -437,15 +444,15 @@ void SceneLoader::applyNodeUrls(Scene* scene)
             {
                 // An external file was referenced, so load the node from file and then insert it into the scene with the new ID.
 
-                // TODO: Revisit this to determine if we should cache Package objects for the duration of the scene
-                // load to prevent constantly creating/destroying the same externally referenced packages each time
+                // TODO: Revisit this to determine if we should cache Bundle objects for the duration of the scene
+                // load to prevent constantly creating/destroying the same externally referenced bundles each time
                 // a url with a file is encountered.
-                Package* tmpPackage = Package::create(snp._file.c_str());
-                if (tmpPackage)
+                Bundle* tmpBundle = Bundle::create(snp._file.c_str());
+                if (tmpBundle)
                 {
                     if (sceneNode._exactMatch)
                     {
-                        Node* node = tmpPackage->loadNode(snp._id.c_str());
+                        Node* node = tmpBundle->loadNode(snp._id.c_str());
                         if (node)
                         {
                             node->setId(sceneNode._nodeID);
@@ -459,18 +466,18 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                     }
                     else
                     {
-                        // Search for nodes in the package using a partial match
+                        // Search for nodes in the bundle using a partial match
                         std::string partialMatch = snp._id;
-                        unsigned int objectCount = tmpPackage->getObjectCount();
+                        unsigned int objectCount = tmpBundle->getObjectCount();
                         unsigned int matchCount = 0;
                         for (unsigned int k = 0; k < objectCount; ++k)
                         {
-                            const char* objid = tmpPackage->getObjectID(k);
+                            const char* objid = tmpBundle->getObjectID(k);
                             if (strstr(objid, snp._id.c_str()) == objid)
                             {
                                 // This object ID matches (starts with).
                                 // Try to load this object as a Node.
-                                Node* node = tmpPackage->loadNode(objid);
+                                Node* node = tmpBundle->loadNode(objid);
                                 if (node)
                                 {
                                     // Construct a new node ID using _nodeID plus the remainder of the partial match.
@@ -489,7 +496,7 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                         }
                     }
 
-                    SAFE_RELEASE(tmpPackage);
+                    SAFE_RELEASE(tmpBundle);
                 }
                 else
                 {
@@ -553,15 +560,15 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::CHARACTER, ns->getString());
                 }
-                else if (strcmp(name, "ghost") == 0)
+                else if (strcmp(name, "ghostObject") == 0)
                 {
-                    addSceneNodeProperty(sceneNode, SceneNodeProperty::GHOST, ns->getString());
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::GHOSTOBJECT, ns->getString());
                 }
-                else if (strcmp(name, "rigidbody") == 0)
+                else if (strcmp(name, "rigidBody") == 0)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::RIGIDBODY, ns->getString());
                 }
-                else if (strcmp(name, "rigidbodymodel") == 0)
+                else if (strcmp(name, "rigidBodyModel") == 0)
                 {
                     // Ignore this for now. We process this when we do rigid body creation.
                 }
@@ -581,6 +588,10 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 {
                     addSceneNodeProperty(sceneNode, SceneNodeProperty::TRANSPARENT);
                 }
+                else if (strcmp(name, "dynamic") == 0)
+                {
+                    addSceneNodeProperty(sceneNode, SceneNodeProperty::DYNAMIC);
+                }
                 else
                 {
                     WARN_VARG("Unsupported node property: %s = %s", name, ns->getString());
@@ -754,19 +765,19 @@ PhysicsConstraint* SceneLoader::loadHingeConstraint(const Properties* constraint
 Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
 {
     // Load the main scene from the specified path.
-    Package* package = Package::create(_path.c_str());
-    if (!package)
+    Bundle* bundle = Bundle::create(_path.c_str());
+    if (!bundle)
     {
         WARN_VARG("Failed to load scene GPB file '%s'.", _path.c_str());
         return NULL;
     }
 
     const char* sceneID = strlen(sceneProperties->getId()) == 0 ? NULL : sceneProperties->getId();
-    Scene* scene = package->loadScene(sceneID);
+    Scene* scene = bundle->loadScene(sceneID);
     if (!scene)
     {
         WARN_VARG("Failed to load scene from '%s'.", _path.c_str());
-        SAFE_RELEASE(package);
+        SAFE_RELEASE(bundle);
         return NULL;
     }
 
@@ -779,7 +790,7 @@ Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
             scene->setActiveCamera(camera->getCamera());
     }
 
-    SAFE_RELEASE(package);
+    SAFE_RELEASE(bundle);
     return scene;
 }
 

+ 3 - 2
gameplay/src/SceneLoader.h

@@ -46,13 +46,14 @@ private:
             MATERIAL = 2,
             PARTICLE = 4,
             CHARACTER = 8,
-            GHOST = 16,
+            GHOSTOBJECT = 16,
             RIGIDBODY = 32,
             TRANSLATE = 64,
             ROTATE = 128,
             SCALE = 256,
             URL = 512,
-            TRANSPARENT = 1024
+            TRANSPARENT = 1024,
+            DYNAMIC = 2048
         };
 
         SceneNodeProperty(Type type, std::string file, std::string id, int index) : _type(type), _file(file), _id(id), _index(index) { }

+ 17 - 16
gameplay/src/Slider.h

@@ -11,22 +11,23 @@ namespace gameplay
 {
 
 /**
- *  A slider consists of a marker that can slide along a track between two end-caps.
- *  The following properties are available for sliders:
- *
- *  slider
- *  {
- *      style       = <styleID>                 // A Style from the Theme.
- *      position    = <x, y>                    // Position of the Control on-screen, measured in pixels.
- *      size        = <width, height>           // Size of the Control, measured in pixels.
- *      min         = <float>                   // The value of the left- / bottom-most point on the slider.
- *      max         = <float>                   // The value of the right- / top-most point on the slider.
- *      value       = <float>                   // The default position of the marker.
- *      step        = <float>                   // If greater than 0, force the marker to snap to discrete multiples of 'step'.
- *      text        = <string>                  // Text to display above, below or alongside the slider (depending on the style).
- *
-*      // TODO: orientation = <HORIZONTAL or VERTICAL>  // Determines whether a slider is stretched along its width or its height
- *  }
+ * A slider consists of a marker that can slide along a track between two end-caps.
+ * The following properties are available for sliders:
+
+ @verbatim
+    slider
+    {
+        style       = <styleID>                 // A Style from the Theme.
+        position    = <x, y>                    // Position of the Control on-screen, measured in pixels.
+        size        = <width, height>           // Size of the Control, measured in pixels.
+        min         = <float>                   // The value of the left- / bottom-most point on the slider.
+        max         = <float>                   // The value of the right- / top-most point on the slider.
+        value       = <float>                   // The default position of the marker.
+        step        = <float>                   // If greater than 0, force the marker to snap to discrete multiples of 'step'.
+        text        = <string>                  // Text to display above, below or alongside the slider (depending on the style).
+        // TODO: orientation = <HORIZONTAL or VERTICAL>  // Determines whether a slider is stretched along its width or its height
+    }
+ @endverbatim
  */
 class Slider : public Label
 {

+ 1 - 1
gameplay/src/SpriteBatch.h

@@ -24,7 +24,7 @@ namespace gameplay
  */
 class SpriteBatch
 {
-    friend class Package;
+    friend class Bundle;
 
 public:
 

+ 32 - 1
gameplay/src/TextBox.cpp

@@ -222,9 +222,40 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         // Insert character into string.
                         _text.insert(textIndex, 1, (char)key);
 
-                        // Get new location of cursor.
+                        // Get new location of caret.
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex + 1,
                             textAlignment, true, rightToLeft);
+
+                        if (key == ' ')
+                        {
+                            // If a space was entered, check that caret is still within bounds.
+                            if (_caretLocation.x >= _clip.x + _clip.width ||
+                                _caretLocation.y >= _clip.y + _clip.height)
+                            {
+                                // If not, undo the character insertion.
+                                _text.erase(textIndex, 1);
+                                font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex,
+                                    textAlignment, true, rightToLeft);
+
+                                // No need to check again.
+                                break;
+                            }
+                        }
+
+                        // Always check that the text still fits within the clip region.
+                        Rectangle textBounds;
+                        font->measureText(_text.c_str(), _clip, fontSize, &textBounds, textAlignment, true, true);
+                        if (textBounds.x <= _clip.x || textBounds.y <= _clip.y ||
+                            textBounds.width >= _clip.width || textBounds.height >= _clip.height)
+                        {
+                            // If not, undo the character insertion.
+                            _text.erase(textIndex, 1);
+                            font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex,
+                                textAlignment, true, rightToLeft);
+
+                            // TextBox is not dirty.
+                            break;
+                        }
                 
                         _dirty = true;
                         break;

+ 15 - 13
gameplay/src/TextBox.h

@@ -17,19 +17,21 @@ namespace gameplay
  * for the last keypress it received.
  *
  * The following properties are available for text boxes:
- *
- * label <labelID>
- * {
- *      style       = <styleID>
- *      alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
- *      position    = <x, y>
- *      autoWidth   = <bool>
- *      autoHeight  = <bool>
- *      size        = <width, height>
- *      width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
- *      height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
- *      text        = <string>
- * }
+
+ @verbatim
+    label <labelID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+    }
+ @endverbatim
  */
 class TextBox : public Label
 {

+ 1 - 1
gameplay/src/Theme.cpp

@@ -394,7 +394,7 @@ namespace gameplay
                     disabled->addRef();
                 }
 
-                Theme::Style* s = new Theme::Style(space->getId(), tw, th, margin, padding, normal, focus, active, disabled);
+                Theme::Style* s = new Theme::Style(theme, space->getId(), tw, th, margin, padding, normal, focus, active, disabled);
                 theme->_styles.push_back(s);
             }
 

+ 109 - 107
gameplay/src/Theme.h

@@ -21,113 +21,115 @@ namespace gameplay
  * are associated with a Control, and Font properties to apply to a Control's text.
  *
  * Below is an explanation of the properties that can be set within themes:
- *
- * theme
- * {
- *     texture = <Path to texture>
- * 
- *     // Describes a single image, to be used as a cursor.
- *     cursor <Cursor ID>
- *     {
- *         region = <x, y, width, height>
- *         color = <#ffffffff>
- *     }
- * 
- *     // Describes all the images used by a control for one or more states.
- *     imageList <ImageList ID>
- *     {
- *         image checked
- *         {
- *             region = <x, y, width, height>
- *         }
- * 
- *         image unchecked
- *         {
- *             region = <x, y, width, height>
- *             color = <#fffffffff>            // Optionally override image-list color.
- *         }
- * 
- *         color = <#fffffffff>    // Default blend color for images that don't specify their own.
- *     }
- *     
- *     // Defines the border and background of a Control.
- *     skin <Skin ID>
- *     {
- *         // The corners and edges of the given region will be used as border sprites.
- *         border
- *         {
- *             top     =   <int>   // Height of top border, top corners.
- *             bottom  =   <int>   // Height of bottom border, bottom corners.
- *             left    =   <int>   // Width of left border, left corners.
- *             right   =   <int>   // Width of right border, right corners.
- *         }
- *         
- *         region  =   <x, y, width, height>   // Total container region including entire border.
- *         color   =   <#ffffffff>             // Tint to apply to skin.
- *     }
- *     
- *     style <Style ID>
- *     {
- *         // Layouts may make use of a style's margin to put space between adjacent controls.
- *         margin
- *         {
- *             top     =   <int>
- *             bottom  =   <int>
- *             left    =   <int>
- *             right   =   <int>        
- *         }
- *         
- *         // Padding is the space between a control's border and its content.
- *         padding
- *         {
- *             top     =   <int>
- *             bottom  =   <int>
- *             left    =   <int>
- *             right   =   <int>        
- *         }
- *         
- *         // Properties used when in control is in the normal state.
- *         stateNormal
- *         {
- *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
- *             imageList = <ImageList ID>
- * 
- *             cursor      =   <Cursor ID>                 // Cursor to use when the mouse is over this control.
- *             font        =   <Path to font>              // Font to use for rendering text.
- *             fontSize    =   <int>                       // Size of text.
- *             textColor   =   <#ffffffff>                 // Color of text.
- *             alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
- *             rightToLeft =   <bool>                      // Whether to draw text from right to left.
- *             opacity     =   <float>                     // Opacity to apply to all text/border/icon colors.
- *         }
- *         
- *         // Properties used when in control is in the focus state
- *         // If not specified, the 'normal' overlay will be used.
- *         stateFocus
- *         {
- *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
- *             ...
- *         }
- *         
- *         // Properties used when in control is in the focus. 
- *         // This is when a touch/mouse is down within the control.
- *         // If not specified, the 'normal' overlay will be used.
- *         stateActive
- *         {
- *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
- *             ...
- *         }
- * 
- *         // Properties used when in control is in the focus. 
- *         // This is when a touch/mouse is down within the control.
- *         // If not specified, the 'normal' overlay will be used.
- *         state-disabled
- *         {
- *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
- *             ...        
- *         }
- *     }
- * }
+
+@verbatim
+    theme
+    {
+        texture = <Path to texture>
+
+        // Describes a single image, to be used as a cursor.
+        cursor <Cursor ID>
+        {
+            region = <x, y, width, height>
+            color = <#ffffffff>
+        }
+
+        // Describes all the images used by a control for one or more states.
+        imageList <ImageList ID>
+        {
+            image checked
+            {
+                region = <x, y, width, height>
+            }
+
+            image unchecked
+            {
+                region = <x, y, width, height>
+                color = <#fffffffff>            // Optionally override image-list color.
+            }
+
+            color = <#fffffffff>    // Default blend color for images that don't specify their own.
+        }
+    
+        // Defines the border and background of a Control.
+        skin <Skin ID>
+        {
+            // The corners and edges of the given region will be used as border sprites.
+            border
+            {
+                top     =   <int>   // Height of top border, top corners.
+                bottom  =   <int>   // Height of bottom border, bottom corners.
+                left    =   <int>   // Width of left border, left corners.
+                right   =   <int>   // Width of right border, right corners.
+            }
+        
+            region  =   <x, y, width, height>   // Total container region including entire border.
+            color   =   <#ffffffff>             // Tint to apply to skin.
+        }
+    
+        style <Style ID>
+        {
+            // Layouts may make use of a style's margin to put space between adjacent controls.
+            margin
+            {
+                top     =   <int>
+                bottom  =   <int>
+                left    =   <int>
+                right   =   <int>        
+            }
+        
+            // Padding is the space between a control's border and its content.
+            padding
+            {
+                top     =   <int>
+                bottom  =   <int>
+                left    =   <int>
+                right   =   <int>        
+            }
+        
+            // Properties used when in control is in the normal state.
+            stateNormal
+            {
+                skin   =   <Skin ID>             // Skin to use for border and background sprites.
+                imageList = <ImageList ID>
+
+                cursor      =   <Cursor ID>                 // Cursor to use when the mouse is over this control.
+                font        =   <Path to font>              // Font to use for rendering text.
+                fontSize    =   <int>                       // Size of text.
+                textColor   =   <#ffffffff>                 // Color of text.
+                alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
+                rightToLeft =   <bool>                      // Whether to draw text from right to left.
+                opacity     =   <float>                     // Opacity to apply to all text/border/icon colors.
+            }
+        
+            // Properties used when in control is in the focus state
+            // If not specified, the 'normal' overlay will be used.
+            stateFocus
+            {
+                skin   =   <Skin ID>             // Skin to use for border and background sprites.
+                ...
+            }
+        
+            // Properties used when in control is in the focus. 
+            // This is when a touch/mouse is down within the control.
+            // If not specified, the 'normal' overlay will be used.
+            stateActive
+            {
+                skin   =   <Skin ID>             // Skin to use for border and background sprites.
+                ...
+            }
+
+            // Properties used when in control is in the focus. 
+            // This is when a touch/mouse is down within the control.
+            // If not specified, the 'normal' overlay will be used.
+            state-disabled
+            {
+                skin   =   <Skin ID>             // Skin to use for border and background sprites.
+                ...        
+            }
+        }
+    }
+@endverbatim
  *
  */
 class Theme: public Ref

+ 4 - 4
gameplay/src/ThemeStyle.cpp

@@ -6,10 +6,10 @@ namespace gameplay
 /****************
  * Theme::Style *
  ****************/
-Theme::Style::Style(const char* id, float tw, float th,
+Theme::Style::Style(Theme* theme, 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)
+    : _theme(theme), _id(id), _tw(tw), _th(th), _margin(margin), _padding(padding)
 {
     _overlays[OVERLAY_NORMAL] = normal;
     _overlays[OVERLAY_FOCUS] = focus;
@@ -76,8 +76,8 @@ const Theme::Padding& Theme::Style::getPadding() const
 }
     
 /*************************
-    * Theme::Style::Overlay *
-    *************************/
+ * Theme::Style::Overlay *
+ *************************/
 Theme::Style::Overlay* Theme::Style::Overlay::create()
 {
     Overlay* overlay = new Overlay();

+ 3 - 2
gameplay/src/ThemeStyle.h

@@ -162,7 +162,7 @@ private:
     /**
      * Constructor.
      */
-    Style(const char* id, float tw, float th,
+    Style(Theme* theme, const char* id, float tw, float th,
           const Theme::Margin& margin, const Theme::Padding& padding,
           Overlay* normal, Overlay* focus, Overlay* active, Overlay* disabled);
 
@@ -209,7 +209,8 @@ private:
      * The margin is used by Layouts other than AbsoluteLayout to put space between Controls.
      */
     void setMargin(float top, float bottom, float left, float right);
-        
+    
+    Theme* _theme;
     std::string _id;
     float _tw;
     float _th;

+ 60 - 51
gameplay/src/Transform.cpp

@@ -7,28 +7,28 @@ namespace gameplay
 {
 
 Transform::Transform()
-    : _matrixDirty(false), _listeners(NULL)
+    : _matrixDirtyBits(0), _listeners(NULL)
 {
     _targetType = AnimationTarget::TRANSFORM;
     _scale.set(Vector3::one());
 }
 
 Transform::Transform(const Vector3& scale, const Quaternion& rotation, const Vector3& translation)
-    : _matrixDirty(false), _listeners(NULL)
+    : _matrixDirtyBits(0), _listeners(NULL)
 {
     _targetType = AnimationTarget::TRANSFORM;
     set(scale, rotation, translation);
 }
 
 Transform::Transform(const Vector3& scale, const Matrix& rotation, const Vector3& translation)
-    : _matrixDirty(false), _listeners(NULL)
+    : _matrixDirtyBits(0), _listeners(NULL)
 {
     _targetType = AnimationTarget::TRANSFORM;
     set(scale, rotation, translation);
 }
 
 Transform::Transform(const Transform& copy)
-    : _matrixDirty(false), _listeners(NULL)
+    : _matrixDirtyBits(0), _listeners(NULL)
 {
     _targetType = AnimationTarget::TRANSFORM;
     set(copy);
@@ -41,40 +41,40 @@ Transform::~Transform()
 
 const Matrix& Transform::getMatrix() const
 {
-    if (_matrixDirty)
+    if (_matrixDirtyBits)
     {
-        _matrixDirty = false;
-
         bool hasTranslation = !_translation.isZero();
         bool hasScale = !_scale.isOne();
         bool hasRotation = !_rotation.isIdentity();
 
         // Compose the matrix in TRS order since we use column-major matrices with column vectors and
         // multiply M*v (as opposed to XNA and DirectX that use row-major matrices with row vectors and multiply v*M).
-        if (hasTranslation)
+        if (hasTranslation || (_matrixDirtyBits & DIRTY_TRANSLATION) == DIRTY_TRANSLATION)
         {
             Matrix::createTranslation(_translation, &_matrix);
-            if (hasRotation)
+            if (hasRotation || (_matrixDirtyBits & DIRTY_ROTATION) == DIRTY_ROTATION)
             {
                 _matrix.rotate(_rotation);
             }
-            if (hasScale)
+            if (hasScale || (_matrixDirtyBits & DIRTY_SCALE) == DIRTY_SCALE)
             {
                 _matrix.scale(_scale);
             }
         }
-        else if (hasRotation)
+        else if (hasRotation || (_matrixDirtyBits & DIRTY_ROTATION) == DIRTY_ROTATION)
         {
             Matrix::createRotation(_rotation, &_matrix);
-            if (hasScale)
+            if (hasScale || (_matrixDirtyBits & DIRTY_SCALE) == DIRTY_SCALE)
             {
                 _matrix.scale(_scale);
             }
         }
-        else if (hasScale)
+        else if (hasScale || (_matrixDirtyBits & DIRTY_SCALE) == DIRTY_SCALE)
         {
             Matrix::createScale(_scale, &_matrix);
         }
+
+        _matrixDirtyBits = 0;
     }
 
     return _matrix;
@@ -231,13 +231,13 @@ void Transform::rotate(float qx, float qy, float qz, float qw)
 {
     Quaternion q(qx, qy, qz, qw);
     _rotation.multiply(q);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::rotate(const Quaternion& rotation)
 {
     _rotation.multiply(rotation);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::rotate(const Vector3& axis, float angle)
@@ -246,7 +246,7 @@ void Transform::rotate(const Vector3& axis, float angle)
     Quaternion::createFromAxisAngle(axis, angle, &rotationQuat);
     _rotation.multiply(rotationQuat);
     _rotation.normalize();
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::rotate(const Matrix& rotation)
@@ -254,7 +254,7 @@ void Transform::rotate(const Matrix& rotation)
     Quaternion rotationQuat;
     Quaternion::createFromRotationMatrix(rotation, &rotationQuat);
     _rotation.multiply(rotationQuat);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::rotateX(float angle)
@@ -262,7 +262,7 @@ void Transform::rotateX(float angle)
     Quaternion rotationQuat;
     Quaternion::createFromAxisAngle(Vector3::unitX(), angle, &rotationQuat);
     _rotation.multiply(rotationQuat);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::rotateY(float angle)
@@ -270,7 +270,7 @@ void Transform::rotateY(float angle)
     Quaternion rotationQuat;
     Quaternion::createFromAxisAngle(Vector3::unitY(), angle, &rotationQuat);
     _rotation.multiply(rotationQuat);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::rotateZ(float angle)
@@ -278,13 +278,13 @@ void Transform::rotateZ(float angle)
     Quaternion rotationQuat;
     Quaternion::createFromAxisAngle(Vector3::unitZ(), angle, &rotationQuat);
     _rotation.multiply(rotationQuat);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::scale(float scale)
 {
     _scale.scale(scale);
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::scale(float sx, float sy, float sz)
@@ -292,7 +292,7 @@ void Transform::scale(float sx, float sy, float sz)
     _scale.x *= sx;
     _scale.y *= sy;
     _scale.z *= sz;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::scale(const Vector3& scale)
@@ -300,25 +300,25 @@ void Transform::scale(const Vector3& scale)
     _scale.x *= scale.x;
     _scale.y *= scale.y;
     _scale.z *= scale.z;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::scaleX(float sx)
 {
     _scale.x *= sx;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::scaleY(float sy)
 {
     _scale.y *= sy;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::scaleZ(float sz)
 {
     _scale.z *= sz;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::set(const Vector3& scale, const Quaternion& rotation, const Vector3& translation)
@@ -326,7 +326,7 @@ void Transform::set(const Vector3& scale, const Quaternion& rotation, const Vect
     _scale.set(scale);
     _rotation.set(rotation);
     _translation.set(translation);
-    dirty();
+    dirty(DIRTY_TRANSLATION | DIRTY_ROTATION | DIRTY_SCALE);
 }
 
 void Transform::set(const Vector3& scale, const Matrix& rotation, const Vector3& translation)
@@ -336,7 +336,7 @@ void Transform::set(const Vector3& scale, const Matrix& rotation, const Vector3&
     Quaternion::createFromRotationMatrix(rotation, &rotationQuat);
     _rotation.set(rotationQuat);
     _translation.set(translation);
-    dirty();
+    dirty(DIRTY_TRANSLATION | DIRTY_ROTATION | DIRTY_SCALE);
 }
 
 void Transform::set(const Vector3& scale, const Vector3& axis, float angle, const Vector3& translation)
@@ -344,6 +344,7 @@ void Transform::set(const Vector3& scale, const Vector3& axis, float angle, cons
     _scale.set(scale);
     _rotation.set(axis, angle);
     _translation.set(translation);
+    dirty(DIRTY_TRANSLATION | DIRTY_ROTATION | DIRTY_SCALE);
 }
 
 void Transform::set(const Transform& transform)
@@ -351,55 +352,63 @@ void Transform::set(const Transform& transform)
     _scale.set(transform._scale);
     _rotation.set(transform._rotation);
     _translation.set(transform._translation);
-    dirty();
+    dirty(DIRTY_TRANSLATION | DIRTY_ROTATION | DIRTY_SCALE);
+}
+
+void Transform::setIdentity()
+{
+    _scale.set(1.0f, 1.0f, 1.0f);
+    _rotation.setIdentity();
+    _translation.set(0.0f, 0.0f, 0.0f);
+    dirty(DIRTY_TRANSLATION | DIRTY_ROTATION | DIRTY_SCALE);
 }
 
 void Transform::setScale(float scale)
 {
     _scale.set(scale, scale, scale);
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::setScale(float sx, float sy, float sz)
 {
     _scale.set(sx, sy, sz);
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::setScale(const Vector3& scale)
 {
     _scale.set(scale);
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::setScaleX(float sx)
 {
     _scale.x = sx;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::setScaleY(float sy)
 {
     _scale.y = sy;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::setScaleZ(float sz)
 {
     _scale.z = sz;
-    dirty();
+    dirty(DIRTY_SCALE);
 }
 
 void Transform::setRotation(const Quaternion& rotation)
 {
     _rotation.set(rotation);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::setRotation(float qx, float qy, float qz, float qw)
 {
     _rotation.set(qx, qy, qz, qw);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::setRotation(const Matrix& rotation)
@@ -407,43 +416,43 @@ void Transform::setRotation(const Matrix& rotation)
     Quaternion rotationQuat;
     Quaternion::createFromRotationMatrix(rotation, &rotationQuat);
     _rotation.set(rotationQuat);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::setRotation(const Vector3& axis, float angle)
 {
     _rotation.set(axis, angle);
-    dirty();
+    dirty(DIRTY_ROTATION);
 }
 
 void Transform::setTranslation(const Vector3& translation)
 {
     _translation.set(translation);
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::setTranslation(float tx, float ty, float tz)
 {
     _translation.set(tx, ty, tz);
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::setTranslationX(float tx)
 {
     _translation.x = tx;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::setTranslationY(float ty)
 {
     _translation.y = ty;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::setTranslationZ(float tz)
 {
     _translation.z = tz;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::translate(float tx, float ty, float tz)
@@ -451,7 +460,7 @@ void Transform::translate(float tx, float ty, float tz)
     _translation.x += tx;
     _translation.y += ty;
     _translation.z += tz;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::translate(const Vector3& translation)
@@ -459,25 +468,25 @@ void Transform::translate(const Vector3& translation)
     _translation.x += translation.x;
     _translation.y += translation.y;
     _translation.z += translation.z;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::translateX(float tx)
 {
     _translation.x += tx;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::translateY(float ty)
 {
     _translation.y += ty;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::translateZ(float tz)
 {
     _translation.z += tz;
-    dirty();
+    dirty(DIRTY_TRANSLATION);
 }
 
 void Transform::translateLeft(float amount)
@@ -737,9 +746,9 @@ void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value,
     }
 }
 
-void Transform::dirty()
+void Transform::dirty(char matrixDirtyBits)
 {
-    _matrixDirty = true;
+    _matrixDirtyBits |= matrixDirtyBits;
     transformChanged();
 }
 

+ 14 - 2
gameplay/src/Transform.h

@@ -464,6 +464,11 @@ public:
      */
     void set(const Transform& transform);
 
+    /**
+     * Sets this transform to the identity transform.
+     */
+    void setIdentity();
+
     /**
      * Sets the scale factor along all axes for this transform
      * to the specified value.
@@ -736,10 +741,17 @@ protected:
         long cookie;
     };
 
+    enum MatrixDirtyBits
+    {
+        DIRTY_TRANSLATION = 0x01,
+        DIRTY_SCALE = 0x02,
+        DIRTY_ROTATION = 0x04,
+    };
+
     /**
      * Marks this transform as dirty and fires transformChanged().
      */
-    void dirty();
+    void dirty(char matrixDirtyBits);
 
     /**
      * Called when the transform changes.
@@ -758,7 +770,7 @@ protected:
     Quaternion _rotation;
     Vector3 _translation;
     mutable Matrix _matrix;
-    mutable bool _matrixDirty;
+    mutable char _matrixDirtyBits;
     std::list<TransformListener>* _listeners;
 
 private:

+ 1 - 1
gameplay/src/gameplay.h

@@ -6,7 +6,7 @@
 #include "Touch.h"
 #include "Mouse.h"
 #include "FileSystem.h"
-#include "Package.h"
+#include "Bundle.h"
 
 // Math
 #include "Rectangle.h"