瀏覽代碼

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

Adam Blake 13 年之前
父節點
當前提交
9debd4a0de

+ 19 - 16
gameplay-newproject.sh

@@ -20,7 +20,7 @@ echo "   This name will be given to the project"
 echo "   executable and a folder with this name"
 echo "   will be created to store all project files."
 echo
-read -p "Project Name: " "" projName 
+read -p "Project Name: " projName 
 if [[ "$projName" == "" ]]; then
 	echo
 	echo "ERROR: No project name specified."
@@ -36,7 +36,7 @@ echo "   On some platforms, this title is used to"
 echo "   identify the game during installation and"
 echo "   on shortcuts/icons."
 echo
-read -p "Title: " "" title 
+read -p "Title: " title 
 if [[ "$title" == "" ]]; then
 	echo
 	echo "ERROR: No game title specified."
@@ -48,7 +48,7 @@ echo
 echo
 echo "3. Enter a short game description."
 echo
-read -p "Description: " "" desc
+read -p "Description: " desc
 if [[ "$desc" == "" ]]; then
 	desc=$title
 fi
@@ -61,7 +61,7 @@ echo "   This should be a human readable package name,"
 echo "   containing at least two words separated by a"
 echo "   period (eg. com.surname.gamename)."
 echo
-read -p "Unique ID: " "" uuid
+read -p "Unique ID: " uuid
 if [[ "$uuid" == "" ]]; then
 	echo
 	echo "ERROR: No uuid specified."
@@ -77,7 +77,7 @@ echo "   On BlackBerry targets, this is used for"
 echo "   signing and must match the developer name"
 echo "   of your development certificate."
 echo
-read -p "Author: " "" author
+read -p "Author: " author
 if [[ "$author" == "" ]]; then
 	echo
 	echo "ERROR: No author specified."
@@ -93,7 +93,7 @@ echo "   Your initial game header and source file"
 echo "   will be given this name and a class with"
 echo "   this name will be created in these files."
 echo
-read -p "Class name: " "" className
+read -p "Class name: " className
 if [[ "$className" == "" ]]; then
 	echo
 	echo "ERROR: No class name specified."
@@ -110,7 +110,7 @@ echo "   or empty for the current folder. Note that"
 echo "   a project folder named $projName will also"
 echo "   be created inside this folder."
 echo
-read -p "Path: " "" location
+read -p "Path: " location
 if [[ "$location" == "" ]]; then
 	projPath=$projName
 else
@@ -118,7 +118,6 @@ else
 fi
 echo
 
-
 # Verify Path and eliminate double '//'
 projPath=`echo "$projPath" | sed 's_//_/_g'`
 if [ -e $projPath ]; then
@@ -129,14 +128,18 @@ if [ -e $projPath ]; then
 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 [[ ${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/src"

+ 105 - 9
gameplay-template/gameplay-template.xcodeproj/project.pbxproj

@@ -22,7 +22,6 @@
 		42C933291491A6E50098216A /* libvorbisfile.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933251491A6E50098216A /* libvorbisfile.a */; };
 		42C9332C1491A7680098216A /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332A1491A7390098216A /* libpng.a */; };
 		42C9332F1491A78D0098216A /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C9332D1491A7810098216A /* libz.dylib */; };
-		5B61611314CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */; };
 		5B61611614CCC24C0073B857 /* TemplateGame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 42C932EF1491A5160098216A /* TemplateGame.cpp */; };
 		5B61611814CCC24C0073B857 /* libgameplay.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42438B521491AD2000D218B8 /* libgameplay.a */; };
 		5B61611914CCC24C0073B857 /* libbullet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42C933201491A6C70098216A /* libbullet.a */; };
@@ -34,14 +33,62 @@
 		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 */; };
-		5B61612814CCC24C0073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B61611214CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist */; };
 		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 */; };
+		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;
+			buildActionMask = 2147483647;
+			dstPath = res;
+			dstSubfolderSpec = 7;
+			files = (
+				5BC4E84E150F913F00CBE1C0 /* shaders in Copy GamePlay Bundle Resources */,
+				5BC4E84F150F913F00CBE1C0 /* textures in Copy GamePlay Bundle Resources */,
+			);
+			name = "Copy GamePlay Bundle Resources";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		5BC4E850150F914500CBE1C0 /* Copy GamePlay Bundle Resources */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = res;
+			dstSubfolderSpec = 7;
+			files = (
+				5BC4E851150F915300CBE1C0 /* shaders in Copy GamePlay Bundle Resources */,
+				5BC4E852150F915300CBE1C0 /* textures in Copy GamePlay Bundle Resources */,
+			);
+			name = "Copy GamePlay Bundle Resources";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
 /* Begin PBXFileReference section */
 		42438B521491AD2000D218B8 /* libgameplay.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgameplay.a; path = "~/Library/Developer/Xcode/DerivedData/gameplay-exiunaubxxjndaapmcqkaoeboiob/Build/Products/Debug/libgameplay.a"; sourceTree = "<group>"; };
 		42C932BC1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TEMPLATE_PROJECT-MacOSX.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -62,12 +109,16 @@
 		42C9332D1491A7810098216A /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
 		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; name = "TEMPLATE_PROJECT-ios.plist"; path = "/Users/bslack/src/git/GamePlay/gameplay-template/TEMPLATE_PROJECT-ios.plist"; sourceTree = "<absolute>"; };
+		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; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -94,6 +145,7 @@
 			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 */,
@@ -139,6 +191,7 @@
 		42C932BF1491A0DB0098216A /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				5BC4E825150F8CE600CBE1C0 /* GamePlay */,
 				5B61613A14CCC3590073B857 /* Mac OS X */,
 				5B61613914CCC3560073B857 /* iOS */,
 			);
@@ -172,6 +225,7 @@
 		5B61613914CCC3560073B857 /* iOS */ = {
 			isa = PBXGroup;
 			children = (
+				5BC4E8AF150F943A00CBE1C0 /* Foundation.framework */,
 				5B61613714CCC3500073B857 /* QuartzCore.framework */,
 				5B61613514CCC3490073B857 /* CoreMotion.framework */,
 				5B61613314CCC3420073B857 /* UIKit.framework */,
@@ -192,6 +246,25 @@
 			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 = (
+				5BC4E849150F911D00CBE1C0 /* shaders */,
+				5BC4E84A150F911D00CBE1C0 /* textures */,
+				5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */,
+			);
+			name = GamePlay;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -203,6 +276,7 @@
 				42C932B91491A0DB0098216A /* Frameworks */,
 				42C933301491A7B50098216A /* ShellScript */,
 				42C932BA1491A0DB0098216A /* Resources */,
+				5BC4E84D150F912B00CBE1C0 /* Copy GamePlay Bundle Resources */,
 			);
 			buildRules = (
 			);
@@ -221,6 +295,7 @@
 				5B61611714CCC24C0073B857 /* Frameworks */,
 				5B61612414CCC24C0073B857 /* ShellScript */,
 				5B61612514CCC24C0073B857 /* Resources */,
+				5BC4E850150F914500CBE1C0 /* Copy GamePlay Bundle Resources */,
 			);
 			buildRules = (
 			);
@@ -249,6 +324,12 @@
 			mainGroup = 42C932B11491A0DB0098216A;
 			productRefGroup = 42C932BD1491A0DB0098216A /* Products */;
 			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = 5BC4E7BB150F8B7B00CBE1C0 /* Products */;
+					ProjectRef = 5BC4E77F150F879E00CBE1C0 /* gameplay.xcodeproj */;
+				},
+			);
 			projectRoot = "";
 			targets = (
 				42C932BB1491A0DB0098216A /* TEMPLATE_PROJECT-MacOSX */,
@@ -257,6 +338,23 @@
 		};
 /* 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;
@@ -264,7 +362,6 @@
 			files = (
 				42C932EE1491A4CB0098216A /* icon.png in Resources */,
 				42C932F31491A53E0098216A /* res in Resources */,
-				5B61611314CCC2200073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -274,7 +371,6 @@
 			files = (
 				5B61612614CCC24C0073B857 /* icon.png in Resources */,
 				5B61612714CCC24C0073B857 /* res in Resources */,
-				5B61612814CCC24C0073B857 /* TEMPLATE_PROJECT-macos.plist in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -393,7 +489,7 @@
 					"GAMEPLAY_PATH/external-deps/bullet/include",
 					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
 				);
-				INFOPLIST_FILE = "gameplay-template-macos.plist";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macos\"",
@@ -419,7 +515,7 @@
 					"GAMEPLAY_PATH/external-deps/bullet/include",
 					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
 				);
-				INFOPLIST_FILE = "gameplay-template-macos.plist";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-macos.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"GAMEPLAY_PATH/external-deps/libpng/lib/macos\"",
@@ -444,7 +540,7 @@
 					"GAMEPLAY_PATH/external-deps/bullet/include",
 					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
 				);
-				INFOPLIST_FILE = "gameplay-template-ios.plist";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-ios.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"GAMEPLAY_PATH/external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",
@@ -469,7 +565,7 @@
 					"GAMEPLAY_PATH/external-deps/bullet/include",
 					"GAMEPLAY_PATH/external-deps/oggvorbis/include",
 				);
-				INFOPLIST_FILE = "gameplay-template-ios.plist";
+				INFOPLIST_FILE = "TEMPLATE_PROJECT-ios.plist";
 				LIBRARY_SEARCH_PATHS = (
 					"$(inherited)",
 					"\"GAMEPLAY_PATH/external-deps/libpng/lib/ios/$(CURRENT_ARCH)\"",

+ 2 - 0
gameplay/gameplay.vcxproj

@@ -62,6 +62,7 @@
     <ClCompile Include="src\Package.cpp" />
     <ClCompile Include="src\ParticleEmitter.cpp" />
     <ClCompile Include="src\PhysicsCharacter.cpp" />
+    <ClCompile Include="src\PhysicsCollisionObject.cpp" />
     <ClCompile Include="src\PhysicsConstraint.cpp" />
     <ClCompile Include="src\PhysicsController.cpp" />
     <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
@@ -150,6 +151,7 @@
     <ClInclude Include="src\Package.h" />
     <ClInclude Include="src\ParticleEmitter.h" />
     <ClInclude Include="src\PhysicsCharacter.h" />
+    <ClInclude Include="src\PhysicsCollisionObject.h" />
     <ClInclude Include="src\PhysicsConstraint.h" />
     <ClInclude Include="src\PhysicsController.h" />
     <ClInclude Include="src\PhysicsFixedConstraint.h" />

+ 7 - 1
gameplay/gameplay.vcxproj.filters

@@ -267,6 +267,9 @@
     <ClCompile Include="src\PhysicsCharacter.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\PhysicsCollisionObject.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">
@@ -524,6 +527,9 @@
     <ClInclude Include="src\PhysicsCharacter.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\PhysicsCollisionObject.h">
+      <Filter>src</Filter>
+    </ClInclude>
     <ClInclude Include="src\TimeListener.h">
       <Filter>src</Filter>
     </ClInclude>
@@ -661,4 +667,4 @@
       <Filter>src</Filter>
     </None>
   </ItemGroup>
-</Project>
+</Project>

+ 206 - 26
gameplay/gameplay.xcodeproj/project.pbxproj

@@ -306,6 +306,67 @@
 		5B5ADD2F14C2439700AC6109 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B5ADD2E14C2439700AC6109 /* Foundation.framework */; };
 		5BB0823D14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
 		5BB0823E14C6FEC40019975F /* Mouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BB0823C14C6FEC40019975F /* Mouse.h */; };
