Browse Source

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

Kieran Cunney 13 years ago
parent
commit
17ebf7c2e2

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

@@ -349,7 +349,7 @@
 		42475CDD147208A000610A6A /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0420;
+				LastUpgradeCheck = 0430;
 			};
 			buildConfigurationList = 42475CE0147208A000610A6A /* Build configuration list for PBXProject "gameplay-encoder" */;
 			compatibilityVersion = "Xcode 3.2";

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

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

+ 22 - 14
gameplay-newproject.sh

@@ -102,6 +102,7 @@ if [[ "$className" == "" ]]; then
 fi
 echo 
 
+
 echo
 echo "7. Enter the project path."
 echo
@@ -127,24 +128,31 @@ if [ -e $projPath ]; then
 	exit -2
 fi
 
-# Generate relative path from project folder to gameplay folder
-if [[ ${projPath:0:1} == "/" ]]; then
-	gpPathAbs=`pwd`
-	common_path=$projPath
-	back=
-	while [ "${gpPathAbs#$common_path}" = "${gpPathAbs}" ]; do
-		common_path=$(dirname $common_path)
-		back="../${back}"
-	done
-	gpPath=${back}${gpPathAbs#$common_path/}
-else
-	gpPath=$projPath
-fi
-
 # Make required source folder directories
+mkdir -p "$projPath"
 mkdir -p "$projPath/src"
 mkdir -p "$projPath/res"
 
+if [[ ${projPath:0:1} != "/" ]]; then
+	currPwd=`pwd`
+	projPath=`cd $projPath; pwd`
+	`cd $currPwd`	
+fi
+
+# Generate relative path from project folder to gameplay folder
+gpPathAbs=`pwd`
+common_path=$projPath
+back=
+while [ "${gpPathAbs#$common_path}" = "${gpPathAbs}" ]; do
+	common_path=$(dirname $common_path)
+	back="../${back}"
+done
+gpPath=${back}${gpPathAbs#$common_path/}
+if [[ ${gpPathAbs} == ${common_path} ]]; then
+	gpPath=${back}
+fi
+
+
 # Below does copy, then uses 'sed' with -i for inplace editing
 # Alternative below uses sed to do a input then output skipping the copy
 # sed "s/TEMPLATE_PROJECT/$projectName/g" "gameplay-template/gameplay-template.vcxproj" > "$projPath/$projName.vcxproj"

+ 27 - 76
gameplay-template/gameplay-template.xcodeproj/project.pbxproj

@@ -33,35 +33,18 @@
 		5B61611F14CCC24C0073B857 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332D1491A7810098216A /* libz.dylib */; };
 		5B61612614CCC24C0073B857 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 42C932ED1491A4CB0098216A /* icon.png */; };
 		5B61612714CCC24C0073B857 /* res in Resources */ = {isa = PBXBuildFile; fileRef = 42C932F21491A53E0098216A /* res */; };
-		5B61613114CCC33A0073B857 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61612F14CCC33A0073B857 /* OpenAL.framework */; };
-		5B61613214CCC33A0073B857 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613014CCC33A0073B857 /* OpenGLES.framework */; };
-		5B61613414CCC3420073B857 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613314CCC3420073B857 /* UIKit.framework */; };
-		5B61613614CCC34A0073B857 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613514CCC3490073B857 /* CoreMotion.framework */; };
-		5B61613814CCC3500073B857 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B61613714CCC3500073B857 /* QuartzCore.framework */; };
+		5B8D58AB1512584A00DA5991 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B8D58A51512584A00DA5991 /* CoreMotion.framework */; };
+		5B8D58AC1512584A00DA5991 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B8D58A61512584A00DA5991 /* Foundation.framework */; };
+		5B8D58AD1512584A00DA5991 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B8D58A71512584A00DA5991 /* OpenAL.framework */; };
+		5B8D58AE1512584A00DA5991 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B8D58A81512584A00DA5991 /* OpenGLES.framework */; };
+		5B8D58AF1512584A00DA5991 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B8D58A91512584A00DA5991 /* QuartzCore.framework */; };
+		5B8D58B01512584A00DA5991 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B8D58AA1512584A00DA5991 /* UIKit.framework */; };
 		5BC4E84E150F913F00CBE1C0 /* shaders in Copy GamePlay Bundle Resources */ = {isa = PBXBuildFile; fileRef = 5BC4E849150F911D00CBE1C0 /* shaders */; };
 		5BC4E84F150F913F00CBE1C0 /* textures in Copy GamePlay Bundle Resources */ = {isa = PBXBuildFile; fileRef = 5BC4E84A150F911D00CBE1C0 /* textures */; };
 		5BC4E851150F915300CBE1C0 /* shaders in Copy GamePlay Bundle Resources */ = {isa = PBXBuildFile; fileRef = 5BC4E849150F911D00CBE1C0 /* shaders */; };
 		5BC4E852150F915300CBE1C0 /* textures in Copy GamePlay Bundle Resources */ = {isa = PBXBuildFile; fileRef = 5BC4E84A150F911D00CBE1C0 /* textures */; };
-		5BC4E8B0150F943A00CBE1C0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BC4E8AF150F943A00CBE1C0 /* Foundation.framework */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXContainerItemProxy section */
-		5BC4E7BF150F8B7B00CBE1C0 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = 5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 4234D99A14686C52003031B3;
-			remoteInfo = "gameplay-macos";
-		};
-		5BC4E7C1150F8B7B00CBE1C0 /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = 5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 5B04C5CA14BFCFE100EB0071;
-			remoteInfo = "gameplay-ios";
-		};
-/* End PBXContainerItemProxy section */
-
 /* Begin PBXCopyFilesBuildPhase section */
 		5BC4E84D150F912B00CBE1C0 /* Copy GamePlay Bundle Resources */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -110,15 +93,15 @@
 		5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-macos.plist"; sourceTree = "<group>"; };
 		5B61612C14CCC24C0073B857 /* TEMPLATE_PROJECT-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		5B61612E14CCC24D0073B857 /* TEMPLATE_PROJECT-ios.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TEMPLATE_PROJECT-ios.plist"; sourceTree = "<group>"; };
-		5B61612F14CCC33A0073B857 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
-		5B61613014CCC33A0073B857 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
-		5B61613314CCC3420073B857 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
-		5B61613514CCC3490073B857 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
-		5B61613714CCC3500073B857 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
-		5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = gameplay.xcodeproj; path = /Developer/../Users/bslack/src/git/GamePlay/gameplay/gameplay.xcodeproj; sourceTree = "<absolute>"; };
-		5BC4E849150F911D00CBE1C0 /* shaders */ = {isa = PBXFileReference; lastKnownFileType = folder; name = shaders; path = "/Users/bslack/src/git/GamePlay/gameplay-template/../gameplay/res/shaders"; sourceTree = "<absolute>"; };
-		5BC4E84A150F911D00CBE1C0 /* textures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = textures; path = "/Users/bslack/src/git/GamePlay/gameplay-template/../gameplay/res/textures"; sourceTree = "<absolute>"; };
-		5BC4E8AF150F943A00CBE1C0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5B8D58A51512584A00DA5991 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
+		5B8D58A61512584A00DA5991 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5B8D58A71512584A00DA5991 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		5B8D58A81512584A00DA5991 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
+		5B8D58A91512584A00DA5991 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
+		5B8D58AA1512584A00DA5991 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = gameplay.xcodeproj; path = GAMEPLAY_PATH/gameplay/gameplay.xcodeproj; sourceTree = SOURCE_ROOT; };
+		5BC4E849150F911D00CBE1C0 /* shaders */ = {isa = PBXFileReference; lastKnownFileType = text; name = shaders; path = GAMEPLAY_PATH/gameplay/res/shaders; sourceTree = SOURCE_ROOT; };
+		5BC4E84A150F911D00CBE1C0 /* textures */ = {isa = PBXFileReference; lastKnownFileType = text; name = textures; path = GAMEPLAY_PATH/gameplay/res/textures; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -145,12 +128,12 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5BC4E8B0150F943A00CBE1C0 /* Foundation.framework in Frameworks */,
-				5B61613814CCC3500073B857 /* QuartzCore.framework in Frameworks */,
-				5B61613614CCC34A0073B857 /* CoreMotion.framework in Frameworks */,
-				5B61613414CCC3420073B857 /* UIKit.framework in Frameworks */,
-				5B61613114CCC33A0073B857 /* OpenAL.framework in Frameworks */,
-				5B61613214CCC33A0073B857 /* OpenGLES.framework in Frameworks */,
+				5B8D58AB1512584A00DA5991 /* CoreMotion.framework in Frameworks */,
+				5B8D58AC1512584A00DA5991 /* Foundation.framework in Frameworks */,
+				5B8D58AD1512584A00DA5991 /* OpenAL.framework in Frameworks */,
+				5B8D58AE1512584A00DA5991 /* OpenGLES.framework in Frameworks */,
+				5B8D58AF1512584A00DA5991 /* QuartzCore.framework in Frameworks */,
+				5B8D58B01512584A00DA5991 /* UIKit.framework in Frameworks */,
 				5B61611814CCC24C0073B857 /* libgameplay.a in Frameworks */,
 				5B61611914CCC24C0073B857 /* libbullet.a in Frameworks */,
 				5B61611A14CCC24C0073B857 /* libogg.a in Frameworks */,
@@ -225,12 +208,12 @@
 		5B61613914CCC3560073B857 /* iOS */ = {
 			isa = PBXGroup;
 			children = (
-				5BC4E8AF150F943A00CBE1C0 /* Foundation.framework */,
-				5B61613714CCC3500073B857 /* QuartzCore.framework */,
-				5B61613514CCC3490073B857 /* CoreMotion.framework */,
-				5B61613314CCC3420073B857 /* UIKit.framework */,
-				5B61612F14CCC33A0073B857 /* OpenAL.framework */,
-				5B61613014CCC33A0073B857 /* OpenGLES.framework */,
+				5B8D58A51512584A00DA5991 /* CoreMotion.framework */,
+				5B8D58A61512584A00DA5991 /* Foundation.framework */,
+				5B8D58A71512584A00DA5991 /* OpenAL.framework */,
+				5B8D58A81512584A00DA5991 /* OpenGLES.framework */,
+				5B8D58A91512584A00DA5991 /* QuartzCore.framework */,
+				5B8D58AA1512584A00DA5991 /* UIKit.framework */,
 			);
 			name = iOS;
 			sourceTree = "<group>";
@@ -246,15 +229,6 @@
 			name = "Mac OS X";
 			sourceTree = "<group>";
 		};
-		5BC4E7BB150F8B7B00CBE1C0 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				5BC4E7C0150F8B7B00CBE1C0 /* libgameplay.a */,
-				5BC4E7C2150F8B7B00CBE1C0 /* libgameplay.a */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
 		5BC4E825150F8CE600CBE1C0 /* GamePlay */ = {
 			isa = PBXGroup;
 			children = (
@@ -324,12 +298,6 @@
 			mainGroup = 42C932B11491A0DB0098216A;
 			productRefGroup = 42C932BD1491A0DB0098216A /* Products */;
 			projectDirPath = "";
-			projectReferences = (
-				{
-					ProductGroup = 5BC4E7BB150F8B7B00CBE1C0 /* Products */;
-					ProjectRef = 5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */;
-				},
-			);
 			projectRoot = "";
 			targets = (
 				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX */,
@@ -338,23 +306,6 @@
 		};
 /* End PBXProject section */
 
-/* Begin PBXReferenceProxy section */
-		5BC4E7C0150F8B7B00CBE1C0 /* libgameplay.a */ = {
-			isa = PBXReferenceProxy;
-			fileType = archive.ar;
-			path = libgameplay.a;
-			remoteRef = 5BC4E7BF150F8B7B00CBE1C0 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
-		5BC4E7C2150F8B7B00CBE1C0 /* libgameplay.a */ = {
-			isa = PBXReferenceProxy;
-			fileType = archive.ar;
-			path = libgameplay.a;
-			remoteRef = 5BC4E7C1150F8B7B00CBE1C0 /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
-/* End PBXReferenceProxy section */
-
 /* Begin PBXResourcesBuildPhase section */
 		42C932BA1491A0DB0098216A /* Resources */ = {
 			isa = PBXResourcesBuildPhase;

+ 2 - 0
gameplay/gameplay.vcxproj

@@ -67,6 +67,7 @@
     <ClCompile Include="src\PhysicsController.cpp" />
     <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
     <ClCompile Include="src\PhysicsGenericConstraint.cpp" />
+    <ClCompile Include="src\PhysicsGhostObject.cpp" />
     <ClCompile Include="src\PhysicsHingeConstraint.cpp" />
     <ClCompile Include="src\PhysicsMotionState.cpp" />
     <ClCompile Include="src\PhysicsRigidBody.cpp" />
@@ -156,6 +157,7 @@
     <ClInclude Include="src\PhysicsController.h" />
     <ClInclude Include="src\PhysicsFixedConstraint.h" />
     <ClInclude Include="src\PhysicsGenericConstraint.h" />
+    <ClInclude Include="src\PhysicsGhostObject.h" />
     <ClInclude Include="src\PhysicsHingeConstraint.h" />
     <ClInclude Include="src\PhysicsMotionState.h" />
     <ClInclude Include="src\PhysicsRigidBody.h" />

+ 7 - 1
gameplay/gameplay.vcxproj.filters

@@ -270,6 +270,9 @@
     <ClCompile Include="src\PhysicsCollisionObject.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\PhysicsGhostObject.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -533,6 +536,9 @@
     <ClInclude Include="src\TimeListener.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\PhysicsGhostObject.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shaders\bumped-specular.vsh">
@@ -667,4 +673,4 @@
       <Filter>src</Filter>
     </None>
   </ItemGroup>
-</Project>
+</Project>

+ 180 - 208
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -13,12 +13,9 @@
 		4208DEEA14A4079F00D3C511 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEE714A4079F00D3C511 /* Image.h */; };
 		4208DEEC14A407B900D3C511 /* Keyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEEB14A407B900D3C511 /* Keyboard.h */; };
 		4208DEEE14A407D500D3C511 /* Touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4208DEED14A407D500D3C511 /* Touch.h */; };
-		4220A6E8146B122B00CAEB3A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4220A6E7146B122B00CAEB3A /* QuartzCore.framework */; };
 		4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4234D99D14686C52003031B3 /* Cocoa.framework */; };
 		428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 428390971489D6E800E2B2F5 /* SceneLoader.cpp */; };
 		4283909A1489D6E800E2B2F5 /* SceneLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 428390981489D6E800E2B2F5 /* SceneLoader.h */; };
-		4299EFA9146AC94300FF4A73 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4299EFA8146AC94300FF4A73 /* OpenGL.framework */; };
-		4299EFAB146AC94B00FF4A73 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4299EFAA146AC94B00FF4A73 /* OpenAL.framework */; };
 		42CCD556146EC1EB00353661 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CCD555146EC1EB00353661 /* libpng.a */; };
 		42CD0DAB147D8EA80000361E /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA6147D8EA80000361E /* libbullet.a */; };
 		42CD0DAC147D8EA80000361E /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42CD0DA7147D8EA80000361E /* libogg.a */; };
@@ -297,15 +294,24 @@
 		5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4201818E14A41B18008C3F56 /* MeshBatch.h */; };
 		5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */; };
 		5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */; };
-		5B04C5F614BFE50100EB0071 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F514BFE50100EB0071 /* UIKit.framework */; };
-		5B04C5F814BFE50B00EB0071 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */; };
-		5B04C5FA14BFE51100EB0071 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5F914BFE51000EB0071 /* OpenGLES.framework */; };
-		5B04C5FC14BFE51600EB0071 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B04C5FB14BFE51600EB0071 /* OpenAL.framework */; };
-		5B5ADCE314C22DF900AC6109 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADCE214C22DF900AC6109 /* libz.dylib */; };
-		5B5ADCE514C22E1F00AC6109 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADCE414C22E1F00AC6109 /* libz.dylib */; };
-		5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADD2E14C2439700AC6109 /* Foundation.framework */; };
+		5B2BC75F1512514500D176CD /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC75D1512514500D176CD /* OpenAL.framework */; };
+		5B2BC7601512514500D176CD /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC75E1512514500D176CD /* OpenGL.framework */; };
+		5B2BC7621512514D00D176CD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC7611512514D00D176CD /* QuartzCore.framework */; };
+		5B2BC7641512516B00D176CD /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC7631512516B00D176CD /* libz.dylib */; };
+		5B2BC765151251EB00D176CD /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC7561512507500D176CD /* CoreMotion.framework */; };
+		5B2BC76D151251EB00D176CD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC766151251EB00D176CD /* CoreGraphics.framework */; };
+		5B2BC76E151251EB00D176CD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC767151251EB00D176CD /* Foundation.framework */; };
+		5B2BC76F151251EB00D176CD /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC768151251EB00D176CD /* libz.dylib */; };
+		5B2BC770151251EB00D176CD /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC769151251EB00D176CD /* OpenAL.framework */; };
+		5B2BC771151251EB00D176CD /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC76A151251EB00D176CD /* OpenGLES.framework */; };
+		5B2BC772151251EB00D176CD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC76B151251EB00D176CD /* QuartzCore.framework */; };
+		5B2BC773151251EB00D176CD /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC76C151251EB00D176CD /* UIKit.framework */; };
 		5BB0823D14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
 		5BB0823E14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
+		5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */; };
+		5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */; };
+		5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */; };
+		5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */; };
 		5BC4E73F150F843D00CBE1C0 /* AbsoluteLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */; };
 		5BC4E740150F843D00CBE1C0 /* AbsoluteLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52635150F822A004C9099 /* AbsoluteLayout.h */; };
 		5BC4E741150F843D00CBE1C0 /* Button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52636150F822A004C9099 /* Button.cpp */; };
@@ -367,7 +373,6 @@
 		5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
 		5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
 		5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
-		5BD776FD14C77E1F001CADA0 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -380,13 +385,10 @@
 		4208DEE814A4079F00D3C511 /* Image.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Image.inl; path = src/Image.inl; sourceTree = SOURCE_ROOT; };
 		4208DEEB14A407B900D3C511 /* Keyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Keyboard.h; path = src/Keyboard.h; sourceTree = SOURCE_ROOT; };
 		4208DEED14A407D500D3C511 /* Touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Touch.h; path = src/Touch.h; sourceTree = SOURCE_ROOT; };
-		4220A6E7146B122B00CAEB3A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
 		4234D99A14686C52003031B3 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		4234D99D14686C52003031B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		428390971489D6E800E2B2F5 /* SceneLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SceneLoader.cpp; path = src/SceneLoader.cpp; sourceTree = SOURCE_ROOT; };
 		428390981489D6E800E2B2F5 /* SceneLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SceneLoader.h; path = src/SceneLoader.h; sourceTree = SOURCE_ROOT; };
-		4299EFA8146AC94300FF4A73 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenGL.framework; sourceTree = DEVELOPER_DIR; };
-		4299EFAA146AC94B00FF4A73 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
 		42C932AF14919FD10098216A /* Game.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Game.inl; path = src/Game.inl; sourceTree = SOURCE_ROOT; };
 		42CCD555146EC1EB00353661 /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/macos/libpng.a"; sourceTree = "<group>"; };
 		42CD0DA6147D8EA80000361E /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/macos/libbullet.a"; sourceTree = "<group>"; };
@@ -544,14 +546,20 @@
 		5B04C5CA14BFCFE100EB0071 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
 		5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformiOS.mm; path = src/PlatformiOS.mm; sourceTree = SOURCE_ROOT; };
-		5B04C5F514BFE50100EB0071 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
-		5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
-		5B04C5F914BFE51000EB0071 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
-		5B04C5FB14BFE51600EB0071 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
-		5B43D17914C3497B008A5D9D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC7561512507500D176CD /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC75D1512514500D176CD /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
+		5B2BC75E1512514500D176CD /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+		5B2BC7611512514D00D176CD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+		5B2BC7631512516B00D176CD /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = "<absolute>"; };
+		5B2BC766151251EB00D176CD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC767151251EB00D176CD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC768151251EB00D176CD /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
+		5B2BC769151251EB00D176CD /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenAL.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC76A151251EB00D176CD /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC76B151251EB00D176CD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
+		5B2BC76C151251EB00D176CD /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
 		5B5ADCE214C22DF900AC6109 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = SDKs/MacOSX10.7.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
 		5B5ADCE414C22E1F00AC6109 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
-		5B5ADD2E14C2439700AC6109 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
 		5B5DB92D14C25B7B007755DB /* libbullet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbullet.a; path = "../external-deps/bullet/lib/ios/i386/libbullet.a"; sourceTree = "<group>"; };
 		5B5DB92F14C25B94007755DB /* libpng.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpng.a; path = "../external-deps/libpng/lib/ios/armv7/libpng.a"; sourceTree = "<group>"; };
 		5B5DB93114C25BA5007755DB /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = "../external-deps/oggvorbis/lib/ios/armv7/libogg.a"; sourceTree = "<group>"; };
@@ -561,6 +569,8 @@
 		5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gameplay-main-android.cpp"; path = "src/gameplay-main-android.cpp"; sourceTree = SOURCE_ROOT; };
 		5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformAndroid.cpp; path = src/PlatformAndroid.cpp; sourceTree = SOURCE_ROOT; };
 		5BB0823C14C6FEC40019975F /* Mouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mouse.h; path = src/Mouse.h; sourceTree = SOURCE_ROOT; };
+		5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsGhostObject.cpp; path = src/PhysicsGhostObject.cpp; sourceTree = SOURCE_ROOT; };
+		5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsGhostObject.h; path = src/PhysicsGhostObject.h; sourceTree = SOURCE_ROOT; };
 		5BC4E7D4150F8C3C00CBE1C0 /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
 		5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AbsoluteLayout.cpp; path = src/AbsoluteLayout.cpp; sourceTree = SOURCE_ROOT; };
 		5BD52635150F822A004C9099 /* AbsoluteLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AbsoluteLayout.h; path = src/AbsoluteLayout.h; sourceTree = SOURCE_ROOT; };
@@ -594,7 +604,6 @@
 		5BD5266C150F8257004C9099 /* PhysicsCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCharacter.h; path = src/PhysicsCharacter.h; sourceTree = SOURCE_ROOT; };
 		5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionObject.cpp; path = src/PhysicsCollisionObject.cpp; sourceTree = SOURCE_ROOT; };
 		5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionObject.h; path = src/PhysicsCollisionObject.h; sourceTree = SOURCE_ROOT; };
-		5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/Frameworks/CoreMotion.framework; sourceTree = DEVELOPER_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -602,7 +611,10 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5B5ADCE314C22DF900AC6109 /* libz.dylib in Frameworks */,
+				5B2BC7641512516B00D176CD /* libz.dylib in Frameworks */,
+				5B2BC7621512514D00D176CD /* QuartzCore.framework in Frameworks */,
+				5B2BC75F1512514500D176CD /* OpenAL.framework in Frameworks */,
+				5B2BC7601512514500D176CD /* OpenGL.framework in Frameworks */,
 				42CD0DAB147D8EA80000361E /* libbullet.a in Frameworks */,
 				42CD0DAC147D8EA80000361E /* libogg.a in Frameworks */,
 				42CD0DAD147D8EA80000361E /* libvorbis.a in Frameworks */,
@@ -610,9 +622,6 @@
 				42CD0DAF147D8EA80000361E /* libvorbisfile.a in Frameworks */,
 				42CCD556146EC1EB00353661 /* libpng.a in Frameworks */,
 				4234D99E14686C52003031B3 /* Cocoa.framework in Frameworks */,