+		5BC4E73F150F843D00CBE1C0 /* AbsoluteLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */; };
+		5BC4E740150F843D00CBE1C0 /* AbsoluteLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52635150F822A004C9099 /* AbsoluteLayout.h */; };
+		5BC4E741150F843D00CBE1C0 /* Button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52636150F822A004C9099 /* Button.cpp */; };
+		5BC4E742150F843D00CBE1C0 /* Button.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52637150F822A004C9099 /* Button.h */; };
+		5BC4E743150F843D00CBE1C0 /* CheckBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52638150F822A004C9099 /* CheckBox.cpp */; };
+		5BC4E744150F843D00CBE1C0 /* CheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52639150F822A004C9099 /* CheckBox.h */; };
+		5BC4E745150F843D00CBE1C0 /* Container.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263A150F822A004C9099 /* Container.cpp */; };
+		5BC4E746150F843D00CBE1C0 /* Container.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263B150F822A004C9099 /* Container.h */; };
+		5BC4E747150F843D00CBE1C0 /* Control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263C150F822A004C9099 /* Control.cpp */; };
+		5BC4E748150F843D00CBE1C0 /* Control.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263D150F822A004C9099 /* Control.h */; };
+		5BC4E749150F843D00CBE1C0 /* FlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263E150F822A004C9099 /* FlowLayout.h */; };
+		5BC4E74A150F843D00CBE1C0 /* Form.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263F150F822A004C9099 /* Form.cpp */; };
+		5BC4E74B150F843D00CBE1C0 /* Form.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52640150F822A004C9099 /* Form.h */; };
+		5BC4E74C150F843D00CBE1C0 /* Label.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52641150F822A004C9099 /* Label.cpp */; };
+		5BC4E74D150F843D00CBE1C0 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52642150F822A004C9099 /* Label.h */; };
+		5BC4E74E150F843D00CBE1C0 /* Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52643150F822A004C9099 /* Layout.h */; };
+		5BC4E74F150F843D00CBE1C0 /* RadioButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52644150F822A004C9099 /* RadioButton.cpp */; };
+		5BC4E750150F843D00CBE1C0 /* RadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52645150F822A004C9099 /* RadioButton.h */; };
+		5BC4E751150F843D00CBE1C0 /* Slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52646150F822A004C9099 /* Slider.cpp */; };
+		5BC4E752150F843D00CBE1C0 /* Slider.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52647150F822A004C9099 /* Slider.h */; };
+		5BC4E753150F843D00CBE1C0 /* TextBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52648150F822A004C9099 /* TextBox.cpp */; };
+		5BC4E754150F843D00CBE1C0 /* TextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52649150F822A004C9099 /* TextBox.h */; };
+		5BC4E755150F843D00CBE1C0 /* Theme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264A150F822A004C9099 /* Theme.cpp */; };
+		5BC4E756150F843D00CBE1C0 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264B150F822A004C9099 /* Theme.h */; };
+		5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264D150F822A004C9099 /* VerticalLayout.cpp */; };
+		5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264E150F822A004C9099 /* VerticalLayout.h */; };
+		5BD5264F150F822A004C9099 /* AbsoluteLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */; };
+		5BD52650150F822A004C9099 /* AbsoluteLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52635150F822A004C9099 /* AbsoluteLayout.h */; };
+		5BD52651150F822A004C9099 /* Button.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52636150F822A004C9099 /* Button.cpp */; };
+		5BD52652150F822A004C9099 /* Button.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52637150F822A004C9099 /* Button.h */; };
+		5BD52653150F822A004C9099 /* CheckBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52638150F822A004C9099 /* CheckBox.cpp */; };
+		5BD52654150F822A004C9099 /* CheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52639150F822A004C9099 /* CheckBox.h */; };
+		5BD52655150F822A004C9099 /* Container.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263A150F822A004C9099 /* Container.cpp */; };
+		5BD52656150F822A004C9099 /* Container.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263B150F822A004C9099 /* Container.h */; };
+		5BD52657150F822A004C9099 /* Control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263C150F822A004C9099 /* Control.cpp */; };
+		5BD52658150F822A004C9099 /* Control.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263D150F822A004C9099 /* Control.h */; };
+		5BD52659150F822A004C9099 /* FlowLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5263E150F822A004C9099 /* FlowLayout.h */; };
+		5BD5265A150F822A004C9099 /* Form.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5263F150F822A004C9099 /* Form.cpp */; };
+		5BD5265B150F822A004C9099 /* Form.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52640150F822A004C9099 /* Form.h */; };
+		5BD5265C150F822A004C9099 /* Label.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52641150F822A004C9099 /* Label.cpp */; };
+		5BD5265D150F822A004C9099 /* Label.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52642150F822A004C9099 /* Label.h */; };
+		5BD5265E150F822A004C9099 /* Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52643150F822A004C9099 /* Layout.h */; };
+		5BD5265F150F822A004C9099 /* RadioButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52644150F822A004C9099 /* RadioButton.cpp */; };
+		5BD52660150F822A004C9099 /* RadioButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52645150F822A004C9099 /* RadioButton.h */; };
+		5BD52661150F822A004C9099 /* Slider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52646150F822A004C9099 /* Slider.cpp */; };
+		5BD52662150F822A004C9099 /* Slider.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52647150F822A004C9099 /* Slider.h */; };
+		5BD52663150F822A004C9099 /* TextBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD52648150F822A004C9099 /* TextBox.cpp */; };
+		5BD52664150F822A004C9099 /* TextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD52649150F822A004C9099 /* TextBox.h */; };
+		5BD52665150F822A004C9099 /* Theme.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264A150F822A004C9099 /* Theme.cpp */; };
+		5BD52666150F822A004C9099 /* Theme.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264B150F822A004C9099 /* Theme.h */; };
+		5BD52667150F822A004C9099 /* TimeListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264C150F822A004C9099 /* TimeListener.h */; };
+		5BD52668150F822A004C9099 /* VerticalLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5264D150F822A004C9099 /* VerticalLayout.cpp */; };
+		5BD52669150F822A004C9099 /* VerticalLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5264E150F822A004C9099 /* VerticalLayout.h */; };
+		5BD5266F150F8258004C9099 /* PhysicsCharacter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */; };
+		5BD52670150F8258004C9099 /* PhysicsCharacter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */; };
+		5BD52671150F8258004C9099 /* PhysicsCharacter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266C150F8257004C9099 /* PhysicsCharacter.h */; };
+		5BD52672150F8258004C9099 /* PhysicsCharacter.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266C150F8257004C9099 /* PhysicsCharacter.h */; };
+		5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
+		5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
+		5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
+		5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
 		5BD776FD14C77E1F001CADA0 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BD776FC14C77E1F001CADA0 /* CoreMotion.framework */; };
 /* End PBXBuildFile section */
 
@@ -500,6 +561,39 @@
 		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; };
+		5BC4E7D4150F8C3C00CBE1C0 /* res */ = {isa = PBXFileReference; lastKnownFileType = folder; path = res; sourceTree = "<group>"; };
+		5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AbsoluteLayout.cpp; path = src/AbsoluteLayout.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52635150F822A004C9099 /* AbsoluteLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AbsoluteLayout.h; path = src/AbsoluteLayout.h; sourceTree = SOURCE_ROOT; };
+		5BD52636150F822A004C9099 /* Button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Button.cpp; path = src/Button.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52637150F822A004C9099 /* Button.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Button.h; path = src/Button.h; sourceTree = SOURCE_ROOT; };
+		5BD52638150F822A004C9099 /* CheckBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckBox.cpp; path = src/CheckBox.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52639150F822A004C9099 /* CheckBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CheckBox.h; path = src/CheckBox.h; sourceTree = SOURCE_ROOT; };
+		5BD5263A150F822A004C9099 /* Container.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Container.cpp; path = src/Container.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5263B150F822A004C9099 /* Container.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Container.h; path = src/Container.h; sourceTree = SOURCE_ROOT; };
+		5BD5263C150F822A004C9099 /* Control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Control.cpp; path = src/Control.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5263D150F822A004C9099 /* Control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Control.h; path = src/Control.h; sourceTree = SOURCE_ROOT; };
+		5BD5263E150F822A004C9099 /* FlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FlowLayout.h; path = src/FlowLayout.h; sourceTree = SOURCE_ROOT; };
+		5BD5263F150F822A004C9099 /* Form.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Form.cpp; path = src/Form.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52640150F822A004C9099 /* Form.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Form.h; path = src/Form.h; sourceTree = SOURCE_ROOT; };
+		5BD52641150F822A004C9099 /* Label.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Label.cpp; path = src/Label.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52642150F822A004C9099 /* Label.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Label.h; path = src/Label.h; sourceTree = SOURCE_ROOT; };
+		5BD52643150F822A004C9099 /* Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Layout.h; path = src/Layout.h; sourceTree = SOURCE_ROOT; };
+		5BD52644150F822A004C9099 /* RadioButton.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RadioButton.cpp; path = src/RadioButton.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52645150F822A004C9099 /* RadioButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RadioButton.h; path = src/RadioButton.h; sourceTree = SOURCE_ROOT; };
+		5BD52646150F822A004C9099 /* Slider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Slider.cpp; path = src/Slider.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52647150F822A004C9099 /* Slider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Slider.h; path = src/Slider.h; sourceTree = SOURCE_ROOT; };
+		5BD52648150F822A004C9099 /* TextBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TextBox.cpp; path = src/TextBox.cpp; sourceTree = SOURCE_ROOT; };
+		5BD52649150F822A004C9099 /* TextBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TextBox.h; path = src/TextBox.h; sourceTree = SOURCE_ROOT; };
+		5BD5264A150F822A004C9099 /* Theme.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Theme.cpp; path = src/Theme.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5264B150F822A004C9099 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Theme.h; path = src/Theme.h; sourceTree = SOURCE_ROOT; };
+		5BD5264C150F822A004C9099 /* TimeListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeListener.h; path = src/TimeListener.h; sourceTree = SOURCE_ROOT; };
+		5BD5264D150F822A004C9099 /* VerticalLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VerticalLayout.cpp; path = src/VerticalLayout.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5264E150F822A004C9099 /* VerticalLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VerticalLayout.h; path = src/VerticalLayout.h; sourceTree = SOURCE_ROOT; };
+		5BD5266A150F8257004C9099 /* gameplay.dox */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = gameplay.dox; path = src/gameplay.dox; sourceTree = SOURCE_ROOT; };
+		5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCharacter.cpp; path = src/PhysicsCharacter.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5266C150F8257004C9099 /* PhysicsCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCharacter.h; path = src/PhysicsCharacter.h; sourceTree = SOURCE_ROOT; };
+		5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionObject.cpp; path = src/PhysicsCollisionObject.cpp; sourceTree = SOURCE_ROOT; };
+		5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionObject.h; path = src/PhysicsCollisionObject.h; sourceTree = SOURCE_ROOT; };
 		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 */
 