-				4220A6E8146B122B00CAEB3A /* QuartzCore.framework in Frameworks */,
-				4299EFA9146AC94300FF4A73 /* OpenGL.framework in Frameworks */,
-				4299EFAB146AC94B00FF4A73 /* OpenAL.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -620,13 +629,14 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5BD776FD14C77E1F001CADA0 /* CoreMotion.framework in Frameworks */,
-				5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */,
-				5B5ADCE514C22E1F00AC6109 /* libz.dylib in Frameworks */,
-				5B04C5FC14BFE51600EB0071 /* OpenAL.framework in Frameworks */,
-				5B04C5FA14BFE51100EB0071 /* OpenGLES.framework in Frameworks */,
-				5B04C5F814BFE50B00EB0071 /* QuartzCore.framework in Frameworks */,
-				5B04C5F614BFE50100EB0071 /* UIKit.framework in Frameworks */,
+				5B2BC76D151251EB00D176CD /* CoreGraphics.framework in Frameworks */,
+				5B2BC76E151251EB00D176CD /* Foundation.framework in Frameworks */,
+				5B2BC76F151251EB00D176CD /* libz.dylib in Frameworks */,
+				5B2BC770151251EB00D176CD /* OpenAL.framework in Frameworks */,
+				5B2BC771151251EB00D176CD /* OpenGLES.framework in Frameworks */,
+				5B2BC772151251EB00D176CD /* QuartzCore.framework in Frameworks */,
+				5B2BC773151251EB00D176CD /* UIKit.framework in Frameworks */,
+				5B2BC765151251EB00D176CD /* CoreMotion.framework in Frameworks */,
 				5B04C57514BFCFE100EB0071 /* libbullet.a in Frameworks */,
 				5B04C57614BFCFE100EB0071 /* libogg.a in Frameworks */,
 				5B04C57714BFCFE100EB0071 /* libvorbis.a in Frameworks */,
@@ -662,85 +672,26 @@
 		4234D9A314686C52003031B3 /* src */ = {
 			isa = PBXGroup;
 			children = (
-				5B43D19714C35347008A5D9D /* GamePlay */,
-				5B43D19614C35344008A5D9D /* Platform */,
-			);
-			name = src;
-			path = gameplay;
-			sourceTree = "<group>";
-		};
-		427D4F42147DC8DE0076760E /* Libraries */ = {
-			isa = PBXGroup;
-			children = (
-				42CD0DA6147D8EA80000361E /* libbullet.a */,
-				42CD0DA7147D8EA80000361E /* libogg.a */,
-				42CD0DA8147D8EA80000361E /* libvorbis.a */,
-				42CD0DA9147D8EA80000361E /* libvorbisenc.a */,
-				42CD0DAA147D8EA80000361E /* libvorbisfile.a */,
-				42CCD555146EC1EB00353661 /* libpng.a */,
-				5B5ADCE114C22DC700AC6109 /* Mac OS X */,
-				5B5ADCE014C22DBE00AC6109 /* iOS */,
-			);
-			name = Libraries;
-			sourceTree = "<group>";
-		};
-		42CCD4AF146D811D00353661 /* Frameworks */ = {
-			isa = PBXGroup;
-			children = (
-				5B04C5FE14BFE52F00EB0071 /* Mac OS X */,
-				5B04C5FD14BFE52300EB0071 /* iOS */,
-			);
-			name = Frameworks;
-			sourceTree = "<group>";
-		};
-		5B04C5FD14BFE52300EB0071 /* iOS */ = {
-			isa = PBXGroup;
-			children = (
-				5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */,
-				5B43D17914C3497B008A5D9D /* CoreGraphics.framework */,
-				5B5ADD2E14C2439700AC6109 /* Foundation.framework */,
-				5B04C5FB14BFE51600EB0071 /* OpenAL.framework */,
-				5B04C5F914BFE51000EB0071 /* OpenGLES.framework */,
-				5B04C5F714BFE50B00EB0071 /* QuartzCore.framework */,
-				5B04C5F514BFE50100EB0071 /* UIKit.framework */,
-			);
-			name = iOS;
-			sourceTree = "<group>";
-		};
-		5B04C5FE14BFE52F00EB0071 /* Mac OS X */ = {
-			isa = PBXGroup;
-			children = (
-				4234D99D14686C52003031B3 /* Cocoa.framework */,
-				4220A6E7146B122B00CAEB3A /* QuartzCore.framework */,
-				4299EFA8146AC94300FF4A73 /* OpenGL.framework */,
-				4299EFAA146AC94B00FF4A73 /* OpenAL.framework */,
-			);
-			name = "Mac OS X";
-			sourceTree = "<group>";
-		};
-		5B43D19614C35344008A5D9D /* Platform */ = {
-			isa = PBXGroup;
-			children = (
-				5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */,
-				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
-				42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */,
-				5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */,
-				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
-				42CD0E19147D8FF50000361E /* Platform.h */,
-				5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */,
-				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
-				42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */,
-				5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */,
-				42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */,
-			);
-			name = Platform;
-			sourceTree = "<group>";
-		};
-		5B43D19714C35347008A5D9D /* GamePlay */ = {
-			isa = PBXGroup;
-			children = (
-				5BD52677150F828A004C9099 /* Animation */,
-				5BD52678150F829F004C9099 /* Audio */,
+				5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */,
+				5BD52635150F822A004C9099 /* AbsoluteLayout.h */,
+				42CD0DB1147D8FF50000361E /* Animation.cpp */,
+				42CD0DB2147D8FF50000361E /* Animation.h */,
+				42CD0DB3147D8FF50000361E /* AnimationClip.cpp */,
+				42CD0DB4147D8FF50000361E /* AnimationClip.h */,
+				42CD0DB5147D8FF50000361E /* AnimationController.cpp */,
+				42CD0DB6147D8FF50000361E /* AnimationController.h */,
+				42CD0DB7147D8FF50000361E /* AnimationTarget.cpp */,
+				42CD0DB8147D8FF50000361E /* AnimationTarget.h */,
+				42CD0DB9147D8FF50000361E /* AnimationValue.cpp */,
+				42CD0DBA147D8FF50000361E /* AnimationValue.h */,
+				42CD0DBB147D8FF50000361E /* AudioBuffer.cpp */,
+				42CD0DBC147D8FF50000361E /* AudioBuffer.h */,
+				42CD0DBD147D8FF50000361E /* AudioController.cpp */,
+				42CD0DBE147D8FF50000361E /* AudioController.h */,
+				42CD0DBF147D8FF50000361E /* AudioListener.cpp */,
+				42CD0DC0147D8FF50000361E /* AudioListener.h */,
+				42CD0DC1147D8FF50000361E /* AudioSource.cpp */,
+				42CD0DC2147D8FF50000361E /* AudioSource.h */,
 				42CD0DC3147D8FF50000361E /* Base.h */,
 				42CD0DC4147D8FF50000361E /* BoundingBox.cpp */,
 				42CD0DC5147D8FF50000361E /* BoundingBox.h */,
@@ -748,8 +699,16 @@
 				42CD0DC7147D8FF50000361E /* BoundingSphere.cpp */,
 				42CD0DC8147D8FF50000361E /* BoundingSphere.h */,
 				42CD0DC9147D8FF50000361E /* BoundingSphere.inl */,
+				5BD52636150F822A004C9099 /* Button.cpp */,
+				5BD52637150F822A004C9099 /* Button.h */,
 				42CD0DCA147D8FF50000361E /* Camera.cpp */,
 				42CD0DCB147D8FF50000361E /* Camera.h */,
+				5BD52638150F822A004C9099 /* CheckBox.cpp */,
+				5BD52639150F822A004C9099 /* CheckBox.h */,
+				5BD5263A150F822A004C9099 /* Container.cpp */,
+				5BD5263B150F822A004C9099 /* Container.h */,
+				5BD5263C150F822A004C9099 /* Control.cpp */,
+				5BD5263D150F822A004C9099 /* Control.h */,
 				42CD0DCC147D8FF50000361E /* Curve.cpp */,
 				42CD0DCD147D8FF50000361E /* Curve.h */,
 				4208DEE514A4078100D3C511 /* Curve.inl */,
@@ -761,8 +720,11 @@
 				42CD0DD3147D8FF50000361E /* Effect.h */,
 				42CD0DD4147D8FF50000361E /* FileSystem.cpp */,
 				42CD0DD5147D8FF50000361E /* FileSystem.h */,
+				5BD5263E150F822A004C9099 /* FlowLayout.h */,
 				42CD0DD6147D8FF50000361E /* Font.cpp */,
 				42CD0DD7147D8FF50000361E /* Font.h */,
+				5BD5263F150F822A004C9099 /* Form.cpp */,
+				5BD52640150F822A004C9099 /* Form.h */,
 				42CD0DD8147D8FF50000361E /* FrameBuffer.cpp */,
 				42CD0DD9147D8FF50000361E /* FrameBuffer.h */,
 				42CD0DDA147D8FF50000361E /* Frustum.cpp */,
@@ -772,12 +734,20 @@
 				42C932AF14919FD10098216A /* Game.inl */,
 				5BD5266A150F8257004C9099 /* gameplay.dox */,
 				42CD0DE1147D8FF50000361E /* gameplay.h */,
+				5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */,
+				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
+				42CD0DDE147D8FF50000361E /* gameplay-main-macos.mm */,
+				5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */,
+				42CD0DDF147D8FF50000361E /* gameplay-main-qnx.cpp */,
 				4208DEE614A4079F00D3C511 /* Image.cpp */,
 				4208DEE714A4079F00D3C511 /* Image.h */,
 				4208DEE814A4079F00D3C511 /* Image.inl */,
 				42CD0DE4147D8FF50000361E /* Joint.cpp */,
 				42CD0DE5147D8FF50000361E /* Joint.h */,
 				4208DEEB14A407B900D3C511 /* Keyboard.h */,
+				5BD52641150F822A004C9099 /* Label.cpp */,
+				5BD52642150F822A004C9099 /* Label.h */,
+				5BD52643150F822A004C9099 /* Layout.h */,
 				42CD0DE6147D8FF50000361E /* Light.cpp */,
 				42CD0DE7147D8FF50000361E /* Light.h */,
 				42CD0DE8147D8FF50000361E /* Material.cpp */,
@@ -810,12 +780,48 @@
 				42CD0E16147D8FF50000361E /* Plane.cpp */,
 				42CD0E17147D8FF50000361E /* Plane.h */,
 				42CD0E18147D8FF50000361E /* Plane.inl */,
-				5BD52679150F82C0004C9099 /* Physics */,
+				5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */,
+				5BD5266C150F8257004C9099 /* PhysicsCharacter.h */,
+				5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */,
+				5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */,
+				42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */,
+				42CD0E00147D8FF50000361E /* PhysicsConstraint.h */,
+				42CD0E01147D8FF50000361E /* PhysicsConstraint.inl */,
+				42CD0E02147D8FF50000361E /* PhysicsController.cpp */,
+				42CD0E03147D8FF50000361E /* PhysicsController.h */,
+				42CD0E04147D8FF50000361E /* PhysicsFixedConstraint.cpp */,
+				42CD0E05147D8FF50000361E /* PhysicsFixedConstraint.h */,
+				42CD0E06147D8FF50000361E /* PhysicsFixedConstraint.inl */,
+				42CD0E07147D8FF50000361E /* PhysicsGenericConstraint.cpp */,
+				42CD0E08147D8FF50000361E /* PhysicsGenericConstraint.h */,
+				42CD0E09147D8FF50000361E /* PhysicsGenericConstraint.inl */,
+				42CD0E0A147D8FF50000361E /* PhysicsHingeConstraint.cpp */,
+				42CD0E0B147D8FF50000361E /* PhysicsHingeConstraint.h */,
+				5BBE143C1513E400003FB362 /* PhysicsGhostObject.cpp */,
+				5BBE143D1513E400003FB362 /* PhysicsGhostObject.h */,
+				42CD0E0C147D8FF50000361E /* PhysicsMotionState.cpp */,
+				42CD0E0D147D8FF50000361E /* PhysicsMotionState.h */,
+				42CD0E0E147D8FF50000361E /* PhysicsRigidBody.cpp */,
+				42CD0E0F147D8FF50000361E /* PhysicsRigidBody.h */,
+				42CD0E10147D8FF50000361E /* PhysicsRigidBody.inl */,
+				42CD0E11147D8FF50000361E /* PhysicsSocketConstraint.cpp */,
+				42CD0E12147D8FF50000361E /* PhysicsSocketConstraint.h */,
+				42CD0E13147D8FF50000361E /* PhysicsSpringConstraint.cpp */,
+				42CD0E14147D8FF50000361E /* PhysicsSpringConstraint.h */,
+				42CD0E15147D8FF50000361E /* PhysicsSpringConstraint.inl */,
+				42CD0E19147D8FF50000361E /* Platform.h */,
+				5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */,
+				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
+				42CD0E1A147D8FF50000361E /* PlatformMacOS.mm */,
+				5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */,
+				42CD0E1B147D8FF50000361E /* PlatformQNX.cpp */,
 				42CD0E1D147D8FF50000361E /* Properties.cpp */,
 				42CD0E1E147D8FF50000361E /* Properties.h */,
 				42CD0E1F147D8FF50000361E /* Quaternion.cpp */,
 				42CD0E20147D8FF50000361E /* Quaternion.h */,
 				42CD0E21147D8FF50000361E /* Quaternion.inl */,
+				5BD52644150F822A004C9099 /* RadioButton.cpp */,
+				5BD52645150F822A004C9099 /* RadioButton.h */,
 				42CD0E22147D8FF50000361E /* Ray.cpp */,
 				42CD0E23147D8FF50000361E /* Ray.h */,
 				42CD0E24147D8FF50000361E /* Ray.inl */,
@@ -831,13 +837,19 @@
 				42CD0E2E147D8FF50000361E /* Scene.h */,
 				428390971489D6E800E2B2F5 /* SceneLoader.cpp */,
 				428390981489D6E800E2B2F5 /* SceneLoader.h */,
+				5BD52646150F822A004C9099 /* Slider.cpp */,
+				5BD52647150F822A004C9099 /* Slider.h */,
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
 				42CD0E30147D8FF50000361E /* SpriteBatch.h */,
 				42CD0E31147D8FF50000361E /* Technique.cpp */,
 				42CD0E32147D8FF50000361E /* Technique.h */,
 				42CD0E33147D8FF50000361E /* Texture.cpp */,
 				42CD0E34147D8FF50000361E /* Texture.h */,
+				5BD52648150F822A004C9099 /* TextBox.cpp */,
+				5BD52649150F822A004C9099 /* TextBox.h */,
 				5BD5264C150F822A004C9099 /* TimeListener.h */,
+				5BD5264A150F822A004C9099 /* Theme.cpp */,
+				5BD5264B150F822A004C9099 /* Theme.h */,
 				4208DEED14A407D500D3C511 /* Touch.h */,
 				42CD0E35147D8FF50000361E /* Transform.cpp */,
 				42CD0E36147D8FF50000361E /* Transform.h */,
@@ -854,132 +866,86 @@
 				42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */,
 				42CD0E42147D8FF50000361E /* VertexFormat.cpp */,
 				42CD0E43147D8FF50000361E /* VertexFormat.h */,
+				5BD5264D150F822A004C9099 /* VerticalLayout.cpp */,
+				5BD5264E150F822A004C9099 /* VerticalLayout.h */,
 				42CD0E44147D8FF50000361E /* Viewport.cpp */,
 				42CD0E45147D8FF50000361E /* Viewport.h */,
-				5BD52633150F81F7004C9099 /* UI */,
 			);
-			name = GamePlay;
+			name = src;
+			path = gameplay;
 			sourceTree = "<group>";
 		};