@@ -548,6 +642,7 @@
 		4234D98A14686BB6003031B3 = {
 			isa = PBXGroup;
 			children = (
+				5BC4E7D4150F8C3C00CBE1C0 /* res */,
 				4234D9A314686C52003031B3 /* src */,
 				427D4F42147DC8DE0076760E /* Libraries */,
 				42CCD4AF146D811D00353661 /* Frameworks */,
@@ -567,8 +662,7 @@
 		4234D9A314686C52003031B3 /* src */ = {
 			isa = PBXGroup;
 			children = (
-				5B43D19714C35347008A5D9D /* gameplay */,
-				5B43D19614C35344008A5D9D /* platform */,
+				5B43D19714C35347008A5D9D /* GamePlay */,
 			);
 			name = src;
 			path = gameplay;
@@ -623,28 +717,11 @@
 			name = "Mac OS X";
 			sourceTree = "<group>";
 		};
-		5B43D19614C35344008A5D9D /* platform */ = {
+		5B43D19714C35347008A5D9D /* GamePlay */ = {
 			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 = (
-				5BB0823C14C6FEC40019975F /* Mouse.h */,
+				5BD52634150F822A004C9099 /* AbsoluteLayout.cpp */,
+				5BD52635150F822A004C9099 /* AbsoluteLayout.h */,
 				42CD0DB1147D8FF50000361E /* Animation.cpp */,
 				42CD0DB2147D8FF50000361E /* Animation.h */,
 				42CD0DB3147D8FF50000361E /* AnimationClip.cpp */,
@@ -670,8 +747,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 */,
@@ -683,8 +768,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 */,
@@ -692,13 +780,22 @@
 				42CD0DDC147D8FF50000361E /* Game.cpp */,
 				42CD0DDD147D8FF50000361E /* Game.h */,
 				42C932AF14919FD10098216A /* Game.inl */,
+				5BD5266A150F8257004C9099 /* gameplay.dox */,
 				42CD0DE1147D8FF50000361E /* gameplay.h */,
+				5BB0823814C6FEB10019975F /* gameplay-main-android.cpp */,
+				42CD0DE0147D8FF50000361E /* gameplay-main-win32.cpp */,
+				42CD0DDE147D8FF50000361E /* gameplay-main-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 */,
@@ -719,6 +816,7 @@
 				42CD0DF4147D8FF50000361E /* MeshSkin.h */,
 				42CD0DF5147D8FF50000361E /* Model.cpp */,
 				42CD0DF6147D8FF50000361E /* Model.h */,
+				5BB0823C14C6FEC40019975F /* Mouse.h */,
 				42CD0DF7147D8FF50000361E /* Node.cpp */,
 				42CD0DF8147D8FF50000361E /* Node.h */,
 				42CD0DF9147D8FF50000361E /* Package.cpp */,
@@ -727,6 +825,13 @@
 				42CD0DFC147D8FF50000361E /* ParticleEmitter.h */,
 				42CD0DFD147D8FF50000361E /* Pass.cpp */,
 				42CD0DFE147D8FF50000361E /* Pass.h */,
+				42CD0E16147D8FF50000361E /* Plane.cpp */,
+				42CD0E17147D8FF50000361E /* Plane.h */,
+				42CD0E18147D8FF50000361E /* Plane.inl */,
+				5BD5266B150F8257004C9099 /* PhysicsCharacter.cpp */,
+				5BD5266C150F8257004C9099 /* PhysicsCharacter.h */,
+				5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */,
+				5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */,
 				42CD0DFF147D8FF50000361E /* PhysicsConstraint.cpp */,
 				42CD0E00147D8FF50000361E /* PhysicsConstraint.h */,
 				42CD0E01147D8FF50000361E /* PhysicsConstraint.inl */,
@@ -750,14 +855,19 @@
 				42CD0E13147D8FF50000361E /* PhysicsSpringConstraint.cpp */,
 				42CD0E14147D8FF50000361E /* PhysicsSpringConstraint.h */,
 				42CD0E15147D8FF50000361E /* PhysicsSpringConstraint.inl */,
-				42CD0E16147D8FF50000361E /* Plane.cpp */,
-				42CD0E17147D8FF50000361E /* Plane.h */,
-				42CD0E18147D8FF50000361E /* Plane.inl */,
+				42CD0E19147D8FF50000361E /* Platform.h */,
+				5BB0823914C6FEB10019975F /* PlatformAndroid.cpp */,
+				42CD0E1C147D8FF50000361E /* PlatformWin32.cpp */,
+				42CD0E1A147D8FF50000361E /* 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 */,
@@ -773,12 +883,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 */,
@@ -795,10 +912,12 @@
 				42CD0E41147D8FF50000361E /* VertexAttributeBinding.h */,
 				42CD0E42147D8FF50000361E /* VertexFormat.cpp */,
 				42CD0E43147D8FF50000361E /* VertexFormat.h */,
+				5BD5264D150F822A004C9099 /* VerticalLayout.cpp */,
+				5BD5264E150F822A004C9099 /* VerticalLayout.h */,
 				42CD0E44147D8FF50000361E /* Viewport.cpp */,
 				42CD0E45147D8FF50000361E /* Viewport.h */,
 			);
-			name = gameplay;
+			name = GamePlay;
 			sourceTree = "<group>";
 		};
 		5B5ADCE014C22DBE00AC6109 /* iOS */ = {
@@ -901,6 +1020,23 @@
 				4208DEEE14A407D500D3C511 /* Touch.h in Headers */,
 				4201819114A41B18008C3F56 /* MeshBatch.h in Headers */,
 				5BB0823D14C6FEC40019975F /* Mouse.h in Headers */,
+				5BD52650150F822A004C9099 /* AbsoluteLayout.h in Headers */,
+				5BD52652150F822A004C9099 /* Button.h in Headers */,
+				5BD52654150F822A004C9099 /* CheckBox.h in Headers */,
+				5BD52656150F822A004C9099 /* Container.h in Headers */,
+				5BD52658150F822A004C9099 /* Control.h in Headers */,
+				5BD52659150F822A004C9099 /* FlowLayout.h in Headers */,
+				5BD5265B150F822A004C9099 /* Form.h in Headers */,
+				5BD5265D150F822A004C9099 /* Label.h in Headers */,
+				5BD5265E150F822A004C9099 /* Layout.h in Headers */,
+				5BD52660150F822A004C9099 /* RadioButton.h in Headers */,
+				5BD52662150F822A004C9099 /* Slider.h in Headers */,
+				5BD52664150F822A004C9099 /* TextBox.h in Headers */,
+				5BD52666150F822A004C9099 /* Theme.h in Headers */,
+				5BD52667150F822A004C9099 /* TimeListener.h in Headers */,
+				5BD52669150F822A004C9099 /* VerticalLayout.h in Headers */,
+				5BD52671150F8258004C9099 /* PhysicsCharacter.h in Headers */,
+				5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -979,6 +1115,22 @@
 				5B04C5C514BFCFE100EB0071 /* Touch.h in Headers */,
 				5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */,
 				5BB0823E14C6FEC40019975F /* Mouse.h in Headers */,
+				5BD52672150F8258004C9099 /* PhysicsCharacter.h in Headers */,
+				5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */,
+				5BC4E740150F843D00CBE1C0 /* AbsoluteLayout.h in Headers */,
+				5BC4E742150F843D00CBE1C0 /* Button.h in Headers */,
+				5BC4E744150F843D00CBE1C0 /* CheckBox.h in Headers */,
+				5BC4E746150F843D00CBE1C0 /* Container.h in Headers */,
+				5BC4E748150F843D00CBE1C0 /* Control.h in Headers */,
+				5BC4E749150F843D00CBE1C0 /* FlowLayout.h in Headers */,
+				5BC4E74B150F843D00CBE1C0 /* Form.h in Headers */,
+				5BC4E74D150F843D00CBE1C0 /* Label.h in Headers */,
+				5BC4E74E150F843D00CBE1C0 /* Layout.h in Headers */,
+				5BC4E750150F843D00CBE1C0 /* RadioButton.h in Headers */,
+				5BC4E752150F843D00CBE1C0 /* Slider.h in Headers */,
+				5BC4E754150F843D00CBE1C0 /* TextBox.h in Headers */,
+				5BC4E756150F843D00CBE1C0 /* Theme.h in Headers */,
+				5BC4E758150F843D00CBE1C0 /* VerticalLayout.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1117,6 +1269,20 @@
 				428390991489D6E800E2B2F5 /* SceneLoader.cpp in Sources */,
 				4208DEE914A4079F00D3C511 /* Image.cpp in Sources */,
 				4201819014A41B18008C3F56 /* MeshBatch.cpp in Sources */,
+				5BD5264F150F822A004C9099 /* AbsoluteLayout.cpp in Sources */,
+				5BD52651150F822A004C9099 /* Button.cpp in Sources */,
+				5BD52653150F822A004C9099 /* CheckBox.cpp in Sources */,
+				5BD52655150F822A004C9099 /* Container.cpp in Sources */,
+				5BD52657150F822A004C9099 /* Control.cpp in Sources */,
+				5BD5265A150F822A004C9099 /* Form.cpp in Sources */,
+				5BD5265C150F822A004C9099 /* Label.cpp in Sources */,
+				5BD5265F150F822A004C9099 /* RadioButton.cpp in Sources */,
+				5BD52661150F822A004C9099 /* Slider.cpp in Sources */,
+				5BD52663150F822A004C9099 /* TextBox.cpp in Sources */,
+				5BD52665150F822A004C9099 /* Theme.cpp in Sources */,
+				5BD52668150F822A004C9099 /* VerticalLayout.cpp in Sources */,
+				5BD5266F150F8258004C9099 /* PhysicsCharacter.cpp in Sources */,
+				5BD52673150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1191,6 +1357,20 @@
 				5B04C57314BFCFE100EB0071 /* MeshBatch.cpp in Sources */,
 				5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */,
 				5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */,
+				5BD52670150F8258004C9099 /* PhysicsCharacter.cpp in Sources */,
+				5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */,
+				5BC4E73F150F843D00CBE1C0 /* AbsoluteLayout.cpp in Sources */,
+				5BC4E741150F843D00CBE1C0 /* Button.cpp in Sources */,
+				5BC4E743150F843D00CBE1C0 /* CheckBox.cpp in Sources */,
+				5BC4E745150F843D00CBE1C0 /* Container.cpp in Sources */,
+				5BC4E747150F843D00CBE1C0 /* Control.cpp in Sources */,
+				5BC4E74A150F843D00CBE1C0 /* Form.cpp in Sources */,
+				5BC4E74C150F843D00CBE1C0 /* Label.cpp in Sources */,
+				5BC4E74F150F843D00CBE1C0 /* RadioButton.cpp in Sources */,
+				5BC4E751150F843D00CBE1C0 /* Slider.cpp in Sources */,
+				5BC4E753150F843D00CBE1C0 /* TextBox.cpp in Sources */,
+				5BC4E755150F843D00CBE1C0 /* Theme.cpp in Sources */,
+				5BC4E757150F843D00CBE1C0 /* VerticalLayout.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

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

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

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

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

+ 2 - 2
gameplay/res/shaders/colored-specular.fsh

@@ -29,7 +29,7 @@ void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, floa
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-	float ddot = abs(dot(normalVector, lightDirection));
+    float ddot = abs(dot(normalVector, lightDirection));
     float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
@@ -122,4 +122,4 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-}
+}

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

@@ -21,7 +21,7 @@ void lighting(vec3 normalVector, vec3 lightDirection, float attenuation)
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-	float ddot = dot(normalVector, lightDirection);
+    float ddot = dot(normalVector, lightDirection);
     float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;

+ 2 - 2
gameplay/res/shaders/diffuse-specular.fsh

@@ -25,7 +25,7 @@ void lighting(vec3 normalVector, vec3 cameraDirection, vec3 lightDirection, floa
     _ambientColor = _baseColor.rgb * u_ambientColor;
 
     // Diffuse
-	float ddot = dot(normalVector, lightDirection);
+    float ddot = dot(normalVector, lightDirection);
     float diffuseIntensity = attenuation * ddot;
     diffuseIntensity = max(0.0, diffuseIntensity);
     _diffuseColor = u_lightColor * _baseColor.rgb * diffuseIntensity;
@@ -114,4 +114,4 @@ void main()
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.rgb = _ambientColor + _diffuseColor + _specularColor;
-}
+}

+ 5 - 3
gameplay/src/Base.h

@@ -201,11 +201,12 @@ extern void printError(const char* format, ...);
     extern PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
     #define glClearDepth glClearDepthf
     #define OPENGL_ES
+    #define OPENGL_ES_PVR    
 #elif WIN32
     #define WIN32_LEAN_AND_MEAN
-	#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG                      0x8C00
-	#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG                      0x8C01
-	#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG                     0x8C02
+	#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG                      0x8C00
+	#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG                      0x8C01
+	#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG                     0x8C02
 	#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG                     0x8C03
     #include <GL/glew.h>
 #elif __APPLE__
@@ -219,6 +220,7 @@ extern void printError(const char* format, ...);
         #define glIsVertexArray glIsVertexArrayOES
         #define glClearDepth glClearDepthf
         #define OPENGL_ES
+        #define OPENGL_ES_PVR    
     #elif TARGET_OS_MAC
         #include <OpenGL/gl.h>
         #include <OpenGL/glext.h>

+ 2 - 2
gameplay/src/Game.cpp

@@ -293,9 +293,9 @@ void Game::updateOnce()
 
 void Game::fireTimeEvents(long frameTime)
 {
-    while (!_timeEvents.empty())
+    while (_timeEvents.size() > 0)
     {
-        TimeEvent* timeEvent = &_timeEvents.top();
+        const TimeEvent* timeEvent = &_timeEvents.top();
         if (timeEvent->time > frameTime)
         {
             break;

+ 1 - 1
gameplay/src/Game.h

@@ -383,7 +383,7 @@ private:
     AnimationController* _animationController;  // Controls the scheduling and running of animations.
     AudioController* _audioController;          // Controls audio sources that are playing in the game.
     PhysicsController* _physicsController;      // Controls the simulation of a physics scene and entities.
-    std::priority_queue<TimeEvent> _timeEvents; // Contains the scheduled time events.
+    std::priority_queue<TimeEvent, std::vector<TimeEvent>, std::less<TimeEvent> > _timeEvents; // Contains the scheduled time events.
 };
 
 }

+ 1 - 1
gameplay/src/Node.cpp

@@ -757,7 +757,7 @@ PhysicsRigidBody* Node::getRigidBody() const
     return _physicsRigidBody;
 }
 
-void Node::setRigidBody(PhysicsRigidBody::Type type, float mass, float friction,
+void Node::setRigidBody(PhysicsRigidBody::ShapeType type, float mass, float friction,
         float restitution, float linearDamping, float angularDamping)
 {
     SAFE_DELETE(_physicsRigidBody);

+ 1 - 1
gameplay/src/Node.h

@@ -387,7 +387,7 @@ public:
      * @param linearDamping The percentage of linear velocity lost per second (between 0.0 and 1.0).
      * @param angularDamping The percentage of angular velocity lost per second (between 0.0 and 1.0).
      */
-    void setRigidBody(PhysicsRigidBody::Type type, float mass = 0.0f, float friction = 0.5f,
+    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);
 
     /**

+ 99 - 47
gameplay/src/PhysicsCharacter.cpp

@@ -10,6 +10,16 @@
 #include "Game.h"
 #include "PhysicsController.h"
 
+// Amount to walk collision normal when attempting to repair a collision.
+// To small a value will result in inefficient collision repairs (several iterations
+// to fix a collision and slow resolution), whereas larger values will result
+// in less accurate collision resolution.
+//#define COLLISION_REPAIR_INCREMENT 0.2f
+#define COLLISION_REPAIR_MARGIN 1.0f
+
+// Maximum number of iterations used to perform perform collision repair each update.
+#define COLLISION_REPAIR_MAX_ITERATIONS 4
+
 namespace gameplay
 {
 
@@ -58,7 +68,7 @@ PhysicsCharacter::PhysicsCharacter(Node* node, float radius, float height, const
     _fallVelocity(0, 0, 0), _currentVelocity(0,0,0), _normalizedVelocity(0,0,0),
     _colliding(false), _collisionNormal(0,0,0), _currentPosition(0,0,0),
     _ghostObject(NULL), _collisionShape(NULL), _ignoreTransformChanged(0),
-    _stepHeight(0.2f), _slopeAngle(0.0f), _cosSlopeAngle(0.0f)
+    _stepHeight(0.2f), _slopeAngle(0.0f), _cosSlopeAngle(0.0f), _physicsEnabled(true)
 {
     setMaxSlopeAngle(45.0f);
 
@@ -76,38 +86,64 @@ PhysicsCharacter::PhysicsCharacter(Node* node, float radius, float height, const
     // Set initial transform
     _motionState->getWorldTransform(_ghostObject->getWorldTransform());
 
-    // Create a capsule collision shape
-    _collisionShape = bullet_new<btCapsuleShape>((btScalar)radius, (btScalar)(height - radius*2));
+    PhysicsController* pc = Game::getInstance()->getPhysicsController();
+
+    // Create a capsule collision shape (this is automatically deleted by PhysicsController when our collision object is removed)
+    _collisionShape = static_cast<btConvexShape*>(pc->createCapsule(radius, height - radius*2.0f));
 
     // Set the collision shape on the ghost object (get it from the node's rigid body)
     _ghostObject->setCollisionShape(_collisionShape);
     _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
 
-    btDynamicsWorld* world = Game::getInstance()->getPhysicsController()->_world;
-    
-    // Register the ghost object for collisions with the world.
-    // For now specify static flag only, so character does not interact with dynamic objects
-    world->addCollisionObject(_ghostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter);
+    // Add the collision object to the physics system
+    pc->addCollisionObject(this);
 
     // Register ourselves as an action on the physics world so we are called back during physics ticks
-    world->addAction(this);
+    pc->_world->addAction(this);
 }
 
 PhysicsCharacter::~PhysicsCharacter()
 {
-    // Unregister ourself with world
-    btDynamicsWorld* world = Game::getInstance()->getPhysicsController()->_world;
-    world->removeCollisionObject(_ghostObject);
-    world->removeAction(this);
+    // Remove ourself from physics system
+    PhysicsController* pc = Game::getInstance()->getPhysicsController();
+
+    pc->removeCollisionObject(this);
+
+    // Unregister ourselves as action from world
+    pc->_world->removeAction(this);
 
     SAFE_DELETE(_ghostObject);
-    SAFE_DELETE(_collisionShape);
 
     _node->removeListener(this);
     SAFE_RELEASE(_node);
     SAFE_DELETE(_motionState);
 }
 
+PhysicsCollisionObject::Type PhysicsCharacter::getType() const
+{
+    return PhysicsCollisionObject::CHARACTER;
+}
+
+btCollisionObject* PhysicsCharacter::getCollisionObject() const
+{
+    return _ghostObject;
+}
+
+bool PhysicsCharacter::isPhysicsEnabled() const
+{
+    return _physicsEnabled;
+}
+
+void PhysicsCharacter::setPhysicsEnabled(bool enabled)
+{
+    _physicsEnabled = enabled;
+}
+
+btCollisionShape* PhysicsCharacter::getCollisionShape() const
+{
+    return _collisionShape;
+}
+
 Node* PhysicsCharacter::getNode() const
 {
     return _node;
@@ -354,32 +390,40 @@ void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar d
     // the following steps (movement) start from a clean slate, where the character
     // is not colliding with anything. Also, this step handles collision between
     // dynamic objects (i.e. objects that moved and now intersect the character).
-    _colliding = false;
-    int stepCount = 0;
-	while (fixCollision(collisionWorld))
-	{
-        _colliding = true;
-
-        // After a small number of attempts to fix a collision/penetration, give up...
-        if (++stepCount > 4)
-		{
-            WARN_VARG("Character '%s' could not recover from collision.", _node->getId());
-			break;
-		}
-	}
+    if (_physicsEnabled)
+    {
+        _colliding = fixCollision(collisionWorld);
+        /*_colliding = false;
+        int stepCount = 0;
+	    while (fixCollision(collisionWorld))
+	    {
+            _colliding = true;
+
+            // After a small number of attempts to fix a collision/penetration, give up.
+            // This hanldes the case where we are deeply penetrating some object and attempting
+            // to step out of it (by COLLISION_REPAIR_INCREMENT units) does not fix the collision.
+            if (++stepCount > COLLISION_REPAIR_MAX_ITERATIONS)
+		    {
+                WARN_VARG("Character '%s' could not recover from collision.", _node->getId());
+			    break;
+		    }
+	    }*/
+    }
 
     // Update current and target world positions
     btTransform transform = _ghostObject->getWorldTransform();
     _currentPosition = transform.getOrigin();
 
     // Process movement in the up direction
-    stepUp(collisionWorld, deltaTimeStep);
+    if (_physicsEnabled)
+        stepUp(collisionWorld, deltaTimeStep);
 
     // Process horizontal movement
     stepForwardAndStrafe(collisionWorld, deltaTimeStep);
 
     // Process movement in the down direction
-    stepDown(collisionWorld, deltaTimeStep);
+    if (_physicsEnabled)
+        stepDown(collisionWorld, deltaTimeStep);
 
     // Set new position
     transform.setOrigin(_currentPosition);
@@ -440,12 +484,6 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
 
     updateCurrentVelocity();
 
-    if (_currentVelocity.isZero())
-    {
-        // No velocity, so we aren't moving
-        return;
-    }
-
     // Calculate final velocity
     btVector3 velocity(_currentVelocity);
     if (animationCount > 0)
@@ -454,9 +492,22 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
     }
     velocity *= time; // since velocity is in meters per second
 
+    if (velocity.isZero())
+    {
+        // No velocity, so we aren't moving
+        return;
+    }
+
     // Translate the target position by the velocity vector (already scaled by t)
     btVector3 targetPosition = _currentPosition + velocity;
 
+    // If physics is disabled, simply update current position without checking collisions
+    if (!_physicsEnabled)
+    {
+        _currentPosition = targetPosition;
+        return;
+    }
+
     // Check for collisions by performing a bullet convex sweep test
     btTransform start, end;
 	start.setIdentity();
@@ -593,7 +644,7 @@ btVector3 perpindicularComponent(const btVector3& direction, const btVector3& no
 void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPosition, const btVector3& collisionNormal)
 {
     //btScalar tangentMag = 0.0;
-    btScalar normalMag = 1.0;
+    //btScalar normalMag = 1.0;
 
 	btVector3 movementDirection = targetPosition - _currentPosition;
 	btScalar movementLength = movementDirection.length();
@@ -605,10 +656,8 @@ void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPositi
 		btVector3 reflectDir = computeReflectionDirection(movementDirection, collisionNormal);
 		reflectDir.normalize();
 
-		btVector3 parallelDir, perpindicularDir;
-
-		parallelDir = parallelComponent(reflectDir, collisionNormal);
-		perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
+		//btVector3 parallelDir = parallelComponent(reflectDir, collisionNormal);
+		btVector3 perpindicularDir = perpindicularComponent(reflectDir, collisionNormal);
 
 		targetPosition = _currentPosition;
 		/*if (tangentMag != 0.0)
@@ -617,11 +666,11 @@ void PhysicsCharacter::updateTargetPositionFromCollision(btVector3& targetPositi
 			targetPosition +=  parComponent;
 		}*/
 
-		if (normalMag != 0.0)
-		{
-			btVector3 perpComponent = perpindicularDir * btScalar (normalMag * movementLength);
+		//if (normalMag != 0.0)
+		//{
+			btVector3 perpComponent = perpindicularDir * btScalar (/*normalMag **/ movementLength);
 			targetPosition += perpComponent;
-		}
+		//}
 	}
 }
 
@@ -654,8 +703,8 @@ bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
 		{
 			btPersistentManifold* manifold = _manifoldArray[j];
 
-            // Get the direction of the contact points (used to scale normal vector in the correct direction)
-			btScalar directionSign = manifold->getBody0() == _ghostObject ? btScalar(-1.0) : btScalar(1.0);
+            // Get the direction of the contact points (used to scale normal vector in the correct direction).
+            btScalar directionSign = manifold->getBody0() == _ghostObject ? -1.0f : 1.0f;
 
 			for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
 			{
@@ -666,6 +715,7 @@ bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
 
 				if (dist < 0.0)
 				{
+                    // A negative distance means the objects are overlapping
 					if (dist < maxPenetration)
 					{
                         // Store collision normal for this point
@@ -674,7 +724,9 @@ bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
 					}
 
                     // Calculate new position for object, which is translated back along the collision normal
-					currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
+                    btVector3 n(pt.m_normalWorldOnB);
+                    n.normalize();
+					currentPosition += /*pt.m_normalWorldOnB*/n * directionSign * dist * COLLISION_REPAIR_MARGIN;// + _collisionShape->getMargin());// * COLLISION_REPAIR_INCREMENT;
 					collision = true;
 				}
 			}

+ 48 - 3
gameplay/src/PhysicsCharacter.h

@@ -23,10 +23,8 @@ namespace gameplay
  * This class can also be used to control animations for a character. Animation
  * clips can be setup for typical character animations, such as walk, run, jump,
  * etc; and the controller will handle blending between these animations as needed.
- *
- * @todo Add support for collision listeners.
  */
-class PhysicsCharacter : public Transform::Listener, public btActionInterface
+class PhysicsCharacter : public PhysicsCollisionObject, public Transform::Listener, public btActionInterface
 {
     friend class PhysicsController;
 
@@ -53,13 +51,43 @@ public:
          ANIMATION_REPEAT
     };
 
+    /**
+     * @see PhysicsCollisionObject#getType
+     */
+    PhysicsCollisionObject::Type getType() const;
+
     /**
      * Returns the character node for this PhysicsCharacter.
      *
      * @return The character Node.
+     *
+     * @see PhysicsCollisionObject::getNode.
      */
     Node* getNode() const;
 
+    /**
+     * Returns whether physics simulation is enabled for the physics character.
+     *
+     * @return true if physics simulation is enabled, false otherwise.
+     *
+     * @see setPhysicsEnabled(bool)
+     */
+    bool isPhysicsEnabled() const;
+
+    /**
+     * Enables or disables phyiscs simulation for the character.
+     *
+     * When physics simulation is enabled (default), the physics character automatically
+     * responds to collisions in the physics world. For example, the character will
+     * automatically slide along walls, step up stairs, react to gravity, etc.
+     *
+     * When disabled, the character will not have any physics applied on it and will
+     * therefore be allowed to walk through walls, ceiling, floors, other objects, etc.
+     *
+     * @param enabled true to enable physics simulation, false otherwise.
+     */
+    void setPhysicsEnabled(bool enabled);
+
     /**
      * Returns the maximum step height for the character.
      *
@@ -247,6 +275,18 @@ public:
      */
 	void debugDraw(btIDebugDraw* debugDrawer);
 
+protected:
+
+    /**
+     * @see PhysicsCollisionObject::getCollisionObject
+     */
+    btCollisionObject* getCollisionObject() const;
+
+    /**
+     * @see PhysicsCollisionObject::getCollisionShape
+     */
+    btCollisionShape* getCollisionShape() const;
+
 private:
 
     struct CharacterAnimation
@@ -264,6 +304,8 @@ private:
     /**
      * Creates a new PhysicsCharacter.
      *
+     * Use PhysicsController::createCharacter to create physics characters.
+     *
      * @param node Scene node that represents the character.
      * @param radius Radius of capsule volume used for character collisions.
      * @param height Height of the capsule volume used for character collisions.
@@ -273,6 +315,8 @@ private:
 
     /**
      * Destructor.
+     *
+     * Use PhysicsController::destroyCharacter to destroy physics characters.
      */
     virtual ~PhysicsCharacter();
 
@@ -310,6 +354,7 @@ private:
     float _stepHeight;
     float _slopeAngle;
     float _cosSlopeAngle;
+    bool _physicsEnabled;
 };
 
 }