-		5B5ADCE014C22DBE00AC6109 /* iOS */ = {
+		427D4F42147DC8DE0076760E /* Libraries */ = {
 			isa = PBXGroup;
 			children = (
-				5B5DB93114C25BA5007755DB /* libogg.a */,
-				5B5DB93214C25BA5007755DB /* libvorbis.a */,
-				5B5DB93314C25BA5007755DB /* libvorbisenc.a */,
-				5B5DB93414C25BA5007755DB /* libvorbisfile.a */,
-				5B5DB92F14C25B94007755DB /* libpng.a */,
-				5B5DB92D14C25B7B007755DB /* libbullet.a */,
-				5B5ADCE414C22E1F00AC6109 /* libz.dylib */,
+				42CD0DA6147D8EA80000361E /* libbullet.a */,
+				42CD0DA7147D8EA80000361E /* libogg.a */,
+				42CD0DA8147D8EA80000361E /* libvorbis.a */,
+				42CD0DA9147D8EA80000361E /* libvorbisenc.a */,
+				42CD0DAA147D8EA80000361E /* libvorbisfile.a */,
+				42CCD555146EC1EB00353661 /* libpng.a */,
+				5B5ADCE114C22DC700AC6109 /* Mac OS X */,
+				5B5ADCE014C22DBE00AC6109 /* iOS */,
 			);
-			name = iOS;
+			name = Libraries;
 			sourceTree = "<group>";
 		};
-		5B5ADCE114C22DC700AC6109 /* Mac OS X */ = {
+		42CCD4AF146D811D00353661 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				5B5ADCE214C22DF900AC6109 /* libz.dylib */,
+				5B04C5FE14BFE52F00EB0071 /* Mac OS X */,
+				5B04C5FD14BFE52300EB0071 /* iOS */,
 			);
-			name = "Mac OS X";
+			name = Frameworks;
 			sourceTree = "<group>";
 		};