+ 66 - 0
gameplay/src/PhysicsCollisionObject.cpp

@@ -0,0 +1,66 @@
+#include "Base.h"
+#include "PhysicsCollisionObject.h"
+#include "PhysicsController.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+PhysicsCollisionObject::PhysicsCollisionObject()
+{
+}
+
+PhysicsCollisionObject::~PhysicsCollisionObject()
+{
+}
+
+void PhysicsCollisionObject::addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
+{
+    Game::getInstance()->getPhysicsController()->addCollisionListener(listener, this, object);
+}
+
+void PhysicsCollisionObject::removeCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
+{
+    Game::getInstance()->getPhysicsController()->removeCollisionListener(listener, this, object);
+}
+
+bool PhysicsCollisionObject::collidesWith(PhysicsCollisionObject* object) const
+{
+    static CollidesWithCallback callback;
+
+    callback.result = false;
+    Game::getInstance()->getPhysicsController()->_world->contactPairTest(getCollisionObject(), object->getCollisionObject(), callback);
+    return callback.result;
+}
+
+PhysicsCollisionObject::CollisionPair::CollisionPair(PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
+    : objectA(objectA), objectB(objectB)
+{
+    // unused
+}
+
+bool PhysicsCollisionObject::CollisionPair::operator < (const CollisionPair& collisionPair) const
+{
+    // If the pairs are equal, then return false.
+    if ((objectA == collisionPair.objectA && objectB == collisionPair.objectB) || (objectA == collisionPair.objectB && objectB == collisionPair.objectA))
+        return false;
+
+    // We choose to compare based on objectA arbitrarily.
+    if (objectA < collisionPair.objectA)
+        return true;
+
+    if (objectA == collisionPair.objectA)
+        return objectB < collisionPair.objectB;
+
+    return false;
+}
+
+btScalar PhysicsCollisionObject::CollidesWithCallback::addSingleResult(btManifoldPoint& cp,
+    const btCollisionObject* a, int partIdA, int indexA, 
+    const btCollisionObject* b, int partIdB, int indexB)
+{
+    result = true;
+    return 0.0f;
+}
+
+}