-		5BD52633150F81F7004C9099 /* UI */ = {
+		5B04C5FD14BFE52300EB0071 /* iOS */ = {
 			isa = PBXGroup;
 			children = (
-				5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */,
-				5BD52635150F822A004C9099 /* AbsoluteLayout.h */,
-				5BD52636150F822A004C9099 /* Button.cpp */,
-				5BD52637150F822A004C9099 /* Button.h */,
-				5BD52638150F822A004C9099 /* CheckBox.cpp */,
-				5BD52639150F822A004C9099 /* CheckBox.h */,
-				5BD5263A150F822A004C9099 /* Container.cpp */,
-				5BD5263B150F822A004C9099 /* Container.h */,
-				5BD5263C150F822A004C9099 /* Control.cpp */,
-				5BD5263D150F822A004C9099 /* Control.h */,
-				5BD5263E150F822A004C9099 /* FlowLayout.h */,
-				5BD5263F150F822A004C9099 /* Form.cpp */,
-				5BD52640150F822A004C9099 /* Form.h */,
-				5BD52641150F822A004C9099 /* Label.cpp */,
-				5BD52642150F822A004C9099 /* Label.h */,
-				5BD52643150F822A004C9099 /* Layout.h */,
-				5BD52644150F822A004C9099 /* RadioButton.cpp */,
-				5BD52645150F822A004C9099 /* RadioButton.h */,
-				5BD52646150F822A004C9099 /* Slider.cpp */,
-				5BD52647150F822A004C9099 /* Slider.h */,
-				5BD52648150F822A004C9099 /* TextBox.cpp */,
-				5BD52649150F822A004C9099 /* TextBox.h */,
-				5BD5264A150F822A004C9099 /* Theme.cpp */,
-				5BD5264B150F822A004C9099 /* Theme.h */,
-				5BD5264D150F822A004C9099 /* VerticalLayout.cpp */,
-				5BD5264E150F822A004C9099 /* VerticalLayout.h */,
+				5B2BC766151251EB00D176CD /* CoreGraphics.framework */,
+				5B2BC767151251EB00D176CD /* Foundation.framework */,
+				5B2BC768151251EB00D176CD /* libz.dylib */,
+				5B2BC769151251EB00D176CD /* OpenAL.framework */,
+				5B2BC76A151251EB00D176CD /* OpenGLES.framework */,
+				5B2BC76B151251EB00D176CD /* QuartzCore.framework */,
+				5B2BC76C151251EB00D176CD /* UIKit.framework */,
+				5B2BC7561512507500D176CD /* CoreMotion.framework */,
 			);
-			name = UI;
+			name = iOS;
 			sourceTree = "<group>";
 		};
-		5BD52677150F828A004C9099 /* Animation */ = {
+		5B04C5FE14BFE52F00EB0071 /* Mac OS X */ = {
 			isa = PBXGroup;
 			children = (
-				42CD0DB1147D8FF50000361E /* Animation.cpp */,
-				42CD0DB2147D8FF50000361E /* Animation.h */,
-				42CD0DB3147D8FF50000361E /* AnimationClip.cpp */,
-				42CD0DB4147D8FF50000361E /* AnimationClip.h */,
-				42CD0DB5147D8FF50000361E /* AnimationController.cpp */,
-				42CD0DB6147D8FF50000361E /* AnimationController.h */,
-				42CD0DB7147D8FF50000361E /* AnimationTarget.cpp */,
-				42CD0DB8147D8FF50000361E /* AnimationTarget.h */,
-				42CD0DB9147D8FF50000361E /* AnimationValue.cpp */,
-				42CD0DBA147D8FF50000361E /* AnimationValue.h */,
+				5B2BC7631512516B00D176CD /* libz.dylib */,
+				5B2BC7611512514D00D176CD /* QuartzCore.framework */,
+				5B2BC75D1512514500D176CD /* OpenAL.framework */,
+				5B2BC75E1512514500D176CD /* OpenGL.framework */,
+				4234D99D14686C52003031B3 /* Cocoa.framework */,
 			);
-			name = Animation;
+			name = "Mac OS X";
 			sourceTree = "<group>";
 		};
-		5BD52678150F829F004C9099 /* Audio */ = {
+		5B5ADCE014C22DBE00AC6109 /* iOS */ = {
 			isa = PBXGroup;
 			children = (
-				42CD0DBB147D8FF50000361E /* AudioBuffer.cpp */,
-				42CD0DBC147D8FF50000361E /* AudioBuffer.h */,
-				42CD0DBD147D8FF50000361E /* AudioController.cpp */,
-				42CD0DBE147D8FF50000361E /* AudioController.h */,
-				42CD0DBF147D8FF50000361E /* AudioListener.cpp */,
-				42CD0DC0147D8FF50000361E /* AudioListener.h */,
-				42CD0DC1147D8FF50000361E /* AudioSource.cpp */,
-				42CD0DC2147D8FF50000361E /* AudioSource.h */,
+				5B5DB93114C25BA5007755DB /* libogg.a */,
+				5B5DB93214C25BA5007755DB /* libvorbis.a */,
+				5B5DB93314C25BA5007755DB /* libvorbisenc.a */,
+				5B5DB93414C25BA5007755DB /* libvorbisfile.a */,
+				5B5DB92F14C25B94007755DB /* libpng.a */,
+				5B5DB92D14C25B7B007755DB /* libbullet.a */,
+				5B5ADCE414C22E1F00AC6109 /* libz.dylib */,
 			);
-			name = Audio;
+			name = iOS;
 			sourceTree = "<group>";
 		};
-		5BD52679150F82C0004C9099 /* Physics */ = {
+		5B5ADCE114C22DC700AC6109 /* Mac OS X */ = {
 			isa = PBXGroup;
 			children = (
-				5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */,
-				5BD5266C150F8257004C9099 /* PhysicsCharacter.h */,
-				5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */,
-				5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */,
-				42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */,
-				42CD0E00147D8FF50000361E /* PhysicsConstraint.h */,
-				42CD0E01147D8FF50000361E /* PhysicsConstraint.inl */,
-				42CD0E02147D8FF50000361E /* PhysicsController.cpp */,
-				42CD0E03147D8FF50000361E /* PhysicsController.h */,
-				42CD0E04147D8FF50000361E /* PhysicsFixedConstraint.cpp */,
-				42CD0E05147D8FF50000361E /* PhysicsFixedConstraint.h */,
-				42CD0E06147D8FF50000361E /* PhysicsFixedConstraint.inl */,
-				42CD0E07147D8FF50000361E /* PhysicsGenericConstraint.cpp */,
-				42CD0E08147D8FF50000361E /* PhysicsGenericConstraint.h */,
-				42CD0E09147D8FF50000361E /* PhysicsGenericConstraint.inl */,
-				42CD0E0A147D8FF50000361E /* PhysicsHingeConstraint.cpp */,
-				42CD0E0B147D8FF50000361E /* PhysicsHingeConstraint.h */,
-				42CD0E0C147D8FF50000361E /* PhysicsMotionState.cpp */,
-				42CD0E0D147D8FF50000361E /* PhysicsMotionState.h */,
-				42CD0E0E147D8FF50000361E /* PhysicsRigidBody.cpp */,
-				42CD0E0F147D8FF50000361E /* PhysicsRigidBody.h */,
-				42CD0E10147D8FF50000361E /* PhysicsRigidBody.inl */,
-				42CD0E11147D8FF50000361E /* PhysicsSocketConstraint.cpp */,
-				42CD0E12147D8FF50000361E /* PhysicsSocketConstraint.h */,
-				42CD0E13147D8FF50000361E /* PhysicsSpringConstraint.cpp */,
-				42CD0E14147D8FF50000361E /* PhysicsSpringConstraint.h */,
-				42CD0E15147D8FF50000361E /* PhysicsSpringConstraint.inl */,
+				5B5ADCE214C22DF900AC6109 /* libz.dylib */,
 			);
-			name = Physics;
+			name = "Mac OS X";
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -1077,6 +1043,7 @@
 				5BD52669150F822A004C9099 /* VerticalLayout.h in Headers */,
 				5BD52671150F8258004C9099 /* PhysicsCharacter.h in Headers */,
 				5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
+				5BBE14401513E400003FB362 /* PhysicsGhostObject.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1171,6 +1138,7 @@
 				5BC4E754150F843D00CBE1C0 /* TextBox.h in Headers */,
 				5BC4E756150F843D00CBE1C0 /* Theme.h in Headers */,
 				5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */,
+				5BBE14411513E400003FB362 /* PhysicsGhostObject.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1217,7 +1185,7 @@
 		4234D98C14686BB6003031B3 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0420;
+				LastUpgradeCheck = 0430;
 			};
 			buildConfigurationList = 4234D98F14686BB6003031B3 /* Build configuration list for PBXProject "gameplay" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -1323,6 +1291,7 @@
 				5BD52668150F822A004C9099 /* VerticalLayout.cpp in Sources */,
 				5BD5266F150F8258004C9099 /* PhysicsCharacter.cpp in Sources */,
 				5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
+				5BBE143E1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1411,6 +1380,7 @@
 				5BC4E753150F843D00CBE1C0 /* TextBox.cpp in Sources */,
 				5BC4E755150F843D00CBE1C0 /* Theme.cpp in Sources */,
 				5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */,
+				5BBE143F1513E400003FB362 /* PhysicsGhostObject.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1420,6 +1390,7 @@
 		4234D99114686BB6003031B3 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				SDKROOT = macosx;
 				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
 				VALID_ARCHS = "armv7 armv6 i386 x86_64";
 			};
@@ -1428,6 +1399,7 @@
 		4234D99214686BB6003031B3 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				SDKROOT = macosx;
 				SUPPORTED_PLATFORMS = "iphonesimulator macosx iphoneos";
 				VALID_ARCHS = "armv7 armv6 i386 x86_64";
 			};
@@ -1462,6 +1434,7 @@
 					"../external-deps/libpng/include",
 					"../external-deps/bullet/include",
 					"../external-deps/oggvorbis/include",
+					./gameplay,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
@@ -1473,7 +1446,6 @@
 				ONLY_ACTIVE_ARCH = NO;
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
 				PRODUCT_NAME = gameplay;
-				SDKROOT = macosx;
 				SHARED_PRECOMPS_DIR = "";
 				SUPPORTED_PLATFORMS = macosx;
 				USER_HEADER_SEARCH_PATHS = "";
@@ -1504,6 +1476,7 @@
 					"../external-deps/libpng/include",
 					"../external-deps/bullet/include",
 					"../external-deps/oggvorbis/include",
+					./gameplay,
 				);
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
@@ -1514,7 +1487,6 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.7;
 				PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO;
 				PRODUCT_NAME = gameplay;
-				SDKROOT = macosx;
 				SHARED_PRECOMPS_DIR = "";
 				SUPPORTED_PLATFORMS = macosx;
 				USER_HEADER_SEARCH_PATHS = "";

+ 12 - 2
gameplay/src/AbsoluteLayout.cpp

@@ -5,6 +5,8 @@
 
 namespace gameplay
 {
+    static AbsoluteLayout* __instance;
+
     AbsoluteLayout::AbsoluteLayout()
     {
     }
@@ -19,8 +21,16 @@ namespace gameplay
 
     AbsoluteLayout* AbsoluteLayout::create()
     {
-        AbsoluteLayout* al = new AbsoluteLayout();
-        return al;
+        if (!__instance)
+        {
+            __instance = new AbsoluteLayout();
+        }
+        else
+        {
+            __instance->addRef();
+        }
+
+        return __instance;
     }
 
     Layout::Type AbsoluteLayout::getType()

+ 3 - 14
gameplay/src/Button.cpp

@@ -3,13 +3,12 @@
 
 namespace gameplay
 {
-    Button::Button() : _callback(NULL)
+    Button::Button()
     {
     }
 
     Button::~Button()
     {
-        SAFE_DELETE(_callback);
     }
 
     Button* Button::create(Theme::Style* style, Properties* properties)
@@ -32,23 +31,13 @@ namespace gameplay
         case Touch::TOUCH_PRESS:
             _state = Control::ACTIVE;
             _dirty = true;
-            return _consumeTouchEvents;
+            break;
         case Touch::TOUCH_RELEASE:
-            if (_callback &&
-                x > 0 && x <= _bounds.width &&
-                y > 0 && y <= _bounds.height)
-            {
-                // Button-clicked callback.
-                _callback->trigger(this);
-                setState(Control::NORMAL);
-                _dirty = true;
-                return _consumeTouchEvents;
-            }
             _dirty = true;
             setState(Control::NORMAL);
             break;
         }
 
-        return _consumeTouchEvents;
+        return Control::touchEvent(evt, x, y, contactIndex);
     }
 }

+ 0 - 59
gameplay/src/Button.h

@@ -26,20 +26,6 @@ class Button : public Label
 {
     friend class Container;
 
-    class Callback;
-
-public:
-    /**
-     * Set a callback method on this button.  The callback will be triggered when the button is
-     * clicked -- i.e. consecutive TOUCH_PRESS and TOUCH_RELEASE events that both fall within
-     * the bounds of the button.  
-     *
-     * @param instance The object to call the method on.
-     * @param callbackMethod The method to call.
-     */
-    template <class ClassType>
-    void setCallback(ClassType* instance, void (ClassType::*callbackMethod)(Control*));
-
 protected:
     /**
      * Create a button with a given style and properties.
@@ -68,55 +54,10 @@ protected:
     Button();
     virtual ~Button();
 
-    Callback* _callback;    // The callback method pointer interface.
-
 private:
     Button(const Button& copy);
-
-    /**
-     * Abstract callback interface.
-     */
-    class Callback
-    {
-    public:
-        virtual ~Callback() { }
-        virtual void trigger(Control* button) = 0;
-    };
-
-    /**
-     * Implementation of the callback interface for a specific class.
-     */
-    template <class ClassType>
-    class CallbackImpl : public Callback
-    {
-        typedef void (ClassType::*CallbackMethod)(Control*);
-    public:
-        CallbackImpl(ClassType* instance, CallbackMethod method);
-        void trigger(Control* control);
-    private:
-        ClassType* _instance;
-        CallbackMethod _method;
-    };
 };
 
-template <class ClassType>
-Button::CallbackImpl<ClassType>::CallbackImpl(ClassType* instance, CallbackMethod method)
-    : _instance(instance), _method(method)
-{
-}
-
-template <class ClassType>
-void Button::setCallback(ClassType* instance, void (ClassType::*callbackMethod)(Control*))
-{
-    _callback = new CallbackImpl<ClassType>(instance, callbackMethod);
-}
-
-template <class ClassType>
-void Button::CallbackImpl<ClassType>::trigger(Control* control)
-{
-    (_instance->*_method)(control);
-}
-
 }
 
 #endif

+ 16 - 18
gameplay/src/CheckBox.cpp

@@ -50,6 +50,17 @@ const Vector2& CheckBox::getIconSize() const
     return _iconSize;
 }
 
+void CheckBox::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
+    {
+        assert("TEXT_CHANGED event is not applicable to CheckBox.");
+        eventFlags &= ~Listener::TEXT_CHANGED;
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
 bool CheckBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     if (!isEnabled())
@@ -67,6 +78,7 @@ bool CheckBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int cont
                     y > 0 && y <= _bounds.height)
                 {
                     _checked = !_checked;
+                    notifyListeners(Listener::VALUE_CHANGED);
                 }
             }
         }
@@ -89,8 +101,8 @@ void CheckBox::update(const Rectangle& clip)
     }
     float iconWidth = size.x;
 
-    _clip.x += iconWidth;
-    _clip.width -= iconWidth;
+    _textBounds.x += iconWidth;
+    _textBounds.width -= iconWidth;
 }
 
 void CheckBox::drawSprites(SpriteBatch* spriteBatch, const Rectangle& clip)
@@ -123,28 +135,14 @@ void CheckBox::drawSprites(SpriteBatch* spriteBatch, const Rectangle& clip)
         if (_checked)
         {
             const Theme::UVs on = icon->getOnUVs();
-            spriteBatch->draw(pos.x, pos.y, size.x, size.y, on.u1, on.v1, on.u2, on.v2, color);
+            spriteBatch->draw(pos.x, pos.y, size.x, size.y, on.u1, on.v1, on.u2, on.v2, color, _clip);
         }
         else
         {
             const Theme::UVs off = icon->getOffUVs();
-            spriteBatch->draw(pos.x, pos.y, size.x, size.y, off.u1, off.v1, off.u2, off.v2, color);
+            spriteBatch->draw(pos.x, pos.y, size.x, size.y, off.u1, off.v1, off.u2, off.v2, color, _clip);
         }
     }
 }
 
-void CheckBox::drawText(const Rectangle& clip)
-{
-    // TODO: Batch all labels that use the same font.
-    Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-    Font* font = overlay->getFont();
-    
-    // Draw the text.
-    font->begin();
-    font->drawText(_text.c_str(), _clip, overlay->getTextColor(), overlay->getFontSize(), overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
-    font->end();
-
-    _dirty = false;
-}
-
 }

+ 12 - 7
gameplay/src/CheckBox.h

@@ -51,6 +51,18 @@ public:
      */
     const Vector2& getIconSize() const;
 
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
 protected:
     CheckBox();
     ~CheckBox();