+ 188 - 0
gameplay/src/PhysicsCollisionObject.h

@@ -0,0 +1,188 @@
+#ifndef PHYSICSCOLLISIONOBJECT_H_
+#define PHYSICSCOLLISIONOBJECT_H_
+
+#include "Vector3.h"
+
+namespace gameplay
+{
+
+class Node;
+
+/**
+ * Base class for all gameplay physics objects that support collision events.
+ */
+class PhysicsCollisionObject
+{
+    friend class PhysicsController;
+
+public:
+
+    /**
+     * Enumeration of all possible collision object types.
+     */
+    enum Type
+    {
+        /**
+         * PhysicsRigidBody type.
+         */
+        RIGID_BODY,
+
+        /**
+         * PhysicsCharacter type.
+         */
+        CHARACTER
+    };
+
+    /** 
+     * Defines a pair of rigid bodies that collided (or may collide).
+     */
+    class CollisionPair
+    {
+    public:
+
+        /**
+         * Constructor.
+         */
+        CollisionPair(PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB);
+
+        /**
+         * Less than operator (needed for use as a key in map).
+         * 
+         * @param collisionPair The collision pair to compare.
+         * @return True if this pair is "less than" the given pair; false otherwise.
+         */
+        bool operator < (const CollisionPair& collisionPair) const;
+
+        /**
+         * The first object in the collision.
+         */
+        PhysicsCollisionObject* objectA;
+
+        /**
+         * The second object in the collision.
+         */
+        PhysicsCollisionObject* objectB;
+    };
+
+    /**
+     * Collision listener interface.
+     */
+    class CollisionListener
+    {
+        friend class PhysicsCollisionObject;
+        friend class PhysicsController;
+
+    public:
+
+        /**
+         * The type of collision event.
+         */
+        enum EventType
+        {
+            /**
+             * Event fired when the two rigid bodies start colliding.
+             */
+            COLLIDING,
+
+            /**
+             * Event fired when the two rigid bodies no longer collide.
+             */
+            NOT_COLLIDING
+        };
+
+        /**
+         * Virtual destructor.
+         */
+        virtual ~CollisionListener() { }
+
+        /**
+         * Called when a collision occurs between two objects in the physics world.
+         * 
+         * @param type The type of collision event.
+         * @param collisionPair The two collision objects involved in the collision.
+         * @param contactPointA The contact point with the first object (in world space).
+         * @param contactPointB The contact point with the second object (in world space).
+         */
+        virtual void collisionEvent(PhysicsCollisionObject::CollisionListener::EventType type,
+                                    const PhysicsCollisionObject::CollisionPair& collisionPair,
+                                    const Vector3& contactPointA = Vector3::zero(),
+                                    const Vector3& contactPointB = Vector3::zero()) = 0;
+    };
+
+    /**
+     * Returns the type of the collision object.
+     */
+    virtual PhysicsCollisionObject::Type getType() const = 0;
+
+    /**
+     * Returns the node associated with this collision object.
+     */
+    virtual Node* getNode() const = 0;
+
+    /**
+     * Adds a collision listener for this collision object.
+     * 
+     * @param listener The listener to add.
+     * @param object Optional collision object used to filter the collision event.
+     */
+    void addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object = NULL);
+
+    /**
+     * Removes a collision listener.
+     *
+     * @param listener The listener to remove.
+     */
+    void removeCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object = NULL);
+
+    /**
+     * Checks if this collision object collides with the given object.
+     * 
+     * @param object The collision object to test for collision with.
+     * 
+     * @return True if this object collides with the specified one; false otherwise.
+     */
+    bool collidesWith(PhysicsCollisionObject* object) const;
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    PhysicsCollisionObject();
+
+    /**
+     * Virtual destructor.
+     */
+    virtual ~PhysicsCollisionObject();
+
+    /**
+     * Returns the Bullet Physics collision object.
+     *
+     * @return The Bullet collision object.
+     */
+    virtual btCollisionObject* getCollisionObject() const = 0;
+
+    /**
+     * Returns the Bullet Physics collision shape.
+     *
+     * @return The Bullet collision shape.
+     */
+    virtual btCollisionShape* getCollisionShape() const = 0;
+
+private:
+
+    // Internal class used to implement the collidesWith(PhysicsRigidBody*) function.
+    struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
+    {
+        btScalar addSingleResult(btManifoldPoint& cp, 
+                                 const btCollisionObject* a, int partIdA, int indexA, 
+                                 const btCollisionObject* b, int partIdB, int indexB);
+
+        bool result;
+    };
+
+};
+
+}
+
+#endif

+ 109 - 88
gameplay/src/PhysicsController.cpp

@@ -142,7 +142,7 @@ void PhysicsController::drawDebug(const Matrix& viewProjection)
     _debugDrawer->end();
 }
 