@@ -95,13 +107,6 @@ protected:
      */
     void drawSprites(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-    /**
-     * Draw this control's text.
-     *
-     * @param position The container position this control is relative to.
-     */
-    void drawText(const Rectangle& clip);
-
     bool _checked;      // Whether this checkbox is currently checked.
     Vector2 _iconSize;  // The size to draw the checkbox icon, if different from its size in the texture.
 

+ 113 - 2
gameplay/src/Control.cpp

@@ -5,7 +5,7 @@ namespace gameplay
 {
     Control::Control()
         : _id(""), _state(Control::NORMAL), _position(Vector2::zero()), _size(Vector2::zero()), _bounds(Rectangle::empty()), _clip(Rectangle::empty()),
-          _autoWidth(true), _autoHeight(true), _dirty(true), _consumeTouchEvents(true)
+          _autoWidth(true), _autoHeight(true), _dirty(true), _consumeTouchEvents(true), _listeners(NULL)
     {
     }
 
@@ -15,6 +15,15 @@ namespace gameplay
 
     Control::~Control()
     {
+        if (_listeners)
+        {
+            for (ListenerMap::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
+            {
+                std::list<Listener*>* list = itr->second;
+                SAFE_DELETE(list);
+            }
+            SAFE_DELETE(_listeners);
+        }
     }
 
     void Control::init(Theme::Style* style, Properties* properties)
@@ -76,6 +85,11 @@ namespace gameplay
 
     void Control::setStyle(Theme::Style* style)
     {
+        if (style != _style)
+        {
+            _dirty = true;
+        }
+
         _style = style;
     }
 
@@ -136,9 +150,78 @@ namespace gameplay
         return _consumeTouchEvents;
     }
 
+    void Control::addListener(Control::Listener* listener, int eventFlags)
+    {
+        if ((eventFlags & Listener::PRESS) == Listener::PRESS)
+        {
+            addSpecificListener(listener, Listener::PRESS);
+        }
+
+        if ((eventFlags & Listener::RELEASE) == Listener::RELEASE)
+        {
+            addSpecificListener(listener, Listener::RELEASE);
+        }
+
+        if ((eventFlags & Listener::CLICK) == Listener::CLICK)
+        {
+            addSpecificListener(listener, Listener::CLICK);
+        }
+
+        if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
+        {
+            addSpecificListener(listener, Listener::VALUE_CHANGED);
+        }
+
+        if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
+        {
+            addSpecificListener(listener, Listener::TEXT_CHANGED);
+        }
+    }
+
+    void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
+    {
+        if (!_listeners)
+        {
+            _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
+        }
+
+        ListenerMap::const_iterator itr = _listeners->find(eventType);
+        if (itr == _listeners->end())
+        {
+            _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
+            itr = _listeners->find(eventType);
+        }
+
+        std::list<Listener*>* listenerList = itr->second;
+        listenerList->push_back(listener);
+    }
+
     bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
     {
-        // Empty stub to be implemented by Button and its descendents.
+        if (!isEnabled())
+        {
+            return false;
+        }
+
+        switch (evt)
+        {
+        case Touch::TOUCH_PRESS:
+            notifyListeners(Listener::PRESS);
+            break;
+            
+        case Touch::TOUCH_RELEASE:
+            // Always trigger Listener::RELEASE
+            notifyListeners(Listener::RELEASE);
+
+            // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
+            if (x > 0 && x <= _bounds.width &&
+                y > 0 && y <= _bounds.height)
+            {
+                notifyListeners(Listener::CLICK);
+            }
+            break;
+        }
+
         return _consumeTouchEvents;
     }
 
@@ -146,6 +229,22 @@ namespace gameplay
     {
     }
 
+    void Control::notifyListeners(Listener::EventType eventType)
+    {
+        if (_listeners)
+        {
+            ListenerMap::const_iterator itr = _listeners->find(eventType);
+            if (itr != _listeners->end())
+            {
+                std::list<Listener*>* listenerList = itr->second;
+                for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); listenerItr++)
+                {
+                    (*listenerItr)->controlEvent(this, eventType);
+                }
+            }
+        }
+    }
+
     void Control::update(const Rectangle& clip)
     {
         // Calculate the bounds.
@@ -185,6 +284,8 @@ namespace gameplay
         width = _size.x - border.left - padding.left - border.right - padding.right;
         height = _size.y - border.top - padding.top - border.bottom - padding.bottom;
 
+        _textBounds.set(x, y, width, height);
+
         clipX2 = clip.x + clip.width;
         x2 = x + width;
         if (x2 > clipX2)
@@ -199,6 +300,16 @@ namespace gameplay
             height = clipY2 - y;
         }
 
+        if (x < clip.x)
+        {
+            x = clip.x;
+        }
+
+        if (y < clip.y)
+        {
+            y = clip.y;
+        }
+
         _clip.set(x, y, width, height);
     }
 

+ 38 - 1
gameplay/src/Control.h

@@ -35,6 +35,21 @@ public:
         DISABLED
     };
 
+    class Listener
+    {
+    public:
+        enum EventType
+        {
+            PRESS           = 0x01,
+            RELEASE         = 0x02,
+            CLICK           = 0x04,
+            VALUE_CHANGED   = 0x08,
+            TEXT_CHANGED    = 0x10
+        };
+
+        virtual void controlEvent(Control* control, EventType evt) = 0;
+    };
+
     /**
      * Get this control's ID string.
      *
@@ -158,6 +173,18 @@ public:
      */
     Theme::Style* getStyle() const;
 
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
 protected:
     Control();
     virtual ~Control();
@@ -246,17 +273,27 @@ protected:
      */
     static State getStateFromString(const char* state);
 
+    /**
+     * Notify all listeners of a specific event.
+     */
+    void notifyListeners(Listener::EventType eventType);
+
+    void addSpecificListener(Control::Listener* listener, Listener::EventType eventType);
+
     std::string _id;
     State _state;           // Determines overlay used during draw().
     Vector2 _position;      // Position, relative to parent container's clipping window.
     Vector2 _size;          // Desired size.  Will be clipped.
     Rectangle _bounds;      // The position and size of this control, relative to parent container's bounds, including border and padding, after clipping.
-    Rectangle _clip;        // Clipping window of this control's content.
+    Rectangle _textBounds;  // The position and size of this control's content, before clipping.  Used for text alignment.
+    Rectangle _clip;        // Clipping window of this control's content, after clipping.
     bool _autoWidth;
     bool _autoHeight;
     bool _dirty;
     bool _consumeTouchEvents;
     Theme::Style* _style;
+    typedef std::map<Listener::EventType, std::list<Listener*>*> ListenerMap;
+    ListenerMap* _listeners;
 
 private:
     Control(const Control& copy);

+ 9 - 2
gameplay/src/Font.cpp

@@ -289,7 +289,7 @@ void Font::drawText(const char* text, int x, int y, const Vector4& color, unsign
     }
 }
 
-void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size, Justify justify, bool wrap, bool rightToLeft)
+void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, unsigned int size, Justify justify, bool wrap, bool rightToLeft, const Rectangle* clip)
 {
     if (size == 0)
         size = _size;
@@ -577,7 +577,14 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                     // Draw this character.
                     if (draw)
                     {
-                        _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
+                        if (clip)
+                        {
+                            _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color, *clip);
+                        }
+                        else
+                        {
+                            _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
+                        }
                     }
                 }
                 xPos += g.width*scale + ((float)size*0.125f);

+ 5 - 4
gameplay/src/Font.h

@@ -141,15 +141,16 @@ public:
      * Clips text outside the viewport.  Optionally wraps text to fit within the width of the viewport.
      *
      * @param text The text to draw.
-     * @param clip The viewport area to draw within.  Text will be clipped outside this rectangle.
+     * @param area The viewport area to draw within.  Text will be clipped outside this rectangle.
      * @param color The color of text.
      * @param size The size to draw text (0 for default size).
      * @param justify Justification of text within the viewport.
      * @param wrap Wraps text to fit within the width of the viewport if true.
-     * @param rightToLeft
+     * @param rightToLeft Whether to draw text from right to left.
+     * @param clip A region to clip text within after applying justification to the viewport area.
      */
-    void drawText(const char* text, const Rectangle& clip, const Vector4& color,
-        unsigned int size = 0, Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false);
+    void drawText(const char* text, const Rectangle& area, const Vector4& color,
+        unsigned int size = 0, Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false, const Rectangle* clip = NULL);
 
     /**
      * Measures a string's width and height without alignment, wrapping or clipping.

+ 8 - 11
gameplay/src/Form.cpp

@@ -134,20 +134,17 @@ namespace gameplay
 
     void Form::setNode(Node* node)
     {
-        // Set this Form up to be 3D by initializing a quad, projection matrix and viewport.
-        if (!_quad)
+        _node = node;
+
+        if (_node && !_quad)
         {
+            // Set this Form up to be 3D by initializing a quad, projection matrix and viewport.
             setQuad(0.0f, 0.0f, _size.x, _size.y);
-        }
-
-        Matrix::createOrthographicOffCenter(0, _size.x, _size.y, 0, 0, 1, &_projectionMatrix);
-        _theme->setProjectionMatrix(_projectionMatrix);
-        _viewport = new Viewport(0, 0, _size.x, _size.y);
 
-        // Connect the new node.
-        _node = node;
-        if (_node)
-        {
+            Matrix::createOrthographicOffCenter(0, _size.x, _size.y, 0, 0, 1, &_projectionMatrix);
+            _theme->setProjectionMatrix(_projectionMatrix);
+            _viewport = new Viewport(0, 0, _size.x, _size.y);
+            
             _node->setModel(_quad);
         }
     }

+ 18 - 1
gameplay/src/Label.cpp

@@ -33,6 +33,23 @@ namespace gameplay
             _text = text;
         }
     }
+
+    void Label::addListener(Control::Listener* listener, int eventFlags)
+    {
+        if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
+        {
+            assert("TEXT_CHANGED event is not applicable to this control.");
+            eventFlags &= ~Listener::TEXT_CHANGED;
+        }
+
+        if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
+        {
+            assert("VALUE_CHANGED event is not applicable to this control.");
+            eventFlags &= ~Listener::VALUE_CHANGED;
+        }
+
+        Control::addListener(listener, eventFlags);
+    }
     
     void Label::setText(const char* text)
     {
@@ -58,7 +75,7 @@ namespace gameplay
 
         // Draw the text.
         font->begin();
-        font->drawText(_text.c_str(), _clip, overlay->getTextColor(), overlay->getFontSize(), overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+        font->drawText(_text.c_str(), _textBounds, overlay->getTextColor(), overlay->getFontSize(), overlay->getTextAlignment(), true, overlay->getTextRightToLeft(), &_clip);
         font->end();
 
         _dirty = false;

+ 13 - 1
gameplay/src/Label.h

@@ -39,6 +39,18 @@ public:
      */
     const char* getText();
 
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
 protected:
     Label();
     virtual ~Label();
@@ -65,7 +77,7 @@ protected:
      */
     void drawText(const Rectangle& clip);
 
-    std::string _text;  // The text displayed by this label.
+    std::string _text;      // The text displayed by this label.
 
 private:
     Label(const Label& copy);

+ 18 - 1
gameplay/src/Node.cpp

@@ -13,7 +13,7 @@ namespace gameplay
 Node::Node(const char* id)
     : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(NULL),
     _camera(NULL), _light(NULL), _model(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL), _physicsRigidBody(NULL), 
-    _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true)
+    _ghostObject(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true)
 {
     if (id)
     {
@@ -36,13 +36,17 @@ Node::~Node()
         _audioSource->setNode(NULL);
     if (_particleEmitter)
         _particleEmitter->setNode(NULL);
+    if (_form)
+        _form->setNode(NULL);
 
     SAFE_RELEASE(_camera);
     SAFE_RELEASE(_light);
     SAFE_RELEASE(_model);
     SAFE_RELEASE(_audioSource);
     SAFE_RELEASE(_particleEmitter);
+    SAFE_RELEASE(_form);
     SAFE_DELETE(_physicsRigidBody);
+    SAFE_DELETE(_ghostObject);
 }
 
 Node* Node::create(const char* id)
@@ -777,4 +781,17 @@ void Node::setRigidBody(Properties* properties)
     _physicsRigidBody = PhysicsRigidBody::create(this, properties);
 }
 
+PhysicsGhostObject* Node::getGhostObject()
+{
+    return _ghostObject;
+}
+
+void Node::setGhostObject(PhysicsRigidBody::ShapeType type)
+{
+    SAFE_DELETE(_ghostObject);
+    
+    if (type != PhysicsRigidBody::SHAPE_NONE)
+        _ghostObject = new PhysicsGhostObject(this, type);
+}
+
 }

+ 19 - 0
gameplay/src/Node.h

@@ -8,6 +8,7 @@
 #include "Form.h"
 #include "AudioSource.h"
 #include "ParticleEmitter.h"
+#include "PhysicsGhostObject.h"
 #include "PhysicsRigidBody.h"
 #include "BoundingBox.h"
 
@@ -390,6 +391,23 @@ public:
     void setRigidBody(PhysicsRigidBody::ShapeType type, float mass = 0.0f, float friction = 0.5f,
         float restitution = 0.0f, float linearDamping = 0.0f, float angularDamping = 0.0f);
 
+    /**
+     * Returns the pointer to this node's physics ghost object or NULL.
+     * 
+     * @return The pointer to this node's physics ghost object or NULL.
+     */
+    PhysicsGhostObject* getGhostObject();
+
+    /**
+     * Sets (or disables) the physics ghost object for this node.
+     * 
+     * Note: This is only allowed for nodes that have a model attached to them.
+     *
+     * @param type The type of physics ghost object to set; to disable the physics ghost
+     *      object, pass PhysicsRigidBody#SHAPE_NONE.
+     */
+    void setGhostObject(PhysicsRigidBody::ShapeType type);
+
     /**
      * Sets the physics rigid body for this node using the rigid body definition in the given file.
      * 
@@ -473,6 +491,7 @@ protected:
     AudioSource* _audioSource;
     ParticleEmitter* _particleEmitter;
     PhysicsRigidBody* _physicsRigidBody;
+    PhysicsGhostObject* _ghostObject;
     mutable Matrix _world;
     mutable int _dirtyBits;
     bool _notifyHierarchyChanged;

+ 6 - 1
gameplay/src/PhysicsCollisionObject.h

@@ -30,7 +30,12 @@ public:
         /**
          * PhysicsCharacter type.
          */