-PhysicsRigidBody* PhysicsController::rayTest(const Ray& ray, float distance, Vector3* hitPoint, float* hitFraction)
+PhysicsCollisionObject* PhysicsController::rayTest(const Ray& ray, float distance, Vector3* hitPoint, float* hitFraction)
 {
     btCollisionWorld::ClosestRayResultCallback callback(BV(ray.getOrigin()), BV(distance * ray.getDirection()));
     _world->rayTest(BV(ray.getOrigin()), BV(distance * ray.getDirection()), callback);
@@ -154,7 +154,7 @@ PhysicsRigidBody* PhysicsController::rayTest(const Ray& ray, float distance, Vec
         if (hitFraction)
             *hitFraction = callback.m_closestHitFraction;
 
-        return getRigidBody(callback.m_collisionObject);
+        return getCollisionObject(callback.m_collisionObject);
     }
 
     return NULL;
@@ -164,65 +164,57 @@ btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisi
     const btCollisionObject* b, int partIdB, int indexB)
 {
     // Get pointers to the PhysicsRigidBody objects.
-    PhysicsRigidBody* rbA = Game::getInstance()->getPhysicsController()->getRigidBody(a);
-    PhysicsRigidBody* rbB = Game::getInstance()->getPhysicsController()->getRigidBody(b);
-    
+    PhysicsCollisionObject* rbA = Game::getInstance()->getPhysicsController()->getCollisionObject(a);
+    PhysicsCollisionObject* rbB = Game::getInstance()->getPhysicsController()->getCollisionObject(b);
+
     // If the given rigid body pair has collided in the past, then
     // we notify the listeners only if the pair was not colliding
     // during the previous frame. Otherwise, it's a new pair, so add a
     // new entry to the cache with the appropriate listeners and notify them.
     PhysicsRigidBody::CollisionPair pair(rbA, rbB);
+
+    CollisionInfo* collisionInfo;
     if (_collisionStatus.count(pair) > 0)
     {
-        const CollisionInfo& collisionInfo = _collisionStatus[pair];
-        if ((collisionInfo._status & COLLISION) == 0)
-        {
-            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = collisionInfo._listeners.begin();
-            for (; iter != collisionInfo._listeners.end(); iter++)
-            {
-                if ((collisionInfo._status & REMOVE) == 0)
-                {
-                    (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
-                        Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
-                }
-            }
-        }
+        collisionInfo = &_collisionStatus[pair];
     }
     else
     {
-        CollisionInfo& collisionInfo = _collisionStatus[pair];
-
-        // Initialized the status for the new entry.
-        collisionInfo._status = 0;
+        // Add a new collision pair for these objects
+        collisionInfo = &_collisionStatus[pair];
 
         // Add the appropriate listeners.
-        PhysicsRigidBody::CollisionPair p1(pair.rigidBodyA, NULL);
+        PhysicsRigidBody::CollisionPair p1(pair.objectA, NULL);
         if (_collisionStatus.count(p1) > 0)
         {
             const CollisionInfo& ci = _collisionStatus[p1];
-            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = ci._listeners.begin();
+            std::vector<PhysicsCollisionObject::CollisionListener*>::const_iterator iter = ci._listeners.begin();
             for (; iter != ci._listeners.end(); iter++)
             {
-                collisionInfo._listeners.push_back(*iter);
+                collisionInfo->_listeners.push_back(*iter);
             }
         }
-        PhysicsRigidBody::CollisionPair p2(pair.rigidBodyB, NULL);
+        PhysicsRigidBody::CollisionPair p2(pair.objectB, NULL);
         if (_collisionStatus.count(p2) > 0)
         {
             const CollisionInfo& ci = _collisionStatus[p2];
-            std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = ci._listeners.begin();
+            std::vector<PhysicsCollisionObject::CollisionListener*>::const_iterator iter = ci._listeners.begin();
             for (; iter != ci._listeners.end(); iter++)
             {
-                collisionInfo._listeners.push_back(*iter);
+                collisionInfo->_listeners.push_back(*iter);
             }
         }
+    }
 
-        std::vector<PhysicsRigidBody::Listener*>::iterator iter = collisionInfo._listeners.begin();
-        for (; iter != collisionInfo._listeners.end(); iter++)
+    // Fire collision event
+    if ((collisionInfo->_status & COLLISION) == 0)
+    {
+        std::vector<PhysicsCollisionObject::CollisionListener*>::const_iterator iter = collisionInfo->_listeners.begin();
+        for (; iter != collisionInfo->_listeners.end(); iter++)
         {
-            if ((collisionInfo._status & REMOVE) == 0)
+            if ((collisionInfo->_status & REMOVE) == 0)
             {
-                (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                (*iter)->collisionEvent(PhysicsCollisionObject::CollisionListener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
                     Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
             }
         }
@@ -231,8 +223,8 @@ btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisi
     // Update the collision status cache (we remove the dirty bit
     // set in the controller's update so that this particular collision pair's
     // status is not reset to 'no collision' when the controller's update completes).
-    _collisionStatus[pair]._status &= ~DIRTY;
-    _collisionStatus[pair]._status |= COLLISION;
+    collisionInfo->_status &= ~DIRTY;
+    collisionInfo->_status |= COLLISION;
     return 0.0f;
 }
 
@@ -326,7 +318,6 @@ void PhysicsController::update(long elapsedTime)
                 (*_listeners)[k]->statusEvent(_status);
             }
         }
-        
     }
 
     // All statuses are set with the DIRTY bit before collision processing occurs.
@@ -362,10 +353,10 @@ void PhysicsController::update(long elapsedTime)
         // of collision pairs in the status cache that we did not explicitly register for.)
         if ((iter->second._status & REGISTERED) != 0 && (iter->second._status & REMOVE) == 0)
         {
-            if (iter->first.rigidBodyB)
-                _world->contactPairTest(iter->first.rigidBodyA->_body, iter->first.rigidBodyB->_body, *this);
+            if (iter->first.objectB)
+                _world->contactPairTest(iter->first.objectA->getCollisionObject(), iter->first.objectB->getCollisionObject(), *this);
             else
-                _world->contactTest(iter->first.rigidBodyA->_body, *this);
+                _world->contactTest(iter->first.objectA->getCollisionObject(), *this);
         }
     }
 
@@ -375,12 +366,12 @@ void PhysicsController::update(long elapsedTime)
     {
         if ((iter->second._status & DIRTY) != 0)
         {
-            if ((iter->second._status & COLLISION) != 0 && iter->first.rigidBodyB)
+            if ((iter->second._status & COLLISION) != 0 && iter->first.objectB)
             {
                 unsigned int size = iter->second._listeners.size();
                 for (unsigned int i = 0; i < size; i++)
                 {
-                    iter->second._listeners[i]->collisionEvent(PhysicsRigidBody::Listener::NOT_COLLIDING, iter->first);
+                    iter->second._listeners[i]->collisionEvent(PhysicsCollisionObject::CollisionListener::NOT_COLLIDING, iter->first);
                 }
             }
 
@@ -389,85 +380,103 @@ void PhysicsController::update(long elapsedTime)
     }
 }
 
-void PhysicsController::addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
+void PhysicsController::addCollisionListener(PhysicsCollisionObject::CollisionListener* listener, PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
 {
-    PhysicsRigidBody::CollisionPair pair(rbA, rbB);
-
-    // Make sure the status of the entry is initialized properly.
-    if (_collisionStatus.count(pair) == 0)
-        _collisionStatus[pair]._status = 0;
+    PhysicsCollisionObject::CollisionPair pair(objectA, objectB);
 
     // Add the listener and ensure the status includes that this collision pair is registered.
-    _collisionStatus[pair]._listeners.push_back(listener);
-    if ((_collisionStatus[pair]._status & PhysicsController::REGISTERED) == 0)
-        _collisionStatus[pair]._status |= PhysicsController::REGISTERED;
+    CollisionInfo& info = _collisionStatus[pair];
+    info._listeners.push_back(listener);
+    info._status |= PhysicsController::REGISTERED;
 }
 
-void PhysicsController::addRigidBody(PhysicsRigidBody* body)
+void PhysicsController::removeCollisionListener(PhysicsCollisionObject::CollisionListener* listener, PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
 {
-    _world->addRigidBody(body->_body);
-    _bodies.push_back(body);
+    // Mark the collision pair for these objects for removal
+    PhysicsCollisionObject::CollisionPair pair(objectA, objectB);
+    if (_collisionStatus.count(pair) > 0)
+    {
+        _collisionStatus[pair]._status |= REMOVE;
+    }
 }
-    
-void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
+
+void PhysicsController::addCollisionObject(PhysicsCollisionObject* object)
 {
-    // Find the rigid body and remove it from the world.
-    for (int i = _world->getNumCollisionObjects() - 1; i >= 0 ; i--)
+    // Assign user pointer for the bullet collision object to allow efficient
+    // lookups of bullet objects -> gameplay objects.
+    object->getCollisionObject()->setUserPointer(object);
+
+    // Add the object to the physics world
+    switch (object->getType())
     {
-        btCollisionObject* obj = _world->getCollisionObjectArray()[i];
-        if (rigidBody->_body == obj)
-        {
-            _world->removeCollisionObject(obj);
-            break;
-        }
+    case PhysicsCollisionObject::RIGID_BODY:
+        _world->addRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()));
+        break;
+
+    case PhysicsCollisionObject::CHARACTER:
+        _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::DefaultFilter);
+        break;
+
+    default:
+        assert(0); // unexpected (new type?)
+        break;
     }
+}
 
-    // Find the rigid body's collision shape and release the rigid body's reference to it.
-    for (unsigned int i = 0; i < _shapes.size(); i++)
+void PhysicsController::removeCollisionObject(PhysicsCollisionObject* object)
+{
+    // Remove the collision object from the world
+    if (object->getCollisionObject())
     {
-        if (_shapes[i]->_shape == rigidBody->_shape)
+        switch (object->getType())
         {
-            if (_shapes[i]->getRefCount() == 1)
-            {
-                _shapes[i]->release();
-                _shapes.erase(_shapes.begin() + i);
-            }
-            else
-                _shapes[i]->release();
+        case PhysicsCollisionObject::RIGID_BODY:
+            _world->removeRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()));
+            break;
 
+        case PhysicsCollisionObject::CHARACTER:
+            _world->removeCollisionObject(object->getCollisionObject());
+            break;
+
+        default:
+            assert(0); // unexpected (new type?)
             break;
         }
     }
 
-    // Remove the rigid body from the controller's list.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
+    // Release collision shape
+    if (object->getCollisionShape())
     {
-        if (_bodies[i] == rigidBody)
+        PhysicsCollisionShape* shape = reinterpret_cast<PhysicsCollisionShape*>(object->getCollisionShape()->getUserPointer());
+        if (shape)
         {
-            _bodies.erase(_bodies.begin() + i);
-            break;
+            if (shape->getRefCount() == 1)
+            {
+                std::vector<PhysicsCollisionShape*>::iterator shapeItr = std::find(_shapes.begin(), _shapes.end(), shape);
+                shape->release();
+                if (shapeItr != _shapes.end())
+                    _shapes.erase(shapeItr);
+            }
+            else
+            {
+                shape->release();
+            }
         }
     }
 
-    // Find all references to the rigid body in the collision status cache and mark them for removal.
+    // Find all references to the object in the collision status cache and mark them for removal.
     std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
     for (; iter != _collisionStatus.end(); iter++)
     {
-        if (iter->first.rigidBodyA == rigidBody || iter->first.rigidBodyB == rigidBody)
+        if (iter->first.objectA == object || iter->first.objectB == object)
             iter->second._status |= REMOVE;
     }
 }
 
-PhysicsRigidBody* PhysicsController::getRigidBody(const btCollisionObject* collisionObject)
+PhysicsCollisionObject* PhysicsController::getCollisionObject(const btCollisionObject* collisionObject) const
 {
-    // Find the rigid body and remove it from the world.
-    for (unsigned int i = 0; i < _bodies.size(); i++)
-    {
-        if (_bodies[i]->_body == collisionObject)
-            return _bodies[i];
-    }
-    
-    return NULL;
+    // Gameplay rigid bodies are stored in the userPointer data of bullet collision objects
+    return reinterpret_cast<PhysicsCollisionObject*>(collisionObject->getUserPointer());
 }
 
 btCollisionShape* PhysicsController::createBox(const Vector3& min, const Vector3& max, const Vector3& scale)
@@ -846,4 +855,16 @@ int	PhysicsController::DebugDrawer::getDebugMode() const
     return _mode;
 }
 