-        CHARACTER
+        CHARACTER,
+
+        /** 
+         * PhysicsGhostObject type.
+         */
+        GHOST_OBJECT
     };
 
     /** 

+ 5 - 0
gameplay/src/PhysicsController.cpp

@@ -417,6 +417,10 @@ void PhysicsController::addCollisionObject(PhysicsCollisionObject* object)
         _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter);
         break;
 
+    case PhysicsCollisionObject::GHOST_OBJECT:
+        _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::AllFilter);
+        break;
+
     default:
         assert(0); // unexpected (new type?)
         break;
@@ -435,6 +439,7 @@ void PhysicsController::removeCollisionObject(PhysicsCollisionObject* object)
             break;
 
         case PhysicsCollisionObject::CHARACTER:
+        case PhysicsCollisionObject::GHOST_OBJECT:
             _world->removeCollisionObject(object->getCollisionObject());
             break;
 

+ 1 - 0
gameplay/src/PhysicsController.h

@@ -23,6 +23,7 @@ class PhysicsController : public btCollisionWorld::ContactResultCallback
     friend class PhysicsRigidBody;
     friend class PhysicsCharacter;
     friend class PhysicsCollisionObject;
+    friend class PhysicsGhostObject;
 
 public:
 

+ 93 - 0
gameplay/src/PhysicsGhostObject.cpp

@@ -0,0 +1,93 @@
+#include "Base.h"
+#include "Game.h"
+#include "PhysicsGhostObject.h"
+#include "Vector3.h"
+
+namespace gameplay
+{
+
+PhysicsGhostObject::PhysicsGhostObject(Node* node, PhysicsRigidBody::ShapeType type)
+    : _node(node), _motionState(NULL), _shape(NULL), _ghostObject(NULL)
+{
+    _node->addListener(this);
+
+    // Create the ghost object.
+    _ghostObject = bullet_new<btPairCachingGhostObject>();
+
+    // Get the node's world scale (we need to apply this during creation since ghost objects don't scale dynamically).
+    Vector3 scale;
+    _node->getWorldMatrix().getScale(&scale);
+
+    // Use the center of the bounding sphere as the center of mass offset.
+    Vector3 c(_node->getModel()->getMesh()->getBoundingSphere().center);
+    c.x *= scale.x;
+    c.y *= scale.y;
+    c.z *= scale.z;
+        
+    // Initialize a physics motion state object for syncing the transform.
+    Vector3 centerOfMassOffset(-c);
+    _motionState = new PhysicsMotionState(_node, &centerOfMassOffset);
+    _motionState->getWorldTransform(_ghostObject->getWorldTransform());
+
+    // Create and set the collision shape for the ghost object.
+    PhysicsController* physicsController = Game::getInstance()->getPhysicsController();
+    switch (type)
+    {
+        case PhysicsRigidBody::SHAPE_BOX:
+        {
+            const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
+            _shape = physicsController->createBox(box.min, box.max, scale);
+            break;
+        }
+        case PhysicsRigidBody::SHAPE_SPHERE:
+        {
+            const BoundingSphere& sphere = node->getModel()->getMesh()->getBoundingSphere();
+            _shape = physicsController->createSphere(sphere.radius, scale);
+            break;
+        }
+    }
+    _ghostObject->setCollisionShape(_shape);
+
+    // Add the ghost object to the physics world.
+    physicsController->addCollisionObject(this);
+}
+
+PhysicsGhostObject::~PhysicsGhostObject()
+{
+    Game::getInstance()->getPhysicsController()->removeCollisionObject(this);
+
+    _shape = NULL;
+    SAFE_DELETE(_ghostObject);
+    SAFE_DELETE(_motionState);
+}
+
+PhysicsCollisionObject::Type PhysicsGhostObject::getType() const
+{
+    return GHOST_OBJECT;
+}
+
+Node* PhysicsGhostObject::getNode() const
+{
+    return _node;
+}
+
+btCollisionObject* PhysicsGhostObject::getCollisionObject() const
+{
+    return _ghostObject;
+}
+
+btCollisionShape* PhysicsGhostObject::getCollisionShape() const
+{
+    return _shape;
+}
+
+void PhysicsGhostObject::transformChanged(Transform* transform, long cookie)
+{
+    // Update the motion state with the transform from the node.
+    _motionState->updateTransformFromNode();
+
+    // Update the transform on the ghost object.
+    _motionState->getWorldTransform(_ghostObject->getWorldTransform());
+}
+
+}

+ 73 - 0
gameplay/src/PhysicsGhostObject.h

@@ -0,0 +1,73 @@
+#ifndef PHYSICSGHOSTOBJECT_H_
+#define PHYSICSGHOSTOBJECT_H_
+
+#include "PhysicsCollisionObject.h"
+#include "PhysicsRigidBody.h"
+#include "Transform.h"
+
+namespace gameplay
+{
+
+class PhysicsMotionState;
+
+/**
+ * Defines a class for physics ghost objects.
+ */
+class PhysicsGhostObject : public PhysicsCollisionObject, public Transform::Listener
+{
+    friend class Node;
+    friend class PhysicsController;
+
+public:
+
+    /**
+     * @see PhysicsCollisionObject#getType
+     */
+    PhysicsCollisionObject::Type getType() const;
+
+    /**
+     * @see PhysicsCollisionObject#getNode
+     */
+    Node* getNode() const;
+
+protected:
+
+    /**
+     * @see PhysicsCollisionObject::getCollisionObject
+     */
+    btCollisionObject* getCollisionObject() const;
+
+    /**
+     * @see PhysicsCollisionObject::getCollisionShape
+     */
+    btCollisionShape* getCollisionShape() const;
+
+private:
+
+    /**
+     * Constructor.
+     * 
+     * @param node The node to attach the ghost object to.
+     * @param type The type of ghost object (collision shape type).
+     */
+    PhysicsGhostObject(Node* node, PhysicsRigidBody::ShapeType type);
+    
+    /**
+     * Destructor.
+     */
+    ~PhysicsGhostObject();
+
+    /**
+     * Used to synchronize the transform between GamePlay and Bullet.
+     */
+    void transformChanged(Transform* transform, long cookie);
+
+    Node* _node;
+    PhysicsMotionState* _motionState;
+    btCollisionShape* _shape;
+    btGhostObject* _ghostObject;
+};
+
+}
+
+#endif

+ 1 - 0
gameplay/src/PhysicsMotionState.h

@@ -17,6 +17,7 @@ class PhysicsMotionState : public btMotionState
     friend class PhysicsRigidBody;
     friend class PhysicsCharacter;
     friend class PhysicsConstraint;
+    friend class PhysicsGhostObject;
 
 protected:
 

+ 19 - 18
gameplay/src/RadioButton.cpp

@@ -65,6 +65,17 @@ const Vector2& RadioButton::getIconSize() const
     return _iconSize;
 }
 
+void RadioButton::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
+    {
+        assert("TEXT_CHANGED event is not applicable to RadioButton.");
+        eventFlags &= ~Listener::TEXT_CHANGED;
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
 bool RadioButton::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     if (!isEnabled())
@@ -81,8 +92,12 @@ bool RadioButton::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int c
                 if (x > 0 && x <= _bounds.width &&
                     y > 0 && y <= _bounds.height)
                 {
-                    RadioButton::clearSelected(_groupId);
-                    _selected = true;
+                    if (!_selected)
+                    {
+                        RadioButton::clearSelected(_groupId);
+                        _selected = true;
+                        notifyListeners(Listener::VALUE_CHANGED);
+                    }
                 }
             }
         }
@@ -158,22 +173,8 @@ void RadioButton::update(const Rectangle& clip)
     }
     float iconWidth = size.x;
 
-    _clip.x += iconWidth;
-    _clip.width -= iconWidth;
-}
-
-void RadioButton::drawText(const Rectangle& clip)
-{
-    // TODO: Batch all labels that use the same font.
-    Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-    Font* font = overlay->getFont();
-    
-    // Draw the text.
-    font->begin();
-    font->drawText(_text.c_str(), _clip, overlay->getTextColor(), overlay->getFontSize(), overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
-    font->end();
-
-    _dirty = false;
+    _textBounds.x += iconWidth;
+    _textBounds.width -= iconWidth;
 }
 
 }

+ 12 - 2
gameplay/src/RadioButton.h

@@ -53,6 +53,18 @@ public:
      */
     const Vector2& getIconSize() const;
 
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
 protected:
     RadioButton();
     virtual ~RadioButton();
@@ -73,8 +85,6 @@ protected:
 
     void drawSprites(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-    void drawText(const Rectangle& clip);
-
     // Clear the _selected flag of all radio buttons in the given group.
     static void clearSelected(const std::string& groupId);
 

+ 14 - 4
gameplay/src/Slider.cpp

@@ -64,6 +64,17 @@ void Slider::setValue(float value)
     _value = MATH_CLAMP(value, _min, _max);
 }
 
+void Slider::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
+    {
+        assert("TEXT_CHANGED event is not applicable to Slider.");
+        eventFlags &= ~Listener::TEXT_CHANGED;
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
 bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
     if (!isEnabled())
@@ -75,7 +86,6 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
     {
     case Touch::TOUCH_PRESS:
         _state = Control::ACTIVE;
-        _dirty = true;
         // Fall through to calculate new value.
 
     case Touch::TOUCH_MOVE:
@@ -121,16 +131,16 @@ bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contac
             }
 
             // Call the callback if our value changed.
-            if (_callback && _value != oldValue)
+            if (_value != oldValue)
             {
-                _callback->trigger(this);
+                notifyListeners(Listener::VALUE_CHANGED);
             }
 
             _dirty = true;
         }
     }
 
-    return _consumeTouchEvents;
+    return Control::touchEvent(evt, x, y, contactIndex);
 }
 
 void Slider::drawSprites(SpriteBatch* spriteBatch, const Rectangle& clip)

+ 3 - 1
gameplay/src/Slider.h

@@ -27,7 +27,7 @@ namespace gameplay
  *      text        = <string>                  // Text to display above, below or alongside the slider (depending on the style).
  *  }
  */
-class Slider : public Button
+class Slider : public Label
 {
     friend class Container;
 
@@ -90,6 +90,8 @@ public:
      */
     float getValue();
 
+    void addListener(Control::Listener* listener, int eventFlags);
+
 protected:
     Slider();
     ~Slider();

+ 19 - 16
gameplay/src/TextBox.cpp

@@ -4,9 +4,7 @@
 namespace gameplay
 {
 
-static std::vector<TextBox*> __textBoxes;
-
-TextBox::TextBox()
+TextBox::TextBox() : _lastKeypress(0)
 {
 }
 
@@ -22,24 +20,13 @@ TextBox* TextBox::create(Theme::Style* style, Properties* properties)
 {
     TextBox* textBox = new TextBox();
     textBox->init(style, properties);
-    __textBoxes.push_back(textBox);
 
     return textBox;
 }
 
-TextBox* TextBox::getTextBox(const char* id)
+int TextBox::getLastKeypress()
 {
-    std::vector<TextBox*>::const_iterator it;
-    for (it = __textBoxes.begin(); it < __textBoxes.end(); it++)
-    {
-        TextBox* t = *it;
-        if (strcmp(id, t->getID()) == 0)
-        {
-            return t;
-        }
-    }
-
-    return NULL;
+    return _lastKeypress;
 }
 
 void TextBox::setCursorLocation(int x, int y)
@@ -57,6 +44,17 @@ void TextBox::setCursorLocation(int x, int y)
                        y - border.top - padding.top + _clip.y);
 }
 
+void TextBox::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
+    {
+        assert("VALUE_CHANGED event is not applicable to TextBox.");
+        eventFlags &= ~Listener::VALUE_CHANGED;
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
 bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {   
     if (!isEnabled())
@@ -144,6 +142,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
                             overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
                         _dirty = true;
+                        notifyListeners(Listener::TEXT_CHANGED);
                         break;
                     }
                     case Keyboard::KEY_LEFT_ARROW:
@@ -241,9 +240,13 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
             
                     break;
                 }
+
+                notifyListeners(Listener::TEXT_CHANGED);
             }
         }
     }
+
+    _lastKeypress = key;
 }
 
 void TextBox::update(const Rectangle& clip)

+ 43 - 8
gameplay/src/TextBox.h