+PhysicsController::PhysicsCollisionShape::PhysicsCollisionShape(btCollisionShape* shape)
+    : _shape(shape)
+{
+    // Assign user pointer to allow efficient lookup of PhysicsCollisionShape from bullet object
+    shape->setUserPointer(this);
+}
+
+PhysicsController::PhysicsCollisionShape::~PhysicsCollisionShape()
+{
+    SAFE_DELETE(_shape);
+}
+
 }

+ 20 - 14
gameplay/src/PhysicsController.h

@@ -22,6 +22,7 @@ class PhysicsController : public btCollisionWorld::ContactResultCallback
     friend class PhysicsConstraint;
     friend class PhysicsRigidBody;
     friend class PhysicsCharacter;
+    friend class PhysicsCollisionObject;
 
 public:
 
@@ -237,7 +238,7 @@ public:
      *      (as a fraction between 0-1) where the intersection occurred.
      * @return The first rigid body that the ray intersects, or NULL if no intersection was found.
      */
-    PhysicsRigidBody* rayTest(const Ray& ray, float distance, Vector3* hitPoint = NULL, float* hitFraction = NULL);
+    PhysicsCollisionObject* rayTest(const Ray& ray, float distance, Vector3* hitPoint = NULL, float* hitFraction = NULL);
 
 protected:
 
@@ -257,15 +258,17 @@ private:
     // Represents the collision listeners and status for a given collision pair (used by the collision status cache).
     struct CollisionInfo
     {
-        std::vector<PhysicsRigidBody::Listener*> _listeners;
+        CollisionInfo() : _status(0) { }
+
+        std::vector<PhysicsCollisionObject::CollisionListener*> _listeners;
         int _status;
     };
 
     // Wraps Bullet collision shapes (used for implementing shape caching).
     struct PhysicsCollisionShape : public Ref
     {
-        PhysicsCollisionShape(btCollisionShape* shape) : _shape(shape) {}
-        ~PhysicsCollisionShape() { SAFE_DELETE(_shape); }
+        PhysicsCollisionShape(btCollisionShape* shape);
+        ~PhysicsCollisionShape();
 
         btCollisionShape* _shape;
     };
@@ -305,17 +308,20 @@ private:
      */
     void update(long elapsedTime);
 
-    // Adds the given collision listener for the two given rigid bodies.
-    void addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB);
+    // Adds the given collision listener for the two given collision objects.
+    void addCollisionListener(PhysicsCollisionObject::CollisionListener* listener, PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB);
+
+    // Removes the given collision listener.
+    void removeCollisionListener(PhysicsCollisionObject::CollisionListener* listener, PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB);
 
-    // Adds the given rigid body to the world.
-    void addRigidBody(PhysicsRigidBody* body);
+    // Adds the given collision object to the world.
+    void addCollisionObject(PhysicsCollisionObject* object);
     
-    // Removes the given rigid body from the simulated physics world.
-    void removeRigidBody(PhysicsRigidBody* rigidBody);
+    // Removes the given collision object from the simulated physics world.
+    void removeCollisionObject(PhysicsCollisionObject* object);
     
     // Gets the corresponding GamePlay object for the given Bullet object.
-    PhysicsRigidBody* getRigidBody(const btCollisionObject* collisionObject);
+    PhysicsCollisionObject* getCollisionObject(const btCollisionObject* collisionObject) const;
     
     // Creates a box collision shape to be used in the creation of a rigid body.
     btCollisionShape* createBox(const Vector3& min, const Vector3& max, const Vector3& scale);
@@ -373,7 +379,7 @@ private:
         const Matrix* _viewProjection;
         MeshBatch* _meshBatch;
     };
-    
+
     btDefaultCollisionConfiguration* _collisionConfiguration;
     btCollisionDispatcher* _dispatcher;
     btBroadphaseInterface* _overlappingPairCache;
@@ -384,9 +390,9 @@ private:
     DebugDrawer* _debugDrawer;
     Listener::EventType _status;
     std::vector<Listener*>* _listeners;
-    std::vector<PhysicsRigidBody*> _bodies;
     Vector3 _gravity;
-    std::map<PhysicsRigidBody::CollisionPair, CollisionInfo> _collisionStatus;  
+    std::map<PhysicsCollisionObject::CollisionPair, CollisionInfo> _collisionStatus;
+
 };
 
 }

+ 30 - 44
gameplay/src/PhysicsRigidBody.cpp

@@ -9,16 +9,16 @@ namespace gameplay
 {
 
 // Internal values used for creating mesh, heightfield, and capsule rigid bodies.
-#define SHAPE_MESH ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 1))
-#define SHAPE_HEIGHTFIELD ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 2))
-#define SHAPE_CAPSULE ((PhysicsRigidBody::Type)(PhysicsRigidBody::SHAPE_NONE + 3))
+#define SHAPE_MESH ((PhysicsRigidBody::ShapeType)(PhysicsRigidBody::SHAPE_NONE + 1))
+#define SHAPE_HEIGHTFIELD ((PhysicsRigidBody::ShapeType)(PhysicsRigidBody::SHAPE_NONE + 2))
+#define SHAPE_CAPSULE ((PhysicsRigidBody::ShapeType)(PhysicsRigidBody::SHAPE_NONE + 3))
 
 // Helper function for calculating heights from heightmap (image) or heightfield data.
 static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y);
 
-PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, float mass, 
+PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::ShapeType type, float mass, 
     float friction, float restitution, float linearDamping, float angularDamping)
-        : _shape(NULL), _body(NULL), _node(node), _listeners(NULL), _angularVelocity(NULL),
+        : _shape(NULL), _body(NULL), _node(node), _angularVelocity(NULL),
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
 {
@@ -61,12 +61,12 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, floa
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
 
     // Add the rigid body to the physics world.
-    Game::getInstance()->getPhysicsController()->addRigidBody(this);
+    Game::getInstance()->getPhysicsController()->addCollisionObject(this);
 }
 
 PhysicsRigidBody::PhysicsRigidBody(Node* node, Image* image, float mass,
     float friction, float restitution, float linearDamping, float angularDamping)
-        : _shape(NULL), _body(NULL), _node(node), _listeners(NULL), _angularVelocity(NULL),
+        : _shape(NULL), _body(NULL), _node(node), _angularVelocity(NULL),
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
 {
@@ -139,7 +139,7 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, Image* image, float mass,
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
 
     // Add the rigid body to the physics world.
-    Game::getInstance()->getPhysicsController()->addRigidBody(this);
+    Game::getInstance()->getPhysicsController()->addCollisionObject(this);
 
     // Add the rigid body as a listener on the node's transform.
     _node->addListener(this);
@@ -147,7 +147,7 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, Image* image, float mass,
 
 PhysicsRigidBody::PhysicsRigidBody(Node* node, float radius, float height, float mass, float friction,
     float restitution, float linearDamping, float angularDamping)
-        : _shape(NULL), _body(NULL), _node(node), _listeners(NULL), _angularVelocity(NULL),
+        : _shape(NULL), _body(NULL), _node(node), _angularVelocity(NULL),
         _anisotropicFriction(NULL), _gravity(NULL), _linearVelocity(NULL), _vertexData(NULL),
         _indexData(NULL), _heightfieldData(NULL), _inverse(NULL), _inverseIsDirty(true)
 {
@@ -172,7 +172,7 @@ PhysicsRigidBody::PhysicsRigidBody(Node* node, float radius, float height, float
         _body = createRigidBodyInternal(_shape, mass, node, friction, restitution, linearDamping, angularDamping);
 
     // Add the rigid body to the physics world.
-    Game::getInstance()->getPhysicsController()->addRigidBody(this);
+    Game::getInstance()->getPhysicsController()->addCollisionObject(this);
 }
 
 PhysicsRigidBody::~PhysicsRigidBody()
@@ -186,17 +186,16 @@ PhysicsRigidBody::~PhysicsRigidBody()
         SAFE_DELETE(ptr);
     }
 
+    Game::getInstance()->getPhysicsController()->removeCollisionObject(this);
+
     // Clean up the rigid body and its related objects.
     if (_body)
     {
         if (_body->getMotionState())
             delete _body->getMotionState();
-
-        Game::getInstance()->getPhysicsController()->removeRigidBody(this);
         SAFE_DELETE(_body);
     }
 
-    SAFE_DELETE(_listeners);
     SAFE_DELETE(_angularVelocity);
     SAFE_DELETE(_anisotropicFriction);
     SAFE_DELETE(_gravity);
@@ -210,9 +209,24 @@ PhysicsRigidBody::~PhysicsRigidBody()
     SAFE_DELETE(_inverse);
 }
 
-void PhysicsRigidBody::addCollisionListener(Listener* listener, PhysicsRigidBody* body)
+Node* PhysicsRigidBody::getNode() const
+{
+    return _node;
+}
+
+PhysicsCollisionObject::Type PhysicsRigidBody::getType() const
+{
+    return PhysicsCollisionObject::RIGID_BODY;
+}
+
+btCollisionObject* PhysicsRigidBody::getCollisionObject() const
+{
+    return _body;
+}
+
+btCollisionShape* PhysicsRigidBody::getCollisionShape() const
 {
-    Game::getInstance()->getPhysicsController()->addCollisionListener(listener, this, body);
+    return _shape;
 }
 
 void PhysicsRigidBody::applyForce(const Vector3& force, const Vector3* relativePosition)
@@ -268,15 +282,6 @@ void PhysicsRigidBody::applyTorqueImpulse(const Vector3& torque)
     }
 }
 
-bool PhysicsRigidBody::collidesWith(PhysicsRigidBody* body)
-{
-    static CollidesWithCallback callback;
-
-    callback.result = false;
-    Game::getInstance()->getPhysicsController()->_world->contactPairTest(_body, body->_body, callback);
-    return callback.result;
-}
-
 PhysicsRigidBody* PhysicsRigidBody::create(Node* node, const char* filePath)
 {
     assert(filePath);
@@ -307,7 +312,7 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
     }
 
     // Set values to their defaults.
-    PhysicsRigidBody::Type type = PhysicsRigidBody::SHAPE_NONE;
+    PhysicsRigidBody::ShapeType type = PhysicsRigidBody::SHAPE_NONE;
     float mass = 0.0;
     float friction = 0.5;
     float restitution = 0.0;
@@ -557,25 +562,6 @@ void PhysicsRigidBody::transformChanged(Transform* transform, long cookie)
     _inverseIsDirty = true;
 }
 
-PhysicsRigidBody::CollisionPair::CollisionPair(PhysicsRigidBody* rigidBodyA, PhysicsRigidBody* rigidBodyB)
-    : rigidBodyA(rigidBodyA), rigidBodyB(rigidBodyB)
-{
-    // Unused
-}
-
-PhysicsRigidBody::Listener::~Listener()
-{
-    // Unused
-}
-
-btScalar PhysicsRigidBody::CollidesWithCallback::addSingleResult(btManifoldPoint& cp, 
-                                                                 const btCollisionObject* a, int partIdA, int indexA, 
-                                                                 const btCollisionObject* b, int partIdB, int indexB)
-{
-    result = true;
-    return 0.0f;
-}
-
 float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y)
 {
     unsigned int x1 = x;

+ 21 - 96
gameplay/src/PhysicsRigidBody.h

@@ -5,6 +5,7 @@
 #include "PhysicsConstraint.h"
 #include "Transform.h"
 #include "Vector3.h"
+#include "PhysicsCollisionObject.h"
 
 namespace gameplay
 {
@@ -15,7 +16,7 @@ class PhysicsConstraint;
 /**
  * Defines a class for physics rigid bodies.
  */
-class PhysicsRigidBody : public Transform::Listener
+class PhysicsRigidBody : public PhysicsCollisionObject, public Transform::Listener
 {
     friend class Node;
     friend class PhysicsCharacter;
@@ -32,7 +33,7 @@ public:
     /**
      * Represents the different types of rigid bodies.
      */
-    enum Type
+    enum ShapeType
     {
         SHAPE_BOX,
         SHAPE_SPHERE,
@@ -40,81 +41,10 @@ public:
         SHAPE_MAX = 10
     };
 
-    /** 
-     * Defines a pair of rigid bodies that collided (or may collide).
-     */
-    class CollisionPair
-    {
-    public:
-
-        /**
-         * Constructor.
-         */
-        CollisionPair(PhysicsRigidBody* rigidBodyA, PhysicsRigidBody* rigidBodyB);
-
-        /**
-         * Less than operator (needed for use as a key in map).
-         * 
-         * @param collisionPair The collision pair to compare.
-         * @return True if this pair is "less than" the given pair; false otherwise.
-         */
-        bool operator<(const CollisionPair& collisionPair) const;
-
-        /** The first rigid body in the collision. */
-        PhysicsRigidBody* rigidBodyA;
-
-        /** The second rigid body in the collision. */
-        PhysicsRigidBody* rigidBodyB;
-    };
-
     /**
-     * Collision listener interface.
+     * @see PhysicsCollisionObject#getType
      */
-    class Listener
-    {
-        friend class PhysicsRigidBody;
-        friend class PhysicsController;
-
-    public:
-        /**
-         * The type of collision event.
-         */
-        enum EventType
-        {
-            /**
-             * Event fired when the two rigid bodies start colliding.
-             */
-            COLLIDING,
-
-            /**
-             * Event fired when the two rigid bodies no longer collide.
-             */
-            NOT_COLLIDING
-        };
-
-        /**
-         * Destructor.
-         */
-        virtual ~Listener();
-
-        /**
-         * Handles when a collision starts or stops occurring for the rigid body where this listener is registered.
-         * 
-         * @param type The type of collision event.
-         * @param collisionPair The two rigid bodies involved in the collision.
-         * @param contactPointA The contact point with the first rigid body (in world space).
-         * @param contactPointB The contact point with the second rigid body (in world space).
-         */
-        virtual void collisionEvent(EventType type, const CollisionPair& collisionPair, const Vector3& contactPointA = Vector3(), const Vector3& contactPointB = Vector3()) = 0;
-    };
-
-    /**
-     * Adds a collision listener for this rigid body.
-     * 
-     * @param listener The listener to add.
-     * @param body Specifies that only collisions with the given rigid body should trigger a notification.
-     */
-    void addCollisionListener(Listener* listener, PhysicsRigidBody* body = NULL);
+    PhysicsCollisionObject::Type getType() const;
 
     /**
      * Applies the given force to the rigid body (optionally, from the given relative position).
@@ -145,14 +75,6 @@ public:
      * @param torque The torque impulse to be applied.
      */
     void applyTorqueImpulse(const Vector3& torque);
-    
-    /**
-     * Checks if this rigid body collides with the given rigid body.
-     * 
-     * @param body The rigid body to test collision with.
-     * @return True if this rigid body collides with the given rigid body; false otherwise.
-     */
-    bool collidesWith(PhysicsRigidBody* body);
 
     /**
      * Gets the rigid body's angular damping.
@@ -217,8 +139,10 @@ public:
      * Gets the node that the rigid body is attached to.
      * 
      * @return The node.
+     *
+     * @see PhysicsCollisionObject::getNode.
      */
-    inline Node* getNode();
+    Node* getNode() const;
 
     /**
      * Gets the rigid body's restitution.
@@ -305,6 +229,18 @@ public:
      */
     inline void setRestitution(float restitution);
 
+protected:
+
+    /**
+     * @see PhysicsCollisionObject::getCollisionObject
+     */
+    btCollisionObject* getCollisionObject() const;
+
+    /**
+     * @see PhysicsCollisionObject::getCollisionShape
+     */
+    btCollisionShape* getCollisionShape() const;
+
 private:
 
     /**
@@ -320,7 +256,7 @@ private:
      * @param linearDamping The percentage of linear velocity lost per second (between 0.0 and 1.0).
      * @param angularDamping The percentage of angular velocity lost per second (between 0.0 and 1.0).
      */
-    PhysicsRigidBody(Node* node, PhysicsRigidBody::Type type, float mass, float friction = 0.5,
+    PhysicsRigidBody(Node* node, PhysicsRigidBody::ShapeType type, float mass, float friction = 0.5,
         float restitution = 0.0, float linearDamping = 0.0, float angularDamping = 0.0);
 
     /**
@@ -404,21 +340,10 @@ private:
     // Used for implementing getHeight() when the heightfield has a transform that can change.
     void transformChanged(Transform* transform, long cookie);
 
-    // Internal class used to implement the collidesWith(PhysicsRigidBody*) function.
-    struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
-    {
-        btScalar addSingleResult(btManifoldPoint& cp, 
-                                 const btCollisionObject* a, int partIdA, int indexA, 
-                                 const btCollisionObject* b, int partIdB, int indexB);
-
-        bool result;
-    };
-
     btCollisionShape* _shape;
     btRigidBody* _body;
     Node* _node;
     std::vector<PhysicsConstraint*> _constraints;
-    std::vector<Listener*>* _listeners;
     mutable Vector3* _angularVelocity;
     mutable Vector3* _anisotropicFriction;
     mutable Vector3* _gravity;

+ 0 - 22
gameplay/src/PhysicsRigidBody.inl

@@ -59,11 +59,6 @@ inline const Vector3& PhysicsRigidBody::getLinearVelocity() const
     return *_linearVelocity;
 }
 
-inline Node* PhysicsRigidBody::getNode()
-{
-    return _node;
-}
-
 inline float PhysicsRigidBody::getRestitution() const
 {
     return _body->getRestitution();
@@ -133,21 +128,4 @@ inline void PhysicsRigidBody::setRestitution(float restitution)
     _body->setRestitution(restitution);
 }
 
-inline bool PhysicsRigidBody::CollisionPair::operator<(const CollisionPair& collisionPair) const
-{
-    // If the pairs are equal, then return false.
-    if ((rigidBodyA == collisionPair.rigidBodyA && rigidBodyB == collisionPair.rigidBodyB) || (rigidBodyA == collisionPair.rigidBodyB && rigidBodyB == collisionPair.rigidBodyA))
-        return false;
-    else
-    {
-        // We choose to compare based on rigidBodyA arbitrarily.
-        if (rigidBodyA < collisionPair.rigidBodyA)
-            return true;
-        else if (rigidBodyA == collisionPair.rigidBodyA)
-            return rigidBodyB < collisionPair.rigidBodyB;
-        else
-            return false;
-    }
-}
-
 }

+ 1 - 1
gameplay/src/Platform.h

@@ -117,7 +117,7 @@ public:
      *
      * @param display true when virtual keyboard needs to be displayed and false otherwise.
      */
-     static void displayKeyboard(bool display);
+    static void displayKeyboard(bool display);
 
     static void touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 

+ 1 - 1
gameplay/src/PlatformiOS.mm

@@ -845,7 +845,7 @@ void Platform::swapBuffers()
         [__view swapBuffers];
 }
 
-void displayKeyboard(bool display) 
+void Platform::displayKeyboard(bool display) 
 {
     if(__view) 
     {

+ 7 - 1
gameplay/src/Texture.cpp

@@ -75,8 +75,12 @@ Texture* Texture::create(const char* path, bool generateMipmaps)
             }
 			else if (tolower(ext[1]) == 'p' && tolower(ext[2]) == 'v' && tolower(ext[3]) == 'r')
 			{
+#ifdef OPENGL_ES_PVR
             	// PowerVR Compressed RGBA
 				texture = createCompressedPVR(path);
+#else
+                texture = NULL; // Cannot handle PVR if not supported on platform
+#endif
 			}
             break;
         }
@@ -143,6 +147,7 @@ Texture* Texture::create(Format format, unsigned int width, unsigned int height,
     return texture;
 }
 
+#ifdef OPENGL_ES_PVR
 Texture* Texture::createCompressedPVR(const char* path)
 {
 	char PVRTexIdentifier[] = "PVR!";
@@ -274,7 +279,8 @@ Texture* Texture::createCompressedPVR(const char* path)
 
 	return texture;
 }
-
+#endif
+    
 unsigned int Texture::getWidth() const
 {
     return _width;

+ 5 - 1
gameplay/src/Texture.h

@@ -30,10 +30,12 @@ public:
         RGBA    = GL_RGBA,
         ALPHA   = GL_ALPHA,
         DEPTH   = GL_DEPTH_COMPONENT,
+#ifdef OPENGL_ES_PVR
         COMPRESSED_RGB_PVRTC_4BPP = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
 		COMPRESSED_RGBA_PVRTC_4BPP = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
 		COMPRESSED_RGB_PVRTC_2BPP = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
 		COMPRESSED_RGBA_PVRTC_2BPP = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
+#endif
     };
 
     /**
@@ -211,8 +213,10 @@ private:
      */
     virtual ~Texture();
 
+#ifdef OPENGL_ES_PVR
 	static Texture* createCompressedPVR(const char* path);
-
+#endif
+    
     std::string _path;
     TextureHandle _handle;
     unsigned int _width;

+ 1 - 1
gameplay/src/VertexAttributeBinding.cpp

@@ -195,7 +195,7 @@ VertexAttributeBinding* VertexAttributeBinding::create(Mesh* mesh, const VertexF
 
         if (attrib == -1)
         {
-            WARN_VARG("Warning: Vertex attribute not found for usage %d", (int)e.usage);
+            WARN_VARG("Warning: Vertex element with usage '%s' in mesh '%s' does not correspond to an attribute in effect '%s'.", VertexFormat::toString(e.usage), mesh->getUrl(), effect->getId());
         }
         else
         {

+ 39 - 0
gameplay/src/VertexFormat.cpp

@@ -80,4 +80,43 @@ bool VertexFormat::Element::operator != (const VertexFormat::Element& e) const
     return !(*this == e);
 }
 
+const char* VertexFormat::toString(Usage usage)
+{
+    switch (usage)
+    {
+    case POSITION:
+        return "POSITION";
+    case NORMAL:
+        return "NORMAL";
+    case COLOR:
+        return "COLOR";
+    case TANGENT:
+        return "TANGENT";
+    case BINORMAL:
+        return "BINORMAL";
+    case BLENDWEIGHTS:
+        return "BLENDWEIGHTS";
+    case BLENDINDICES:
+        return "BLENDINDICES";
+    case TEXCOORD0:
+        return "TEXCOORD0";
+    case TEXCOORD1:
+        return "TEXCOORD1";
+    case TEXCOORD2:
+        return "TEXCOORD2";
+    case TEXCOORD3:
+        return "TEXCOORD3";
+    case TEXCOORD4:
+        return "TEXCOORD4";
+    case TEXCOORD5:
+        return "TEXCOORD5";
+    case TEXCOORD6:
+        return "TEXCOORD6";
+    case TEXCOORD7:
+        return "TEXCOORD7";
+    default:
+        return "UNKNOWN";
+    }
+}
+
 }

+ 5 - 0
gameplay/src/VertexFormat.h

@@ -141,6 +141,11 @@ public:
      */
     bool operator != (const VertexFormat& f) const;
 
+    /**
+     * Returns a string representation of a Usage enumeration value.
+     */
+    static const char* toString(Usage usage);
+
 private:
 
     std::vector<Element> _elements;

+ 1 - 1
gameplay/src/gameplay.h

@@ -66,10 +66,10 @@
 #include "PhysicsHingeConstraint.h"
 #include "PhysicsSocketConstraint.h"
 #include "PhysicsSpringConstraint.h"
+#include "PhysicsCollisionObject.h"
 #include "PhysicsRigidBody.h"
 #include "PhysicsCharacter.h"
 
-
 // UI
 #include "Theme.h"
 #include "Control.h"