@@ -9,11 +9,49 @@
 namespace gameplay
 {
 
+/**
+ * An editable text label.  Tap or click within the text box to bring up the
+ * virtual keyboard.
+ *
+ * Listeners can listen for a TEXT_CHANGED event, and then query the text box
+ * for the last keypress it received.
+ *
+ * The following properties are available for text boxes:
+ *
+ * label <Label ID>
+ * {
+ *      style       = <Style ID>
+ *      position    = <x, y>
+ *      size        = <width, height>
+ *      text        = <string>
+ * }
+ */
 class TextBox : public Label
 {
+    friend class Container;
+
 public:
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
+    int getLastKeypress();
+
+protected:
+    TextBox();
+    ~TextBox();
+
     static TextBox* create(Theme::Style* style, Properties* properties);
-    static TextBox* getTextBox(const char* id);
+
+    void setCursorLocation(int x, int y);
 
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
@@ -24,15 +62,12 @@ public:
     // Draw the cursor.
     void drawSprites(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-private:
-    TextBox();
-    TextBox(const TextBox& copy);
-    ~TextBox();
-
-    void setCursorLocation(int x, int y);
-
     Vector2 _cursorLocation;
     unsigned int textIndex;
+    int _lastKeypress;
+
+private:
+    TextBox(const TextBox& copy);
 };
 
 }

+ 244 - 16
gameplay/src/Theme.h

@@ -1,7 +1,3 @@
-/*
- * Theme.h
- */
-
 #ifndef THEME_H_
 #define THEME_H_
 
@@ -19,10 +15,107 @@ static const unsigned int MAX_OVERLAYS = 4;
 static const unsigned int MAX_OVERLAY_REGIONS = 9;
 
 /**
- * This class represents the appearance of an UI form described in a 
- * theme file. A theme file, at its simplest, contains a source texture atlas,
- * the texture coordinates of each control in its different mode. Once loaded,
- * the appearance properties can be retrieved using a style id and set on a UI control.
+ * A theme is created and stored as part of a form and represents its appearance.
+ * Once loaded, the appearance properties can be retrieved from their style IDs and set on other
+ * UI controls.  A Theme has one property, 'texture', which points to an image containing
+ * all the Icon, Cursor, Slider, and Container sprites used by the theme.  Each set of sprites within
+ * the texture is described in its own namespace.  The rest of the Theme consists of Style namespaces.
+ * A Style describes the border, margin, and padding of a Control, what icons and cursors (if any) are
+ * associated with a Control, and Font properties to apply to a Control's text.
+ *
+ * Below is an explanation of the properties that can be set within themes:
+ *
+ * theme
+ * {
+ *    texture = <Path to texture>
+ *
+ *    // Describes the images used for CheckBox and RadioButton icons.
+ *    icon <iconID>
+ *    {
+ *        size            =   <width, height>     // Size of this icon.
+ *        offPosition     =   <x, y>              // Position of the unchecked / unselected image.
+ *        onPosition      =   <x, y>              // Position of the checked / selected image.
+ *        color           =   <#ffffffff>         // Tint to apply to icon.
+ *    }
+ *   
+ *    cursor <cursorID>
+ *    {
+ *        region  =   <x, y, width, height>   // Region within the texture of cursor sprite.
+ *        color   =   <#ffffffff>             // Tint to apply to cursor.
+ *    }
+ *   
+ *    slider <sliderID>
+ *    {
+ *        minCapRegion    =   <x, y, width, height>   // Left / bottom slider cap.
+ *        maxCapRegion    =   <x, y, width, height>   // Right / top slider cap.
+ *        markerRegion    =   <x, y, width, height>   // Shows the slider's current position.
+ *        trackRegion     =   <x, y, width, height>   // Track the marker slides along.
+ *        color           =   <#ffffffff>             // Tint to apply to slider sprites.
+ *    }
+ *   
+ *    // Defines the border and background of a Control.
+ *    container <containerID>
+ *    {
+ *        // 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 container sprites.
+ *    }
+ *   
+ *    style <styleID>
+ *    {
+ *        // Layouts may make use of a style's margin to put space between adjacent controls.
+ *        margin
+ *        {
+ *            top     =   <int>
+ *            bottom  =   <int>
+ *            left    =   <int>
+ *            right   =   <int>        
+ *        }
+ *       
+ *        // Padding is the space between a control's border and its content.
+ *        padding
+ *        {
+ *            top     =   <int>
+ *            bottom  =   <int>
+ *            left    =   <int>
+ *            right   =   <int>        
+ *        }
+ *       
+ *        // This overlay is used when a control is enabled but not active or focused.
+ *        normal
+ *        {
+ *            container   =   <containerID>               // Container to use for border and background sprites.
+ *            checkBox    =   <iconID>                    // Icon to use for checkbox sprites.
+ *            radioButton =   <iconID>                    // Icon to use for radioButton sprites.
+ *            slider      =   <sliderID>                  // Slider to use for slider sprites.
+ *            mouseCursor =   <cursorID>                  // Cursor to use when the mouse is over this control.
+ *            textCursor  =   <cursorID>                  // Cursor to use within a textBox.
+ *            font        =   <Path to font>              // Font to use for rendering text.
+ *            fontSize    =   <int>                       // Size of text.
+ *            textColor   =   <#ffffffff>                 // Color of text.
+ *            alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
+ *            rightToLeft =   <bool>                      // Whether to draw text from right to left.
+ *        }
+ *       
+ *        // This overlay is used when the control is in focus.
+ *        // If not specified, the 'normal' overlay will be used.
+ *        focus{}
+ *       
+ *        // This overlay is used when the control is active.
+ *        // (Touch or mouse is down within the control.)
+ *        // If not specified, the 'normal' overlay will be used.
+ *        active{}
+ *    }
+ * }
+ *
  */
 class Theme: public Ref
 {
@@ -58,6 +151,9 @@ private:
     SpriteBatch* getSpriteBatch() const;
 
 public:
+    /**
+     * Struct representing the UV coordinates of a rectangular image.
+     */
     typedef struct UVs
     {
         float u1;
@@ -66,6 +162,10 @@ public:
         float v2;
     } UVs;
 
+    /**
+     * Struct representing margin, border, and padding areas by
+     * the width or height of each side.
+     */
     typedef struct padding
     {
         float top;
@@ -76,15 +176,46 @@ public:
         padding() : top(0), bottom(0), left(0), right(0) {}
     } Margin, Border, Padding;
 
+    /**
+     * An icon with two images representing "on" and "off" states.
+     */
     class Icon : public Ref
     {
         friend class Theme;
 
     public:
+        /**
+         * Get this icon's ID.
+         *
+         * @return This icon's ID.
+         */
         const char* getId() const;
+
+        /**
+         * Get this icon's size.
+         *
+         * @return This icon's size.
+         */
         const Vector2& getSize() const;
+        /**
+         * Get this icon's color.
+         *
+         * @return This icon's color.
+         */
         const Vector4& getColor() const;
+
+        /**
+         * Get the UVs for this icon's off-state image.
+         *
+         * @return The UVs for this icon's off-state image.
+         */
         const Theme::UVs& getOffUVs() const;
+
+        /**
+         * Get the UVs for this icon's on-state image.
+         *
+         * @return The UVs for this icon's on-state image.
+         */
         const Theme::UVs& getOnUVs() const;
 
     private:
@@ -102,20 +233,83 @@ public:
         UVs _on;
     };
 
+    /**
+     * A set of four icons that make up a slider:
+     * two end-caps, a track, and a marker to be placed along the track.
+     */
     class SliderIcon : public Ref
     {
         friend class Theme;
 
     public:
+        /**
+         * Get this slider icon's ID.
+         *
+         * @return This slider icon's ID.
+         */
         const char* getId() const;
+
+        /**
+         * Get the UVs for this slider's min-cap image.
+         *
+         * @return The UVs for this slider's min-cap image.
+         */
         const Theme::UVs& getMinCapUVs() const;
+
+        /**
+         * Get the UVs for this slider's max-cap image.
+         *
+         * @return The UVs for this slider's max-cap image.
+         */
         const Theme::UVs& getMaxCapUVs() const;
+
+        /**
+         * Get the UVs for this slider's marker image.
+         *
+         * @return The UVs for this slider's marker image.
+         */
         const Theme::UVs& getMarkerUVs() const;
+
+        /**
+         * Get the UVs for this slider's track image.
+         *
+         * @return The UVs for this slider's track image.
+         */
         const Theme::UVs& getTrackUVs() const;
+
+        /**
+         * Get this slider's min-cap size.
+         *
+         * @return This slider's min-cap size.
+         */
         const Vector2& getMinCapSize() const;
+
+        /**
+         * Get this slider's max-cap size.
+         *
+         * @return This slider's max-cap size.
+         */
         const Vector2& getMaxCapSize() const;
+
+        /**
+         * Get this slider's marker size.
+         *
+         * @return This slider's marker size.
+         */
         const Vector2& getMarkerSize() const;
+
+        /**
+         * Get this slider's track size.
+         *
+         * @return This slider's track size.
+         */
         const Vector2& getTrackSize() const;
+
+        /**
+         * Get this slider's color.
+         *
+         * @return This slider's color.
+         */
         const Vector4& getColor() const;
 
     private:
@@ -149,16 +343,30 @@ public:
     public:
        /**
         * Returns the Id of this Cursor.
+        *
+        * @return This cursor's ID.
         */
         const char* getId() const;
 
        /**
         * Gets a UV coordinates computed from the texture region.
+        *
+        * @return This cursor's UVs.
         */
         const Theme::UVs& getUVs() const;
 
+        /**
+         * Gets this cursor's size.
+         *
+         * @return This cursor's size.
+         */
         const Vector2& getSize() const;
 
+        /**
+         * Gets this cursor's color.
+         *
+         * @return This cursor's color.
+         */
         const Vector4& getColor() const;
     
     private:
@@ -174,6 +382,9 @@ public:
         Vector4 _color;
     };
 
+    /**
+     * A container region defines the border and background of a control.
+     */
     class ContainerRegion : public Ref
     {
         friend class Theme;
@@ -186,19 +397,33 @@ public:
             BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT
         };
 
+        /**
+         * Gets this container area's ID.
+         *
+         * @return This container area's ID.
+         */
         const char* getId() const;
+
+        /**
+         * Gets this container area's border.
+         *
+         * @return This container area's border.
+         */
         const Theme::Border& getBorder() const;
-        const Theme::UVs& getUVs(ContainerArea area) const;
-        const Vector4& getColor() const;
-        
+
         /**
-         * Set the size of this ContainerRegion's border.
+         * Gets this container area's UVs.
          *
-         * When auto-size is set on width and/or height:
-         * Space added to the calculated (tightly bound) width and height.
+         * @return This container area's UVs.
+         */
+        const Theme::UVs& getUVs(ContainerArea area) const;
+
+        /**
+         * Gets this container area's color.
          *
+         * @return This container area's color.
          */
-        //void setBorder(float top, float bottom, float left, float right);
+        const Vector4& getColor() const;
 
     private:
         ContainerRegion(const Texture& texture, const Rectangle& region, const Theme::Border& border, const Vector4& color);
@@ -214,7 +439,10 @@ public:
     };
     
     /**
-     * This class represents the apperance of a control.
+     * This class represents the appearance of a control.  A style can have padding and margin values,
+     * as well as overlays for each of the control's states.  Each overlay in turn can reference
+     * the above classes to determine the border, background, cursor, and icon settings to use for
+     * a particular state.
      */
     class Style
     {

+ 12 - 2
gameplay/src/VerticalLayout.cpp

@@ -3,6 +3,8 @@
 
 namespace gameplay
 {
+    static VerticalLayout* __instance;
+
     VerticalLayout::VerticalLayout() : _bottomToTop(false)
     {
     }
@@ -17,8 +19,16 @@ namespace gameplay
 
     VerticalLayout* VerticalLayout::create()
     {
-        VerticalLayout* al = new VerticalLayout();
-        return al;
+        if (!__instance)
+        {
+            __instance = new VerticalLayout();
+        }
+        else
+        {
+            __instance->addRef();
+        }
+
+        return __instance;
     }
 
     void VerticalLayout::setBottomToTop(bool bottomToTop)