Browse Source

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

Steve Grenier 13 years ago
parent
commit
cd56321b6d
51 changed files with 2474 additions and 136 deletions
  1. 180 12
      gameplay.sln
  2. 1 0
      gameplay/CMakeLists.txt
  3. 2 1
      gameplay/android/jni/Android.mk
  4. 230 0
      gameplay/gameplay.vcxproj
  5. 3 0
      gameplay/gameplay.vcxproj.filters
  6. 10 0
      gameplay/gameplay.xcodeproj/project.pbxproj
  7. 58 0
      gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-ios.xcscheme
  8. 58 0
      gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-macosx.xcscheme
  9. 75 9
      gameplay/src/Container.cpp
  10. 2 0
      gameplay/src/Container.h
  11. 9 2
      gameplay/src/Control.cpp
  12. 11 2
      gameplay/src/Control.h
  13. 25 16
      gameplay/src/Form.cpp
  14. 14 0
      gameplay/src/Form.h
  15. 18 11
      gameplay/src/Game.cpp
  16. 1 0
      gameplay/src/Game.h
  17. 14 2
      gameplay/src/Layout.cpp
  18. 1 9
      gameplay/src/Layout.h
  19. 29 0
      gameplay/src/MathUtil.cpp
  20. 31 0
      gameplay/src/MathUtil.h
  21. 4 4
      gameplay/src/Mesh.cpp
  22. 204 3
      gameplay/src/PhysicsVehicle.cpp
  23. 217 1
      gameplay/src/PhysicsVehicle.h
  24. 28 3
      gameplay/src/PhysicsVehicleWheel.cpp
  25. 9 0
      gameplay/src/PhysicsVehicleWheel.h
  26. 823 33
      gameplay/src/PlatformMacOSX.mm
  27. 11 11
      gameplay/src/TextBox.cpp
  28. 0 5
      gameplay/src/TextBox.h
  29. 4 1
      gameplay/src/ThemeStyle.cpp
  30. 9 0
      gameplay/src/Transform.cpp
  31. 13 0
      gameplay/src/Transform.h
  32. 8 0
      gameplay/src/Vector2.cpp
  33. 13 0
      gameplay/src/Vector2.h
  34. 8 0
      gameplay/src/Vector3.cpp
  35. 13 0
      gameplay/src/Vector3.h
  36. 1 0
      gameplay/src/gameplay.h
  37. 0 1
      gameplay/src/lua/lua_Global.cpp
  38. 47 0
      gameplay/src/lua/lua_Joint.cpp
  39. 1 0
      gameplay/src/lua/lua_Joint.h
  40. 0 5
      gameplay/src/lua/lua_LayoutType.cpp
  41. 88 1
      gameplay/src/lua/lua_MathUtil.cpp
  42. 1 0
      gameplay/src/lua/lua_MathUtil.h
  43. 47 0
      gameplay/src/lua/lua_Node.cpp
  44. 1 0
      gameplay/src/lua/lua_Node.h
  45. 8 4
      gameplay/src/lua/lua_PhysicsVehicle.cpp
  46. 47 0
      gameplay/src/lua/lua_Transform.cpp
  47. 1 0
      gameplay/src/lua/lua_Transform.h
  48. 47 0
      gameplay/src/lua/lua_Vector2.cpp
  49. 1 0
      gameplay/src/lua/lua_Vector2.h
  50. 47 0
      gameplay/src/lua/lua_Vector3.cpp
  51. 1 0
      gameplay/src/lua/lua_Vector3.h

+ 180 - 12
gameplay.sln

@@ -45,63 +45,231 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample06-racer", "gameplay-
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|BlackBerry = Debug|BlackBerry
+		Debug|BlackBerrySimulator = Debug|BlackBerrySimulator
 		Debug|Win32 = Debug|Win32
+		DebugMem|BlackBerry = DebugMem|BlackBerry
+		DebugMem|BlackBerrySimulator = DebugMem|BlackBerrySimulator
 		DebugMem|Win32 = DebugMem|Win32
+		Release|BlackBerry = Release|BlackBerry
+		Release|BlackBerrySimulator = Release|BlackBerrySimulator
 		Release|Win32 = Release|Win32
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|Win32.ActiveCfg = Debug|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Debug|Win32.Build.0 = Debug|Win32
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.ActiveCfg = Release|Win32
 		{1032BA4B-57EB-4348-9E03-29DD63E80E4A}.Release|Win32.Build.0 = Release|Win32
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|Win32.Build.0 = Debug|Win32
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|Win32.ActiveCfg = Release|Win32
+		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|Win32.Build.0 = Release|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
+		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Debug|Win32.Build.0 = Debug|Win32
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|Win32.ActiveCfg = Release|Win32
 		{9A515C8B-3320-4C5C-9754-211E91206C9D}.Release|Win32.Build.0 = Release|Win32
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|Win32.ActiveCfg = Debug|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Debug|Win32.Build.0 = Debug|Win32
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|Win32.ActiveCfg = Release|Win32
 		{CC37B8E9-6402-4841-8D6A-5D908A5909B3}.Release|Win32.Build.0 = Release|Win32
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|Win32.ActiveCfg = Debug|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Debug|Win32.Build.0 = Debug|Win32
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|Win32.ActiveCfg = Release|Win32
 		{87388E8B-F3CF-428F-BC2C-C1886248C111}.Release|Win32.Build.0 = Release|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|Win32.ActiveCfg = Debug|Win32
 		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Debug|Win32.Build.0 = Debug|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|Win32.ActiveCfg = Release|Win32
 		{CB5ABFAA-EA69-E439-5A4D-3B9359916C71}.Release|Win32.Build.0 = Release|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Debug|Win32.Build.0 = Debug|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.DebugMem|Win32.Build.0 = DebugMem|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.ActiveCfg = Release|Win32
-		{D672DC66-3CE0-4878-B0D2-813CA731012F}.Release|Win32.Build.0 = Release|Win32
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|Win32.ActiveCfg = Debug|Win32
 		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Debug|Win32.Build.0 = Debug|Win32
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|Win32.ActiveCfg = Release|Win32
 		{C6121A62-AA46-BA6D-A1CE-8000544456AA}.Release|Win32.Build.0 = Release|Win32
-		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Debug|Win32.Build.0 = Debug|Win32
-		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
-		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.DebugMem|Win32.Build.0 = DebugMem|Win32
-		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|Win32.ActiveCfg = Release|Win32
-		{D70B295E-A2FF-2CBB-737E-3876E8AF77F6}.Release|Win32.Build.0 = Release|Win32
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|BlackBerry.ActiveCfg = Debug|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|BlackBerry.Build.0 = Debug|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|BlackBerry.Deploy.0 = Debug|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|BlackBerrySimulator.ActiveCfg = Debug|BlackBerrySimulator
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|BlackBerrySimulator.Build.0 = Debug|BlackBerrySimulator
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|BlackBerrySimulator.Deploy.0 = Debug|BlackBerrySimulator
 		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|Win32.ActiveCfg = Debug|Win32
 		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Debug|Win32.Build.0 = Debug|Win32
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|BlackBerry.ActiveCfg = DebugMem|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|BlackBerry.Build.0 = DebugMem|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|BlackBerry.Deploy.0 = DebugMem|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|BlackBerrySimulator.ActiveCfg = DebugMem|BlackBerrySimulator
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|BlackBerrySimulator.Build.0 = DebugMem|BlackBerrySimulator
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|BlackBerrySimulator.Deploy.0 = DebugMem|BlackBerrySimulator
 		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|Win32.ActiveCfg = DebugMem|Win32
 		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.DebugMem|Win32.Build.0 = DebugMem|Win32
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|BlackBerry.ActiveCfg = Release|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|BlackBerry.Build.0 = Release|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|BlackBerry.Deploy.0 = Release|BlackBerry
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|BlackBerrySimulator.ActiveCfg = Release|BlackBerrySimulator
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|BlackBerrySimulator.Build.0 = Release|BlackBerrySimulator
+		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|BlackBerrySimulator.Deploy.0 = Release|BlackBerrySimulator
 		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|Win32.ActiveCfg = Release|Win32
 		{1808B3EA-1ED5-1219-6D3C-9F588D2D8385}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection

+ 1 - 0
gameplay/CMakeLists.txt

@@ -96,6 +96,7 @@ set(GAMEPLAY_SRC
     src/Material.h
     src/MaterialParameter.cpp
     src/MaterialParameter.h
+    src/MathUtil.cpp
     src/MathUtil.h
     src/MathUtil.inl
     src/MathUtilNeon.inl

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

@@ -61,6 +61,7 @@ LOCAL_SRC_FILES := \
     Light.cpp \
     Material.cpp \
     MaterialParameter.cpp \
+    MathUtil.cpp \
     Matrix.cpp \
     Mesh.cpp \
     MeshBatch.cpp \
@@ -281,4 +282,4 @@ LOCAL_STATIC_LIBRARIES := android_native_app_glue
 
 include $(BUILD_STATIC_LIBRARY)
 
-$(call import-module,android/native_app_glue)
+$(call import-module,android/native_app_glue)

+ 230 - 0
gameplay/gameplay.vcxproj

@@ -1,14 +1,38 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="DebugMem|BlackBerry">
+      <Configuration>DebugMem</Configuration>
+      <Platform>BlackBerry</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="DebugMem|BlackBerrySimulator">
+      <Configuration>DebugMem</Configuration>
+      <Platform>BlackBerrySimulator</Platform>
+    </ProjectConfiguration>
     <ProjectConfiguration Include="DebugMem|Win32">
       <Configuration>DebugMem</Configuration>
       <Platform>Win32</Platform>
     </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|BlackBerry">
+      <Configuration>Debug</Configuration>
+      <Platform>BlackBerry</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|BlackBerrySimulator">
+      <Configuration>Debug</Configuration>
+      <Platform>BlackBerrySimulator</Platform>
+    </ProjectConfiguration>
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
       <Platform>Win32</Platform>
     </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|BlackBerry">
+      <Configuration>Release</Configuration>
+      <Platform>BlackBerry</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|BlackBerrySimulator">
+      <Configuration>Release</Configuration>
+      <Platform>BlackBerrySimulator</Platform>
+    </ProjectConfiguration>
     <ProjectConfiguration Include="Release|Win32">
       <Configuration>Release</Configuration>
       <Platform>Win32</Platform>
@@ -220,6 +244,7 @@
     <ClCompile Include="src\lua\lua_VertexFormatUsage.cpp" />
     <ClCompile Include="src\lua\lua_VerticalLayout.cpp" />
     <ClCompile Include="src\Material.cpp" />
+    <ClCompile Include="src\MathUtil.cpp" />
     <ClCompile Include="src\MeshBatch.cpp" />
     <ClCompile Include="src\Pass.cpp" />
     <ClCompile Include="src\MaterialParameter.cpp" />
@@ -607,48 +632,140 @@
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerry'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerrySimulator'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerry'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerrySimulator'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerry'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerrySimulator'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerry'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerrySimulator'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerry'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerrySimulator'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerry'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerrySimulator'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <OutDir>$(Configuration)\</OutDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerry'">
+    <OutDir>Device-$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerrySimulator'">
+    <OutDir>Simulator\</OutDir>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
     <OutDir>$(Configuration)\</OutDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerry'">
+    <OutDir>Device-$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerrySimulator'">
+    <OutDir>Simulator\</OutDir>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <IntDir>$(Configuration)\</IntDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerry'">
+    <IntDir>Device-$(Configuration)\</IntDir>
+    <TargetName>lib$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerrySimulator'">
+    <IntDir>Simulator\</IntDir>
+    <TargetName>lib$(ProjectName)</TargetName>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
     <IntDir>$(Configuration)\</IntDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerry'">
+    <IntDir>Device-$(Configuration)\</IntDir>
+    <TargetName>lib$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerrySimulator'">
+    <IntDir>Simulator\</IntDir>
+    <TargetName>lib$(ProjectName)</TargetName>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <OutDir>$(Configuration)\</OutDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerry'">
+    <OutDir>Device-$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerrySimulator'">
+    <OutDir>Simulator\</OutDir>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <IntDir>$(Configuration)\</IntDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerry'">
+    <IntDir>Device-$(Configuration)\</IntDir>
+    <TargetName>lib$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerrySimulator'">
+    <IntDir>Simulator\</IntDir>
+    <TargetName>lib$(ProjectName)</TargetName>
+  </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <PrecompiledHeader>
@@ -666,6 +783,41 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
   </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerry'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)src;..\external-deps\lua\include;..\external-deps\bullet\include;..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\oggvorbis\include;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>
+      </RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <AdditionalOptions>-mfpu=neon %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|BlackBerrySimulator'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)src;..\external-deps\lua\include;..\external-deps\bullet\include;..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\oggvorbis\include;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>
+      </RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
     <ClCompile>
       <PrecompiledHeader>
@@ -686,6 +838,47 @@
       </Verbose>
     </Lib>
   </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerry'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;GAMEPLAY_MEM_LEAK_DETECTION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)src;..\external-deps\lua\include;..\external-deps\bullet\include;..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\oggvorbis\include;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <AdditionalOptions>-mfpu=neon %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <Verbose>
+      </Verbose>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|BlackBerrySimulator'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;GAMEPLAY_MEM_LEAK_DETECTION;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)src;..\external-deps\lua\include;..\external-deps\bullet\include;..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\oggvorbis\include;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <Verbose>
+      </Verbose>
+    </Lib>
+  </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
@@ -704,6 +897,43 @@
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
   </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerry'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)src;..\external-deps\lua\include;..\external-deps\bullet\include;..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\oggvorbis\include;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>-mfpu=neon %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|BlackBerrySimulator'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)src;..\external-deps\lua\include;..\external-deps\bullet\include;..\external-deps\openal\include\AL;..\external-deps\alut\include\AL;..\external-deps\oggvorbis\include;..\external-deps\glew\include;..\external-deps\libpng\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

+ 3 - 0
gameplay/gameplay.vcxproj.filters

@@ -804,6 +804,9 @@
     <ClCompile Include="src\lua\lua_PhysicsVehicleWheel.cpp">
       <Filter>lua</Filter>
     </ClCompile>
+    <ClCompile Include="src\MathUtil.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\Animation.h">

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

@@ -1622,6 +1622,7 @@
 		5B04C5C614BFCFE100EB0071 /* MeshBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 4201818E14A41B18008C3F56 /* MeshBatch.h */; };
 		5B04C5CD14BFD48500EB0071 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */; };
 		5B04C5CE14BFD48500EB0071 /* PlatformiOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */; };
+		5B21E99616153890006EBEAC /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B21E99516153890006EBEAC /* IOKit.framework */; };
 		5B2BC75F1512514500D176CD /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC75D1512514500D176CD /* OpenAL.framework */; };
 		5B2BC7601512514500D176CD /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC75E1512514500D176CD /* OpenGL.framework */; };
 		5B2BC7621512514D00D176CD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B2BC7611512514D00D176CD /* QuartzCore.framework */; };
@@ -1706,6 +1707,8 @@
 		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 */; };
+		F1616ABC1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
+		F1616ABD1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -2547,6 +2550,7 @@
 		5B04C5CA14BFCFE100EB0071 /* libgameplay.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgameplay.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		5B04C5CB14BFD48500EB0071 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
 		5B04C5CC14BFD48500EB0071 /* PlatformiOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformiOS.mm; path = src/PlatformiOS.mm; sourceTree = SOURCE_ROOT; };
+		5B21E99516153890006EBEAC /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
 		5B2BC75D1512514500D176CD /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; };
 		5B2BC75E1512514500D176CD /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
 		5B2BC7611512514D00D176CD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
@@ -2607,6 +2611,7 @@
 		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; };
+		F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MathUtil.cpp; path = src/MathUtil.cpp; sourceTree = SOURCE_ROOT; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -2614,6 +2619,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				5B21E99616153890006EBEAC /* IOKit.framework in Frameworks */,
 				5B2BC7641512516B00D176CD /* libz.dylib in Frameworks */,
 				5B2BC7621512514D00D176CD /* QuartzCore.framework in Frameworks */,
 				5B2BC75F1512514500D176CD /* OpenAL.framework in Frameworks */,
@@ -2780,6 +2786,7 @@
 				42CD0DE9147D8FF50000361E /* Material.h */,
 				42CD0DEA147D8FF50000361E /* MaterialParameter.cpp */,
 				42CD0DEB147D8FF50000361E /* MaterialParameter.h */,
+				F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */,
 				4239DDF1157545C1005EA3F6 /* MathUtil.h */,
 				4239DDF2157545C1005EA3F6 /* MathUtil.inl */,
 				4239DDF3157545C1005EA3F6 /* MathUtilNeon.inl */,
@@ -3578,6 +3585,7 @@
 		42CCD4AF146D811D00353661 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				5B21E99516153890006EBEAC /* IOKit.framework */,
 				5B04C5FD14BFE52300EB0071 /* iOS */,
 				5B04C5FE14BFE52F00EB0071 /* MacOSX */,
 			);
@@ -4982,6 +4990,7 @@
 				421FBD531602818800A61BC0 /* PhysicsVehicleWheel.cpp in Sources */,
 				421FBD5C1602827C00A61BC0 /* lua_PhysicsVehicle.cpp in Sources */,
 				421FBD601602827C00A61BC0 /* lua_PhysicsVehicleWheel.cpp in Sources */,
+				F1616ABC1614E24B008DD8B7 /* MathUtil.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -5405,6 +5414,7 @@
 				421FBD541602818800A61BC0 /* PhysicsVehicleWheel.cpp in Sources */,
 				421FBD5D1602827C00A61BC0 /* lua_PhysicsVehicle.cpp in Sources */,
 				421FBD611602827C00A61BC0 /* lua_PhysicsVehicleWheel.cpp in Sources */,
+				F1616ABD1614E24B008DD8B7 /* MathUtil.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 58 - 0
gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-ios.xcscheme

@@ -0,0 +1,58 @@
+<?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.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      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>

+ 58 - 0
gameplay/gameplay.xcodeproj/xcshareddata/xcschemes/gameplay-macosx.xcscheme

@@ -0,0 +1,58 @@
+<?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-macosx"
+               ReferencedContainer = "container:gameplay.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Debug"
+      ignoresPersistentStateOnLaunch = "NO"
+      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>

+ 75 - 9
gameplay/src/Container.cpp

@@ -41,7 +41,7 @@ Container::Container()
       _scrollingRight(false), _scrollingDown(false),
       _scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
       _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0), _totalWidth(0), _totalHeight(0),
-      _contactIndices(0)
+      _contactIndices(0), _initializedWithScroll(false)
 {
 }
 
@@ -172,6 +172,7 @@ void Container::addControls(Theme* theme, Properties* properties)
         if (control)
         {
             addControl(control);
+            control->release();
 
             if (control->getZIndex() == -1)
             {
@@ -204,32 +205,78 @@ Layout* Container::getLayout()
 unsigned int Container::addControl(Control* control)
 {
     GP_ASSERT(control);
-    _controls.push_back(control);
 
-    return _controls.size() - 1;
+    if (control->_parent && control->_parent != this)
+    {
+        control->_parent->removeControl(control);
+    }
+
+    if (control->_parent != this)
+    {
+        _controls.push_back(control);
+        control->addRef();
+        control->_parent = this;
+        return _controls.size() - 1;
+    }
+    else
+    {
+        // Control is already in this container.
+        // Do nothing but determine and return control's index.
+        const size_t size = _controls.size();
+        for (size_t i = 0; i < size; ++i)
+        {
+            Control* c = _controls[i];
+            if (c == control)
+            {
+                return i;
+            }
+        }
+
+        // Should never reach this.
+        GP_ASSERT(false);
+        return 0;
+    }
 }
 
 void Container::insertControl(Control* control, unsigned int index)
 {
     GP_ASSERT(control);
-    std::vector<Control*>::iterator it = _controls.begin() + index;
-    _controls.insert(it, control);
+
+    if (control->_parent && control->_parent != this)
+    {
+        control->_parent->removeControl(control);
+    }
+
+    if (control->_parent != this)
+    {
+        std::vector<Control*>::iterator it = _controls.begin() + index;
+        _controls.insert(it, control);
+        control->addRef();
+        control->_parent = this;
+    }
 }
 
 void Container::removeControl(unsigned int index)
 {
+    GP_ASSERT(index < _controls.size());
+
     std::vector<Control*>::iterator it = _controls.begin() + index;
     _controls.erase(it);
+    Control* control = *it;
+    control->_parent = NULL;
+    SAFE_RELEASE(control);
 }
 
 void Container::removeControl(const char* id)
 {
+    GP_ASSERT(id);
     std::vector<Control*>::iterator it;
     for (it = _controls.begin(); it < _controls.end(); it++)
     {
         Control* c = *it;
         if (strcmp(id, c->getId()) == 0)
         {
+            SAFE_RELEASE(c);
             _controls.erase(it);
             return;
         }
@@ -244,6 +291,7 @@ void Container::removeControl(Control* control)
     {
         if (*it == control)
         {
+            SAFE_RELEASE(control);
             _controls.erase(it);
             return;
         }
@@ -533,6 +581,11 @@ bool Container::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 
 bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
 {
+    // This event may run untrusted code by notifying listeners of events.
+    // If the user calls exit() or otherwise releases this container, we
+    // need to keep it alive until the method returns.
+    addRef();
+
     std::vector<Control*>::const_iterator it;
     for (it = _controls.begin(); it < _controls.end(); it++)
     {
@@ -547,6 +600,7 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
         {
             if (control->keyEvent(evt, key))
             {
+                release();
                 return _consumeInputEvents;
             }
             else if (evt == Keyboard::KEY_CHAR && key == Keyboard::KEY_TAB)
@@ -566,6 +620,7 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
                     if (nextControl->getFocusIndex() == focusIndex)
                     {
                         nextControl->setState(Control::FOCUS);
+                        release();
                         return _consumeInputEvents;
                     }
                 }
@@ -573,6 +628,7 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
         }
     }
 
+    release();
     return false;
 }
 
@@ -602,10 +658,6 @@ Layout::Type Container::getLayoutType(const char* layoutString)
     {
         return Layout::LAYOUT_FLOW;
     }
-    else if (layoutName == "LAYOUT_SCROLL")
-    {
-        return Layout::LAYOUT_SCROLL;
-    }
     else
     {
         // Default.
@@ -615,6 +667,12 @@ Layout::Type Container::getLayoutType(const char* layoutString)
 
 void Container::updateScroll()
 {
+    if (!_initializedWithScroll)
+    {
+        _initializedWithScroll = true;
+        _layout->update(this, _scrollPosition);
+    }
+
     // Update Time.
     static double lastFrameTime = Game::getGameTime();
     double frameTime = Game::getGameTime();
@@ -955,6 +1013,11 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         return false;
     }
 
+    // This event may run untrusted code by notifying listeners of events.
+    // If the user calls exit() or otherwise releases this container, we
+    // need to keep it alive until the method returns.
+    addRef();
+
     bool eventConsumed = false;
     const Theme::Border& border = getBorder(_state);
     const Theme::Padding& padding = getPadding();
@@ -1008,6 +1071,7 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
 
     if (!isEnabled())
     {
+        release();
         return (_consumeInputEvents | eventConsumed);
     }
     
@@ -1027,6 +1091,7 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         {
             setState(Control::NORMAL);
             _contactIndex = INVALID_CONTACT_INDEX;
+            release();
             return false;
         }
         break;
@@ -1050,6 +1115,7 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         }
     }
 
+    release();
     return (_consumeInputEvents | eventConsumed);
 }
 

+ 2 - 0
gameplay/src/Container.h

@@ -507,6 +507,8 @@ private:
     float _totalHeight;
 
     int _contactIndices;
+
+    bool _initializedWithScroll;
 };
 
 }

+ 9 - 2
gameplay/src/Control.cpp

@@ -7,8 +7,8 @@ namespace gameplay
 
 Control::Control()
     : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
-    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _listeners(NULL),
-    _contactIndex(INVALID_CONTACT_INDEX), _styleOverridden(false), _skin(NULL)
+    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT), _autoWidth(false), _autoHeight(false), _listeners(NULL),
+    _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(0), _parent(NULL), _styleOverridden(false), _skin(NULL)
 {
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
 }
@@ -798,6 +798,11 @@ bool Control::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 
 void Control::notifyListeners(Listener::EventType eventType)
 {
+    // This method runs untrusted code by notifying listeners of events.
+    // If the user calls exit() or otherwise releases this control, we
+    // need to keep it alive until the method returns.
+    addRef();
+
     if (_listeners)
     {
         std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
@@ -813,6 +818,8 @@ void Control::notifyListeners(Listener::EventType eventType)
     }
 
     fireScriptEvent<void>("controlEvent", this, eventType);
+
+    release();
 }
 
 void Control::update(const Control* container, const Vector2& offset)

+ 11 - 2
gameplay/src/Control.h

@@ -15,6 +15,8 @@
 namespace gameplay
 {
 
+class Container;
+
 /**
  * Base class for UI controls.
  */
@@ -214,13 +216,15 @@ public:
 
     /** 
      * Set the desired width of the control, including it's border and padding, before clipping.
-     * @param width The width;
+     *
+     * @param width The width.
      */
     virtual void setWidth(float width);
 
     /** 
      * Set the desired height of the control, including it's border and padding, before clipping.
-     * @param height The height;
+     *
+     * @param height The height.
      */
     virtual void setHeight(float height);
 
@@ -1002,6 +1006,11 @@ protected:
      */
     int _focusIndex;
 
+    /**
+     * The control's parent container.
+     */
+    Container* _parent;
+
 private:
 
     /*

+ 25 - 16
gameplay/src/Form.cpp

@@ -199,8 +199,6 @@ Form* Form::create(const char* url)
     // Add all the controls to the form.
     form->addControls(theme, formProperties);
 
-    form->update(0.0f);
-
     SAFE_DELETE(properties);
 
     __forms.push_back(form);
@@ -240,7 +238,8 @@ void Form::setSize(float width, float height)
         height = Game::getInstance()->getHeight();
     }
 
-    if (width != _bounds.width || height != _bounds.height)
+    if (width != 0.0f && height != 0.0f &&
+        (width != _bounds.width || height != _bounds.height))
     {
         // Width and height must be powers of two to create a texture.
         unsigned int w = nextPowerOfTwo(width);
@@ -273,11 +272,11 @@ void Form::setSize(float width, float height)
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
         FrameBuffer::bindDefault();
         game->setViewport(prevViewport);
-
-        _bounds.width = width;
-        _bounds.height = height;
-        _dirty = true;
     }
+    
+    _bounds.width = width;
+    _bounds.height = height;
+    _dirty = true;
 }
 
 void Form::setBounds(const Rectangle& bounds)
@@ -286,6 +285,16 @@ void Form::setBounds(const Rectangle& bounds)
     setSize(bounds.width, bounds.height);
 }
 
+void Form::setWidth(float width)
+{
+    setSize(width, _bounds.height);
+}
+
+void Form::setHeight(float height)
+{
+    setSize(_bounds.width, height);
+}
+
 void Form::setAutoWidth(bool autoWidth)
 {
     if (_autoWidth != autoWidth)
@@ -583,10 +592,10 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
     // Check for a collision with each Form in __forms.
     // Pass the event on.
     bool eventConsumed = false;
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    size_t size = __forms.size();
+    for (size_t i = 0; i < size; ++i)
     {
-        Form* form = *it;
+        Form* form = __forms[i];
         GP_ASSERT(form);
 
         if (form->isEnabled())
@@ -630,10 +639,10 @@ bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int
 
 bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    size_t size = __forms.size();
+    for (size_t i = 0; i < size; ++i)
     {
-        Form* form = *it;
+        Form* form = __forms[i];
         GP_ASSERT(form);
         if (form->isEnabled())
         {
@@ -648,10 +657,10 @@ bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
 {
     bool eventConsumed = false;
 
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    size_t size = __forms.size();
+    for (size_t i = 0; i < size; ++i)
     {
-        Form* form = *it;
+        Form* form = __forms[i];
         GP_ASSERT(form);
 
         if (form->isEnabled())

+ 14 - 0
gameplay/src/Form.h

@@ -104,6 +104,20 @@ public:
      */
     virtual void setBounds(const Rectangle& bounds);
 
+    /** 
+     * Set the desired width of the form.
+     *
+     * @param width The width.
+     */
+    virtual void setWidth(float width);
+
+    /** 
+     * Set the desired height of the form.
+     *
+     * @param height The height.
+     */
+    virtual void setHeight(float height);
+
     /**
      * Set this form's width to that of the display.
      *

+ 18 - 11
gameplay/src/Game.cpp

@@ -19,7 +19,7 @@ double Game::_pausedTimeLast = 0.0;
 double Game::_pausedTimeTotal = 0.0;
 
 Game::Game() 
-    : _initialized(false), _state(UNINITIALIZED), 
+    : _initialized(false), _state(UNINITIALIZED), _pausedCount(0),
       _frameLastFPS(0), _frameCount(0), _frameRate(0), 
       _clearDepth(1.0f), _clearStencil(0), _properties(NULL),
       _animationController(NULL), _audioController(NULL), 
@@ -235,22 +235,29 @@ void Game::pause()
         _physicsController->pause();
         _aiController->pause();
     }
+
+    ++_pausedCount;
 }
 
 void Game::resume()
 {
     if (_state == PAUSED)
     {
-        GP_ASSERT(_animationController);
-        GP_ASSERT(_audioController);
-        GP_ASSERT(_physicsController);
-        GP_ASSERT(_aiController);
-        _state = RUNNING;
-        _pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
-        _animationController->resume();
-        _audioController->resume();
-        _physicsController->resume();
-        _aiController->resume();
+        --_pausedCount;
+
+        if (_pausedCount == 0)
+		{
+			GP_ASSERT(_animationController);
+			GP_ASSERT(_audioController);
+			GP_ASSERT(_physicsController);
+			GP_ASSERT(_aiController);
+			_state = RUNNING;
+			_pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
+			_animationController->resume();
+			_audioController->resume();
+			_physicsController->resume();
+			_aiController->resume();
+		}
     }
 }
 

+ 1 - 0
gameplay/src/Game.h

@@ -661,6 +661,7 @@ private:
 
     bool _initialized;                          // If game has initialized yet.
     State _state;                               // The game state.
+    unsigned int _pausedCount;                  // Number of times pause() has been called.
     static double _pausedTimeLast;              // The last time paused.
     static double _pausedTimeTotal;             // The total time paused.
     double _frameLastFPS;                       // The last time the frame count was updated.

+ 14 - 2
gameplay/src/Layout.cpp

@@ -20,8 +20,20 @@ void Layout::align(Control* control, const Container* container)
         const Theme::Border& containerBorder = container->getBorder(container->getState());
         const Theme::Padding& containerPadding = container->getPadding();
 
-        float clipWidth = containerBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right;
-        float clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
+        float clipWidth;
+        float clipHeight; 
+        if (container->getScroll() != Container::SCROLL_NONE)
+        {
+            const Rectangle& verticalScrollBarBounds = container->getImageRegion("verticalScrollBar", container->getState());
+            const Rectangle& horizontalScrollBarBounds = container->getImageRegion("horizontalScrollBar", container->getState());
+            clipWidth = containerBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right - verticalScrollBarBounds.width;
+            clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - horizontalScrollBarBounds.height;
+        }
+        else
+        {
+            clipWidth = containerBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right;
+            clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
+        }
 
         if (control->_autoWidth)
         {

+ 1 - 9
gameplay/src/Layout.h

@@ -45,15 +45,7 @@ public:
          * Absolute layout: Controls are not modified at all by this layout.
          * They must be positioned and sized manually.
          */
-        LAYOUT_ABSOLUTE,
-
-        /**
-         * Scroll layout: Controls may be placed outside the bounds of the container.
-         * The user can then touch and drag to scroll.  By default controls are placed
-         * based on absolute positions in the .form file, but vertical or horizontal
-         * automatic positioning is an available option.
-         */
-        LAYOUT_SCROLL
+        LAYOUT_ABSOLUTE
     };
 
     /**

+ 29 - 0
gameplay/src/MathUtil.cpp

@@ -0,0 +1,29 @@
+#include "Base.h"
+#include "MathUtil.h"
+
+namespace gameplay
+{
+
+void MathUtil::smooth(float* x, float target, float elapsedTime, float responseTime)
+{
+    GP_ASSERT(x);
+
+    if (elapsedTime > 0)
+    {
+        *x += (target - *x) * elapsedTime / (elapsedTime + responseTime);
+    }
+}
+
+void MathUtil::smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime)
+{
+    GP_ASSERT(x);
+
+    float delta;
+    if (elapsedTime > 0)
+    {
+        delta = target - *x;
+        *x += delta * elapsedTime / (elapsedTime + (delta > 0 ? riseTime : fallTime));
+    }
+}
+
+}

+ 31 - 0
gameplay/src/MathUtil.h

@@ -11,6 +11,37 @@ class MathUtil
     friend class Matrix;
     friend class Vector3;
 
+public:
+
+    /**
+     * Updates the given scalar towards the given target using a smoothing function.
+     * The given response time determines the amount of smoothing (lag). A longer
+     * response time yields a smoother result and more lag. To force the scalar to
+     * follow the target closely, provide a response time that is very small relative
+     * to the given elapsed time.
+     *
+     * @param x the scalar to update.
+     * @param target target value.
+     * @param elapsedTime elapsed time between calls.
+     * @param responseTime response time (in the same units as elapsedTime).
+     */
+    static void smooth(float* x, float target, float elapsedTime, float responseTime);
+
+    /**
+     * Updates the given scalar towards the given target using a smoothing function.
+     * The given rise and fall times determine the amount of smoothing (lag). Longer
+     * rise and fall times yield a smoother result and more lag. To force the scalar to
+     * follow the target closely, provide rise and fall times that are very small relative
+     * to the given elapsed time.
+     *
+     * @param x the scalar to update.
+     * @param target target value.
+     * @param elapsedTime elapsed time between calls.
+     * @param riseTime response time for rising slope (in the same units as elapsedTime).
+     * @param fallTime response time for falling slope (in the same units as elapsedTime).
+     */
+    static void smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime);
+
 private:
 
     inline static void addMatrix(const float* m, float scalar, float* dst);

+ 4 - 4
gameplay/src/Mesh.cpp

@@ -109,10 +109,10 @@ Mesh* Mesh::createQuadFullscreen()
 
     float vertices[] =
     {
-        x, y2,   0, 0,
-        x, y,    0, 1,
-        x2, y2,  1, 0,
-        x2, y,   1, 1
+        x, y2,   0, 1,
+        x, y,    0, 0,
+        x2, y2,  1, 1,
+        x2, y,   1, 0
     };
 
     VertexFormat::Element elements[] =

+ 204 - 3
gameplay/src/PhysicsVehicle.cpp

@@ -1,9 +1,13 @@
 #include "Base.h"
 #include "Game.h"
+#include "MathUtil.h"
 #include "Node.h"
 #include "PhysicsVehicle.h"
 #include "PhysicsVehicleWheel.h"
 
+#define AIR_DENSITY (1.2f)
+#define KPH_TO_MPS (1.0f / 3.6f)
+
 namespace gameplay
 {
 
@@ -76,7 +80,7 @@ private:
 };
 
 PhysicsVehicle::PhysicsVehicle(Node* node, const PhysicsCollisionShape::Definition& shape, const PhysicsRigidBody::Parameters& parameters)
-    : PhysicsCollisionObject(node)
+    : PhysicsCollisionObject(node), _speedSmoothed(0)
 {
     // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
     // that is where the rigid body gets added to the dynamics world.
@@ -86,7 +90,7 @@ PhysicsVehicle::PhysicsVehicle(Node* node, const PhysicsCollisionShape::Definiti
 }
 
 PhysicsVehicle::PhysicsVehicle(Node* node, PhysicsRigidBody* rigidBody)
-    : PhysicsCollisionObject(node)
+    : PhysicsCollisionObject(node), _speedSmoothed(0)
 {
     _rigidBody = rigidBody;
 
@@ -117,6 +121,42 @@ PhysicsVehicle* PhysicsVehicle::create(Node* node, Properties* properties)
         {
             vehicle->setDrivingForce(properties->getFloat());
         }
+        else if (strcmp(name, "steerdownSpeed") == 0)
+        {
+            vehicle->_steerdownSpeed = properties->getFloat();
+        }
+        else if (strcmp(name, "steerdownGain") == 0)
+        {
+            vehicle->_steerdownGain = properties->getFloat();
+        }
+        else if (strcmp(name, "brakedownStart") == 0)
+        {
+            vehicle->_brakedownStart = properties->getFloat();
+        }
+        else if (strcmp(name, "brakedownFull") == 0)
+        {
+            vehicle->_brakedownFull = properties->getFloat();
+        }
+        else if (strcmp(name, "drivedownStart") == 0)
+        {
+            vehicle->_drivedownStart = properties->getFloat();
+        }
+        else if (strcmp(name, "drivedownFull") == 0)
+        {
+            vehicle->_drivedownFull = properties->getFloat();
+        }
+        else if (strcmp(name, "boostSpeed") == 0)
+        {
+            vehicle->_boostSpeed = properties->getFloat();
+        }
+        else if (strcmp(name, "boostGain") == 0)
+        {
+            vehicle->_boostGain = properties->getFloat();
+        }
+        else if (strcmp(name, "downforce") == 0)
+        {
+            vehicle->_downforce = properties->getFloat();
+        }
         else
         {
             // Ignore this case (we've already parsed the rigid body parameters).
@@ -134,6 +174,11 @@ void PhysicsVehicle::initialize()
     setSteeringGain(0.5f);
     setBrakingForce(350.0f);
     setDrivingForce(2000.0f);
+    setSteerdown(0, 1);
+    setBrakedown(1000, 0);
+    setDrivedown(1000, 0);
+    setBoost(0, 1);
+    setDownforce(0);
 
     // Create the vehicle and add it to world
     btRigidBody* body = static_cast<btRigidBody*>(_rigidBody->getCollisionObject());
@@ -204,8 +249,28 @@ float PhysicsVehicle::getSpeedKph() const
     return _vehicle->getCurrentSpeedKmHour();
 }
 
-void PhysicsVehicle::update(float steering, float braking, float driving)
+float PhysicsVehicle::getSpeedSmoothKph() const
 {
+    return _speedSmoothed;
+}
+
+void PhysicsVehicle::update(float elapsedTime, float steering, float braking, float driving)
+{
+    float v = getSpeedKph();
+    MathUtil::smooth(&_speedSmoothed, v, elapsedTime, 0, 1200);
+    applyDownforce();
+
+    // Adjust control inputs based on vehicle speed.
+    steering = getSteering(v, steering);
+    driving = getDriving(v, driving, braking);
+    braking = getBraking(v, braking);
+
+    // Allow braking to take precedence over driving.
+    if (driving > 0 && braking > 0)
+    {
+        driving = 0;
+    }
+
     PhysicsVehicleWheel* wheel;
     for (int i = 0; i < _vehicle->getNumWheels(); i++)
     {
@@ -221,10 +286,72 @@ void PhysicsVehicle::update(float steering, float braking, float driving)
             _vehicle->setBrake(braking * _brakingForce, i);
         }
 
+        wheel->update(elapsedTime);
         wheel->transform(wheel->getNode());
     }
 }
 
+void PhysicsVehicle::reset()
+{
+    _rigidBody->setLinearVelocity(Vector3::zero());
+    _rigidBody->setAngularVelocity(Vector3::zero());
+    _speedSmoothed = 0;
+}
+
+float PhysicsVehicle::getSteering(float v, float rawSteering) const
+{
+    float gain = 1;
+    if (_steerdownSpeed > MATH_FLOAT_SMALL)
+    {
+        gain = max(_steerdownGain, 1 - (1 - _steerdownGain) * fabs(v) / _steerdownSpeed);
+    }
+
+    return rawSteering * gain;
+}
+
+float PhysicsVehicle::getBraking(float v, float rawBraking) const
+{
+    float reduc = 0;
+    float delta = _brakedownFull - _brakedownStart;
+    if (delta > MATH_FLOAT_SMALL)
+    {
+        reduc = max(0.0f, (v - _brakedownStart) / delta);
+        reduc *= reduc;
+    }
+
+    return max(0.0f, rawBraking - reduc);
+}
+
+float PhysicsVehicle::getDriving(float v, float rawDriving, float rawBraking) const
+{
+    float reduc = 0;
+    float delta = _drivedownFull - _drivedownStart;
+    if (rawBraking == 0 && delta > MATH_FLOAT_SMALL)
+    {
+        reduc = max(0.0f, (v - _drivedownStart) / delta);
+        reduc *= reduc;
+    }
+
+    float gain = 1;
+    if (_boostSpeed > MATH_FLOAT_SMALL)
+    {
+        gain = max(1.0f, _boostGain - (_boostGain - 1) * fabs(v) / _boostSpeed);
+    }
+
+    return gain * rawDriving - reduc;
+}
+
+void PhysicsVehicle::applyDownforce()
+{
+    float v = _speedSmoothed * KPH_TO_MPS;
+
+    // dynamic pressure
+    float q = 0.5f * AIR_DENSITY * v * v;
+
+    // _downforce is the product of reference area and the aerodynamic coefficient
+    _rigidBody->applyForce(Vector3(0, -_downforce * q, 0));
+}
+
 float PhysicsVehicle::getSteeringGain() const
 {
     return _steeringGain;
@@ -255,4 +382,78 @@ void PhysicsVehicle::setDrivingForce(float drivingForce)
     _drivingForce = drivingForce;
 }
 
+float PhysicsVehicle::getSteerdownSpeed() const
+{
+    return _steerdownSpeed;
+}
+
+float PhysicsVehicle::getSteerdownGain() const
+{
+    return _steerdownGain;
+}
+
+void PhysicsVehicle::setSteerdown(float steerdownSpeed, float steerdownGain)
+{
+    _steerdownSpeed = steerdownSpeed;
+    _steerdownGain = steerdownGain;
+}
+
+float PhysicsVehicle::getBrakedownStart() const
+{
+    return _brakedownStart;
+}
+
+float PhysicsVehicle::getBrakedownFull() const
+{
+    return _brakedownFull;
+}
+
+void PhysicsVehicle::setBrakedown(float brakedownStart, float brakedownFull)
+{
+    _brakedownStart = brakedownStart;
+    _brakedownFull = brakedownFull;
+}
+
+float PhysicsVehicle::getDrivedownStart() const
+{
+    return _drivedownStart;
+}
+
+float PhysicsVehicle::getDrivedownFull() const
+{
+    return _drivedownFull;
+}
+
+void PhysicsVehicle::setDrivedown(float drivedownStart, float drivedownFull)
+{
+    _drivedownStart = drivedownStart;
+    _drivedownFull = drivedownFull;
+}
+
+float PhysicsVehicle::getBoostSpeed() const
+{
+    return _boostSpeed;
+}
+
+float PhysicsVehicle::getBoostGain() const
+{
+    return _boostGain;
+}
+
+void PhysicsVehicle::setBoost(float boostSpeed, float boostGain)
+{
+    _boostSpeed = boostSpeed;
+    _boostGain = boostGain;
+}
+
+float PhysicsVehicle::getDownforce() const
+{
+    return _downforce;
+}
+
+void PhysicsVehicle::setDownforce(float downforce)
+{
+    _downforce = downforce;
+}
+
 }

+ 217 - 1
gameplay/src/PhysicsVehicle.h

@@ -33,6 +33,25 @@ class PhysicsVehicleWheel;
         steeringGain   = <float>    // steering at full deflection
         brakingForce   = <float>    // braking force at full braking
         drivingForce   = <float>    // driving force at full throttle
+
+        // Steering gain reduction with speed (optional)
+        steerdownSpeed = <float>    // steering gain fades to this point
+        steerdownGain  = <float>    // gain value at that point (less than 1)
+
+        // Brake force reduction at high speeds (optional)
+        brakedownStart = <float>    // braking fades above this speed
+        brakedownFull  = <float>    // braking is fully faded at this speed
+
+        // Driving force reduction at high speeds (optional)
+        drivedownStart = <float>    // driving force fades above this speed
+        drivedownFull  = <float>    // driving force is fully faded at this speed
+
+        // Driving force boost at low speeds (optional)
+        boostSpeed     = <float>    // Boost fades to 1 at this point
+        boostGain      = <float>    // Boost at zero speed (greater than 1)
+
+        // Aerodynamic downforce effect (optional)
+        downforce      = <float>    // proportional control of downforce
     }
  @endverbatim
  */
@@ -80,15 +99,27 @@ public:
      */
     float getSpeedKph() const;
 
+    /**
+     * Returns a lagged version of vehicle speed in kilometers per hour,
+     * for example that might be used to control engine sounds.
+     */
+    float getSpeedSmoothKph() const;
+
     /**
      * Updates the vehicle state using the specified normalized command
      * inputs, and updates the transform on the visual node for each wheel.
      *
+     * @param elapsedTime The elapsed game time.
      * @param steering steering command (-1 to 1).
      * @param braking braking command (0 to 1).
      * @param driving net drivetrain command (0 to 1).
      */
-    void update(float steering, float braking, float driving);
+    void update(float elapsedTime, float steering, float braking, float driving);
+
+    /**
+     * Resets the vehicle's state, for example in preparation for a reposition.
+     */
+    void reset();
 
     /**
      * Gets steering gain at full deflection.
@@ -132,6 +163,151 @@ public:
      */
     void setDrivingForce(float drivingForce);
 
+    /**
+     * Returns speed at the point of reduced steering, in km/h.
+     * A point of reduced steering is defined by speed and gain.
+     * Steering authority will reduce linearly with speed up to
+     * this point, and remain constant above that.
+     *
+     * @return speed at the point of reduced steering, in km/h.
+     */
+    float getSteerdownSpeed() const;
+
+    /**
+     * Returns gain at the point of reduced steering, typically
+     * less than 1.
+     * A point of reduced steering is defined by speed and gain.
+     * Steering authority will reduce linearly with speed up to
+     * this point, and remain constant above that.
+     *
+     * @return gain at the point of reduced steering.
+     */
+    float getSteerdownGain() const;
+
+    /**
+     * Sets the point of reduced steering, defined by speed and
+     * gain. Typically the gain value is less than 1.
+     * Steering authority will reduce linearly with speed up to
+     * this point, and remain constant above that.
+     *
+     * @param steerdownSpeed speed at the point of reduced steering,
+     *     in km/h.
+     * @param steerdownGain gain at the point of reduced steering.
+     *     A gain of 1 will effectively disable the feature.
+     */
+    void setSteerdown(float steerdownSpeed, float steerdownGain);
+
+    /**
+     * Returns speed where braking starts to fade, in km/h.
+     *
+     * @return speed where braking starts to fade, in km/h.
+     */
+    float getBrakedownStart() const;
+
+    /**
+     * Returns speed where braking is fully faded, in km/h.
+     * This speed is typically greater than the brakedownStart
+     * speed.
+     *
+     * @return speed where braking is fully faded, in km/h.
+     */
+    float getBrakedownFull() const;
+
+    /**
+     * Sets points that control fade of brake force with speed,
+     * in km/h.
+     *
+     * @param brakedownStart braking fades above this speed.
+     *     A very large value will effectively disable the feature.
+     * @param brakedownFull braking is fully faded at this speed.
+     *     This speed is typically greater than the brakedownStart
+     *     speed.
+     */
+    void setBrakedown(float brakedownStart, float brakedownFull);
+
+    /**
+     * Returns speed where driving force starts to fade, in km/h.
+     *
+     * @return speed where driving force starts to fade, in km/h.
+     */
+    float getDrivedownStart() const;
+
+    /**
+     * Returns speed where driving force is fully faded, in km/h.
+     * This speed is typically greater than the drivedownStart
+     * speed.
+     *
+     * @return speed where driving force is fully faded, in km/h.
+     */
+    float getDrivedownFull() const;
+
+    /**
+     * Sets points that control fade of driving force with speed,
+     * in km/h.
+     *
+     * @param drivedownStart driving force fades above this speed.
+     *     A very large value will effectively disable the feature.
+     * @param drivedownFull driving force is fully faded at this speed.
+     *     This speed is typically greater than the drivedownStart
+     *     speed.
+     */
+    void setDrivedown(float drivedownStart, float drivedownFull);
+
+    /**
+     * Returns upper limit of low-speed boost effect, in km/h.
+     * Driving force is boosted by a specified factor at zero speed,
+     * and that factor fades linearly with speed reaching 1 at
+     * this speed.
+     *
+     * @return upper limit of low-speed boost effect, in km/h.
+     */
+    float getBoostSpeed() const;
+
+    /**
+     * Returns boost gain at zero speed, typically greater than 1.
+     * Driving force is boosted by this factor at zero speed, and
+     * that factor fades linearly with speed reaching 1 at a
+     * specified speed.
+     *
+     * @return boost gain at zero speed.
+     */
+    float getBoostGain() const;
+
+    /**
+     * Sets parameters that define low-speed boost of the driving force.
+     * Driving force is boosted by the specified factor at zero speed,
+     * and that factor fades linearly with speed reaching 1 at the
+     * specified speed.
+     *
+     * @param boostSpeed upper limit of low-speed boost effect, in km/h.
+     * @param boostGain boost gain at zero speed, typically greater than 1.
+     *     A gain of 1 will effectively disable the feature.
+     */
+    void setBoost(float boostSpeed, float boostGain);
+
+    /**
+     * Returns the lumped constant that controls aerodynamic downforce.
+     * Technically speaking, this constant lumps together the reference
+     * area and the down-force coefficient, and is in world-units squared.
+     * The actual aerodynamic down-force is calculated as a function of
+     * current speed, and is proportional to this constant.
+     *
+     * @return the lumped constant that controls aerodynamic downforce.
+     */
+    float getDownforce() const;
+
+    /**
+     * Sets the lumped constant that controls aerodynamic downforce.
+     * Technically speaking, this constant lumps together the reference
+     * area and the down-force coefficient, and is in world-units squared.
+     * The actual aerodynamic down-force is calculated as a function of
+     * current speed, and is proportional to this constant.
+     *
+     * @param downforce the lumped constant that controls aerodynamic downforce.
+     *     A value of 0 will effectively disable this feature.
+     */
+    void setDownforce(float downforce);
+
 protected:
 
     /**
@@ -185,6 +361,36 @@ private:
      */
     void initialize();
 
+    /**
+     * Returns adjusted steering value.
+     *
+     * @param v vehicle speed.
+     * @param rawSteering raw steering command.
+     */
+    float getSteering(float v, float rawSteering) const;
+
+    /**
+     * Returns adjusted braking force value.
+     *
+     * @param v vehicle speed.
+     * @param rawBraking raw braking force command.
+     */
+    float getBraking(float v, float rawBraking) const;
+
+    /**
+     * Returns adjusted driving force value.
+     *
+     * @param v vehicle speed.
+     * @param rawDriving raw driving force command.
+     * @param rawBraking raw braking force command.
+     */
+    float getDriving(float v, float rawDriving, float rawBraking) const;
+
+    /**
+     * Applies effect of aerodynamic downforce.
+     */
+    void applyDownforce();
+
     /**
      * Destructor.
      */
@@ -193,6 +399,16 @@ private:
     float _steeringGain;
     float _brakingForce;
     float _drivingForce;
+    float _steerdownSpeed;
+    float _steerdownGain;
+    float _brakedownStart;
+    float _brakedownFull;
+    float _drivedownStart;
+    float _drivedownFull;
+    float _boostSpeed;
+    float _boostGain;
+    float _downforce;
+    float _speedSmoothed;
     PhysicsRigidBody* _rigidBody;
     btRaycastVehicle::btVehicleTuning _vehicleTuning;
     btVehicleRaycaster* _vehicleRaycaster;

+ 28 - 3
gameplay/src/PhysicsVehicleWheel.cpp

@@ -182,16 +182,41 @@ void PhysicsVehicleWheel::transform(Node* node) const
 {
     GP_ASSERT(_host);
     GP_ASSERT(_host->_vehicle);
+    GP_ASSERT(_host->_node);
+
+    const btTransform& trans = _host->_vehicle->getWheelInfo(_indexInHost).m_worldTransform;
+    const btVector3& pos = trans.getOrigin();
+    node->setRotation(_orientation);
+
+    // Use only the component parallel to the defined strut line
+    Vector3 strutLine;
+    getWheelDirection(&strutLine);
+    Vector3 wheelPos = _initialOffset;
+    _host->_node->getMatrix().transformPoint(&wheelPos);
+    node->setTranslation(wheelPos + strutLine*(strutLine.dot(_positionDelta) / strutLine.lengthSquared()));
+}
+
+void PhysicsVehicleWheel::update(float elapsedTime)
+{
+    GP_ASSERT(_host);
+    GP_ASSERT(_host->_vehicle);
+    GP_ASSERT(_host->_node);
 
     const btTransform& trans = _host->_vehicle->getWheelInfo(_indexInHost).m_worldTransform;
     const btQuaternion& rot = trans.getRotation();
     const btVector3& pos = trans.getOrigin();
-    node->setRotation(rot.x(), rot.y(), rot.z(), rot.w());
+    _orientation.set(rot.x(), rot.y(), rot.z(), rot.w());
 
-    // Ignore X and Z translation for wheel
+    Vector3 commandedPosition(pos.x(), pos.y(), pos.z());
     Vector3 wheelPos = _initialOffset;
     _host->_node->getMatrix().transformPoint(&wheelPos);
-    node->setTranslation(wheelPos.x, wheelPos.y, wheelPos.z);
+    commandedPosition -= wheelPos;
+
+    // Filter out noise from Bullet
+    Vector3 delta(_positionDelta, commandedPosition);
+    float threshold = getStrutRestLength() * 2.0f;
+    float responseTime = (delta.lengthSquared() > threshold*threshold) ? 0 : 60;
+    _positionDelta.smooth(commandedPosition, elapsedTime, responseTime);
 }
 
 bool PhysicsVehicleWheel::isFront() const

+ 9 - 0
gameplay/src/PhysicsVehicleWheel.h

@@ -326,10 +326,19 @@ private:
      */
     void addToVehicle(btRaycastVehicle* vehicle);
 
+    /**
+     * Update state of this wheel, per frame.
+     *
+     * @param elapsedTime The elapsed game time.
+     */
+    void update(float elapsedTime);
+
     PhysicsRigidBody* _rigidBody;
     PhysicsVehicle* _host;
     unsigned int _indexInHost;
     Vector3 _initialOffset;
+    Vector3 _positionDelta;
+    Quaternion _orientation;
 };
 
 }

+ 823 - 33
gameplay/src/PlatformMacOSX.mm

@@ -7,14 +7,24 @@
 #include "Form.h"
 #include "ScriptController.h"
 #include <unistd.h>
+#include <IOKit/hid/IOHIDLib.h>
 #import <Cocoa/Cocoa.h>
 #import <QuartzCore/CVDisplayLink.h>
 #import <OpenGL/OpenGL.h>
 #import <mach/mach_time.h>
+#import <Foundation/Foundation.h>
+
+// These should probably be moved to a platform common file
+#define SONY_USB_VENDOR_ID          0x54c
+#define SONY_USB_PS3_PRODUCT_ID     0x268
+
 
 using namespace std;
 using namespace gameplay;
 
+@class View;
+@class OSXGamepad;
+
 // Default to 720p
 static int __width = 1280;
 static int __height = 720;
@@ -40,6 +50,29 @@ static void* __attachToWindow = NULL;
 static bool __mouseCaptured = false;
 static CGPoint __mouseCapturePoint;
 static bool __cursorVisible = true;
+static View* __view = NULL;
+
+static NSMutableDictionary *__activeGamepads = NULL;
+static NSMutableArray *__gamepads = NULL;
+static IOHIDManagerRef __hidManagerRef = NULL;
+
+// Gamepad Helper Function
+OSXGamepad *gamepadForLocationID(NSNumber *locationID);
+OSXGamepad *gamepadForLocationIDValue(unsigned int locationIDValue);
+OSXGamepad *gamepadForGameHandle(int gameHandle);
+
+
+// IOHid Helper Functions
+CFMutableDictionaryRef IOHIDCreateDeviceMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage);
+CFStringRef IOHIDDeviceGetStringProperty(IOHIDDeviceRef deviceRef, CFStringRef key);
+int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key);
+
+// IOHid Callbacks
+static void hidDeviceDiscoveredCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
+static void hidDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
+static void hidDeviceValueAvailableCallback(void *inContext, IOReturn inResult,  void *inSender);
+
+
 
 double getMachTimeInMilliseconds()
 {
@@ -54,7 +87,537 @@ double getMachTimeInMilliseconds()
     return ((double)mach_absolute_time() * (double)s_timebase_info.numer) / (kOneMillion * (double)s_timebase_info.denom);
 }
 
-@class View;
+
+@interface OSXGamepadAxis : NSObject
+{
+    IOHIDElementRef e;
+    CFIndex v;
+    CFIndex logMin;
+    CFIndex logMax;
+}
++ gamepadAxisWithAxisElement:(IOHIDElementRef)element;
+- initWithAxisElement:(IOHIDElementRef)element;
+- (IOHIDElementRef)element;
+- (IOHIDElementCookie)cookie;
+- (uint32_t)usage;
+- (uint32_t)usagePage;
+- (CFIndex)logicalMinimum;
+- (CFIndex)logicalMaximum;
+
+- (float)calibratedValue;
+- (CFIndex)value;
+- (void)setValue:(CFIndex)value;
+@end
+@implementation OSXGamepadAxis
++ gamepadAxisWithAxisElement:(IOHIDElementRef)element
+{
+    return [[[[self class] alloc] initWithAxisElement:element] autorelease];
+}
+- initWithAxisElement:(IOHIDElementRef)element
+{
+    if((self = [super init]))
+    {
+        e = (IOHIDElementRef)CFRetain(element);
+    }
+    return self;
+}
+- (void)dealloc
+{
+    CFRelease(e);
+    [super dealloc];
+}
+- (IOHIDElementRef)element
+{
+    return e;
+}
+- (IOHIDElementCookie)cookie
+{
+    return IOHIDElementGetCookie(e);
+}
+- (bool)isHatSwitch {
+    return (IOHIDElementGetUsage(e) == kHIDUsage_GD_Hatswitch);
+}
+- (uint32_t)usage
+{
+    return IOHIDElementGetUsage(e);
+}
+- (uint32_t)usagePage
+{
+    return IOHIDElementGetUsagePage(e);
+}
+- (CFIndex)logicalMinimum
+{
+    return IOHIDElementGetLogicalMin(e);    
+}
+- (CFIndex)logicalMaximum
+{
+    return IOHIDElementGetLogicalMax(e);
+}
+- (float)calibratedValue
+{
+    float cmax = 2.0f;
+    float cmin = 0.0f;
+    return ((((v - [self logicalMinimum]) * (cmax - cmin)) / ([self logicalMaximum] - [self logicalMinimum])) + cmin - 1.0f);    
+}
+- (CFIndex)value
+{
+    return v;
+}
+- (void)setValue:(CFIndex)value
+{
+    v = value;
+}
+@end
+
+@interface OSXGamepadButton : NSObject
+{
+    IOHIDElementRef e;
+    IOHIDElementRef te;
+    bool state;
+    int triggerValue;
+}
++ gamepadButtonWithButtonElement:(IOHIDElementRef)element;
+- initWithButtonElement:(IOHIDElementRef)element;
+- (void)setTriggerElement:(IOHIDElementRef)element;
+- (IOHIDElementRef)element;
+- (IOHIDElementCookie)cookie;
+- (IOHIDElementRef)triggerElement;
+- (IOHIDElementCookie)triggerCookie;
+
+- (bool)isTriggerButton;
+- (uint32_t)usage;
+- (uint32_t)usagePage;
+- (int)stateValue;
+- (float)calibratedStateValue;
+- (void)setStateValue:(int)value;
+- (bool)state;
+- (void)setState:(bool)state;
+@end
+@implementation OSXGamepadButton
++ gamepadButtonWithButtonElement:(IOHIDElementRef)element
+{
+    return [[[[self class] alloc] initWithButtonElement:element] autorelease];
+}
+- initWithButtonElement:(IOHIDElementRef)element
+{
+    if((self = [super init]))
+    {
+        e = (IOHIDElementRef)CFRetain(element);
+        te = NULL;
+        state = false;
+    }
+    return self;
+}
+- (void)dealloc
+{
+    CFRelease(e);
+    if(te != NULL) CFRelease(te);
+    [super dealloc];
+}
+- (void)setTriggerElement:(IOHIDElementRef)element {
+    if(te)
+    {
+        CFRelease(te);
+        te = NULL;
+    }
+    if(element)
+    {
+        te = (IOHIDElementRef)CFRetain(element);
+    }
+}
+- (IOHIDElementRef)element
+{
+    return e;
+}
+- (IOHIDElementCookie)cookie
+{
+    return IOHIDElementGetCookie(e);
+}
+- (IOHIDElementRef)triggerElement
+{
+    return te;
+}
+- (IOHIDElementCookie)triggerCookie
+{
+    return IOHIDElementGetCookie(te);
+}
+- (bool)isTriggerButton
+{
+    return (te != NULL);
+}
+- (uint32_t)usage
+{
+    return IOHIDElementGetUsage(e);
+}
+- (uint32_t)usagePage
+{
+    return IOHIDElementGetUsagePage(e);
+}
+- (void)setStateValue:(int)value {
+    triggerValue = value;
+}
+- (int)stateValue
+{
+    return triggerValue;
+}
+- (float)calibratedStateValue
+{
+    return (float)triggerValue; // TODO: Need to figure out expected range
+}
+- (bool)state
+{
+    return state;
+}
+- (void)setState:(bool)s
+{
+    state = s;
+}
+@end
+
+@interface OSXGamepad : NSObject
+{
+    IOHIDDeviceRef hidDeviceRef;
+    IOHIDQueueRef queueRef;
+    NSMutableArray *buttons;
+    NSMutableArray *triggerButtons;
+    NSMutableArray *axes;
+}
+@property (assign) IOHIDDeviceRef hidDeviceRef;
+@property (assign) IOHIDQueueRef queueRef;
+@property (retain) NSMutableArray *buttons;
+@property (retain) NSMutableArray *triggerButtons;
+@property (retain) NSMutableArray *axes;
+
+- initWithDevice:(IOHIDDeviceRef)rawDevice;
+- (IOHIDDeviceRef)rawDevice;
+- (NSNumber*)locationID;
+
+- (void)initializeGamepadElements;
+- (OSXGamepadButton*)buttonWithCookie:(IOHIDElementCookie)cookie;
+
+- (bool)startListening;
+- (void)stopListening;
+
+- (NSString *)identifierName;
+- (NSString *)productName;
+- (NSString *)manufacturerName;
+- (NSString *)serialNumber;
+- (int)vendorID;
+- (int)productID;
+
+- (NSUInteger)numberOfAxes;
+- (NSUInteger)numberOfSticks;
+- (NSUInteger)numberOfButtons;
+- (NSUInteger)numberOfTriggerButtons;
+- (OSXGamepadAxis*)axisAtIndex:(NSUInteger)index;
+- (OSXGamepadButton*)buttonAtIndex:(NSUInteger)index;
+- (OSXGamepadButton*)triggerButtonAtIndex:(NSUInteger)index;
+@end
+
+@implementation OSXGamepad
+
+@synthesize hidDeviceRef;
+@synthesize queueRef;
+@synthesize buttons;
+@synthesize triggerButtons;
+@synthesize axes;
+
+- initWithDevice:(IOHIDDeviceRef)rawDevice
+{
+    if((self = [super init]))
+    {
+        [self setButtons:[NSMutableArray array]];
+        [self setTriggerButtons:[NSMutableArray array]];
+        [self setAxes:[NSMutableArray array]];
+
+        CFRetain(rawDevice);
+        IOHIDQueueRef queue = IOHIDQueueCreate(CFAllocatorGetDefault(), rawDevice, 10, kIOHIDOptionsTypeNone);
+        [self setHidDeviceRef:rawDevice];
+        [self setQueueRef:queue];
+        
+        [self initializeGamepadElements];
+        [self startListening];
+    }
+    return self;
+}
+- (void)dealloc
+{
+    [self stopListening];
+    
+    CFRelease([self rawDevice]);
+    CFRelease([self queueRef]);
+    [self setQueueRef:NULL];
+    [self setHidDeviceRef:NULL];
+    
+    [self setButtons:NULL];
+    [self setTriggerButtons:NULL];
+    [self setAxes:NULL];
+    [super dealloc];
+}
+- (IOHIDDeviceRef)rawDevice
+{
+    return [self hidDeviceRef];
+}
+- (NSNumber*)locationID
+{
+    return (NSNumber*)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDLocationIDKey));
+}
+
+- (void)initializeGamepadElements
+{
+    CFArrayRef elements = IOHIDDeviceCopyMatchingElements([self rawDevice], NULL, kIOHIDOptionsTypeNone);
+    for(int i = 0; i < CFArrayGetCount(elements); i++)
+    {
+        IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
+        IOHIDElementType type = IOHIDElementGetType(hidElement);
+
+        if (type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis)
+        {
+            uint32_t pageUsage = IOHIDElementGetUsage(hidElement);
+            IOHIDElementCookie cookie = IOHIDElementGetCookie(hidElement);
+
+            switch(pageUsage)
+            {
+                case kHIDUsage_GD_X:
+                case kHIDUsage_GD_Y:
+                case kHIDUsage_GD_Z:
+                case kHIDUsage_GD_Rx:
+                case kHIDUsage_GD_Ry:
+                case kHIDUsage_GD_Rz:
+                {
+                    OSXGamepadAxis *axis = [OSXGamepadAxis gamepadAxisWithAxisElement:hidElement];
+                    [[self axes] addObject:axis];
+                }
+                    break;
+                default:
+                    // Ignore the pointers
+                    // Note: Some of the pointers are for the 6-axis accelerometer in a PS3 controller
+                    // Note: L2/R2 triggers are at cookie 39 and 40 base 10 tied to 9 and 10 button elements
+                    break;
+            }
+
+        }
+        if(type == kIOHIDElementTypeInput_Button)
+        {
+            OSXGamepadButton *button = [OSXGamepadButton gamepadButtonWithButtonElement:hidElement];
+            [[self buttons] addObject:button];
+        }
+    }
+    // Go back and get proprietary information (e.g. triggers) and asscoaite with appropriate values
+    // Example for other trigger buttons
+    uint32_t vendorID = [self vendorID];
+    uint32_t productID = [self productID];
+    for(int i = 0; i < CFArrayGetCount(elements); i++)
+    {
+        IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
+        IOHIDElementType type = IOHIDElementGetType(hidElement);
+        IOHIDElementCookie cookie = IOHIDElementGetCookie(hidElement);
+        
+        // Gamepad specific code
+        // Not sure if there is a better way to associate buttons and misc hid elements :/
+        if(vendorID == SONY_USB_VENDOR_ID && productID == SONY_USB_PS3_PRODUCT_ID)
+        {
+            if((unsigned long)cookie == 39)
+            {
+                OSXGamepadButton *leftTrigger = [self buttonWithCookie:(IOHIDElementCookie)9];
+                if(leftTrigger)
+                {
+                    [leftTrigger setTriggerElement:hidElement];
+                    [[self triggerButtons] addObject:leftTrigger];
+                    //[[self buttons] removeObject:leftTrigger]; Defer to gamepad team on this line..  not sure how they intend to tackle
+                }
+            }
+            if((unsigned long)cookie == 40)
+            {
+                OSXGamepadButton *rightTrigger = [self buttonWithCookie:(IOHIDElementCookie)10];
+                if(rightTrigger)
+                {
+                    [rightTrigger setTriggerElement:hidElement];
+                    [[self triggerButtons] addObject:rightTrigger];
+                    //[[self buttons] removeObject:rightTrigger];
+                }
+            }
+        }
+    }
+    
+}
+- (OSXGamepadButton*)buttonWithCookie:(IOHIDElementCookie)cookie {
+    for(OSXGamepadButton *b in [self buttons]) {
+        if([b cookie] == cookie) return b;
+    }
+    return NULL;
+}
+
+- (bool)startListening
+{
+    IOReturn kr = IOHIDDeviceOpen([self hidDeviceRef], kIOHIDOptionsTypeNone);
+    if(kr != 0) {
+        return false;
+    }
+    IOHIDDeviceScheduleWithRunLoop([self hidDeviceRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    
+    IOHIDQueueStart([self queueRef]);
+    IOHIDQueueRegisterValueAvailableCallback([self queueRef], hidDeviceValueAvailableCallback, self);
+    
+    CFArrayRef elements = (CFArrayRef)[self watchedElements];
+    for(int i = 0; i < CFArrayGetCount(elements); i++)
+    {
+        IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
+        IOHIDQueueAddElement([self queueRef], hidElement);
+    }
+    IOHIDQueueScheduleWithRunLoop([self queueRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    
+    return true;
+}
+- (void)stopListening
+{
+    IOHIDQueueUnscheduleFromRunLoop([self queueRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDQueueStop([self queueRef]);
+    
+    IOHIDDeviceUnscheduleFromRunLoop([self hidDeviceRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDDeviceClose([self hidDeviceRef], kIOHIDOptionsTypeNone);
+}
+
+- (NSString *)identifierName
+{
+    NSString *idName = NULL;
+    if(idName == NULL) idName = [self productName];
+    if(idName == NULL) idName = [self manufacturerName];
+    if(idName == NULL) idName = [self serialNumber];
+    if(idName == NULL) idName = [NSString stringWithFormat:@"%d-%d", [self vendorID], [self productID]];
+    return idName;
+}
+
+- (NSString *)productName {
+    CFStringRef productName = (CFStringRef)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDProductKey));
+    if(productName == NULL || CFGetTypeID(productName) != CFStringGetTypeID()) {
+        return NULL;
+    }
+    return (NSString*)productName;
+}
+- (NSString *)manufacturerName {
+    CFStringRef manufacturerName = (CFStringRef)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDManufacturerKey));
+    if(manufacturerName == NULL || CFGetTypeID(manufacturerName) != CFStringGetTypeID()) {
+        return NULL;
+    }
+    return (NSString*)manufacturerName;
+}
+- (NSString *)serialNumber {
+    CFStringRef serialNumber = (CFStringRef)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDSerialNumberKey));
+    if(serialNumber == NULL || CFGetTypeID(serialNumber) != CFStringGetTypeID()) {
+        return NULL;
+    }
+    return (NSString*)serialNumber;
+}
+
+
+- (int)vendorID
+{
+    return IOHIDDeviceGetIntProperty([self rawDevice], CFSTR(kIOHIDVendorIDKey));
+}
+- (int)productID
+{
+    return IOHIDDeviceGetIntProperty([self rawDevice], CFSTR(kIOHIDProductIDKey));
+}
+
+
+- (NSUInteger)numberOfAxes
+{
+    return [[self axes] count];
+}
+- (NSUInteger)numberOfSticks
+{
+    return ([[self axes] count] / 2);
+}
+- (NSUInteger)numberOfButtons
+{
+    return [[self buttons] count];
+}
+- (NSUInteger)numberOfTriggerButtons
+{
+    return [[self triggerButtons] count];
+}
+
+- (OSXGamepadButton*)triggerButtonAtIndex:(NSUInteger)index
+{
+    OSXGamepadButton *b = NULL;
+    if(index < [[self triggerButtons] count])
+    {
+        b = [[self triggerButtons] objectAtIndex:index];
+    }
+    return b;
+}
+
+- (OSXGamepadAxis*)axisAtIndex:(NSUInteger)index
+{
+    OSXGamepadAxis *a = NULL;
+    if(index < [[self axes] count])
+    {
+        a = [[self axes] objectAtIndex:index];
+    }
+    return a;
+}
+- (OSXGamepadButton*)buttonAtIndex:(NSUInteger)index
+{
+    OSXGamepadButton *b = NULL;
+    if(index < [[self buttons] count])
+    {
+        b = [[self buttons] objectAtIndex:index];
+    }
+    return b;
+}
+- (NSArray*)watchedElements
+{
+    NSMutableArray *r = [NSMutableArray array];
+    for(OSXGamepadButton *b in [self buttons])
+    {
+        [r addObject:(id)[b element]];
+    }
+    for(OSXGamepadAxis *a in [self axes])
+    {
+        [r addObject:(id)[a element]];
+    }
+    return [NSArray arrayWithArray:r];
+}
+- (void)hidValueAvailable:(IOHIDValueRef)value
+{
+    IOHIDElementRef element = IOHIDValueGetElement(value);
+	IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
+    
+    if(IOHIDValueGetLength(value) > 4) return; // saftey precaution for PS3 cotroller
+    CFIndex integerValue = IOHIDValueGetIntegerValue(value);
+    
+    for(OSXGamepadAxis *a in [self axes])
+    {
+        if([a cookie] == cookie)
+        {
+            [a setValue:integerValue];
+        }
+    }
+    
+    for(OSXGamepadButton *b in [self buttons])
+    {
+        if([b cookie] == cookie)
+        {
+            [b setState:(bool)integerValue];
+            break;
+        }
+    }
+    
+    for(OSXGamepadButton *b in [self triggerButtons])
+    {
+        if([b triggerCookie] == cookie)
+        {
+            [b setStateValue:integerValue];
+            break;
+        }
+    }
+
+}
+
+
+@end
+
 
 @interface View : NSOpenGLView <NSWindowDelegate>
 {
@@ -66,10 +629,8 @@ double getMachTimeInMilliseconds()
     Game* _game;
     unsigned int _gestureEvents;    
 }
-
 @end
 
-static View* __view = NULL;
 
 @implementation View
 
@@ -486,8 +1047,8 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
             return Keyboard::KEY_F10;
         
         // MACOS reserved:
-        //return Keyboard::KEY_F11;
-        //return Keyboard::KEY_F12;
+        // return Keyboard::KEY_F11;
+        // return Keyboard::KEY_F12;
         // return Keyboard::KEY_PAUSE;
         // return Keyboard::KEY_SCROLL_LOCK;
             
@@ -680,25 +1241,6 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
     [gameLock unlock];
 }
 
-- (void)swipeWithEvent:(NSEvent *)event
-{
-    if([self isGestureRegistered:Gesture::GESTURE_SWIPE] == false) return;
-    /**
-     * Gesture callback on Gesture::SWIPE events.
-     *
-     * @param x The x-coordinate of the start of the swipe.
-     * @param y The y-coordinate of the start of the swipe.
-     * @param direction The direction of the swipe
-     *
-     * @see Gesture::SWIPE_DIRECTION_UP
-     * @see Gesture::SWIPE_DIRECTION_DOWN
-     * @see Gesture::SWIPE_DIRECTION_LEFT
-     * @see Gesture::SWIPE_DIRECTION_RIGHT
-     */
-    //[gameLock lock];
-    //virtual void gestureSwipeEvent(int x, int y, int direction);
-    //[gameLock unlock];
-}
 
 @end
 
@@ -730,12 +1272,36 @@ extern void print(const char* format, ...)
 Platform::Platform(Game* game)
 : _game(game)
 {
+    __activeGamepads = [[NSMutableDictionary alloc] init];
+    __gamepads = [[NSMutableArray alloc] init];
+    __hidManagerRef = IOHIDManagerCreate(CFAllocatorGetDefault(), kIOHIDOptionsTypeNone);
+    IOHIDManagerRegisterDeviceMatchingCallback(__hidManagerRef, hidDeviceDiscoveredCallback, NULL);
+    IOHIDManagerRegisterDeviceRemovalCallback(__hidManagerRef, hidDeviceRemovalCallback, NULL);
+    
+    CFDictionaryRef matchingCFDictRef = IOHIDCreateDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
+    if (matchingCFDictRef) IOHIDManagerSetDeviceMatching(__hidManagerRef, matchingCFDictRef);
+    CFRelease(matchingCFDictRef);
+    
+    IOHIDManagerScheduleWithRunLoop(__hidManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOReturn kr = IOHIDManagerOpen(__hidManagerRef, kIOHIDOptionsTypeNone);
+    assert(kr == 0);
 }
 
+    
 Platform::~Platform()
 {
+    IOHIDManagerUnscheduleFromRunLoop(__hidManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+    IOHIDManagerClose(__hidManagerRef, kIOHIDOptionsTypeNone);
+    
+    CFRelease(__hidManagerRef);
+    __hidManagerRef = NULL;
+    [__activeGamepads release];
+    __activeGamepads = NULL;
+    [__gamepads release];
+    __gamepads = NULL;
 }
 
+    
 Platform* Platform::create(Game* game, void* attachToWindow)
 {
     __attachToWindow = attachToWindow;
@@ -999,7 +1565,11 @@ bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheel
 
 bool Platform::isGestureSupported(Gesture::GestureEvent evt)
 {
-    // TODO: Support Swipe and Tap
+    // Swipe unsupported as it is considered moving mouse cursor
+    // Two fingers is scrolling
+    // Three fingers is swipe, but is not always enabled on users system
+    // Tap not supported as it is considered a mouse click/button click
+    // on some systems making it difficult to differentiate 
     switch(evt)
     {
         case Gesture::GESTURE_PINCH:
@@ -1012,12 +1582,12 @@ bool Platform::isGestureSupported(Gesture::GestureEvent evt)
 
 void Platform::registerGesture(Gesture::GestureEvent evt)
 {
-    [__view registerGesture:evt];
+    [__view registerGesture:evt];   
 }
 
 void Platform::unregisterGesture(Gesture::GestureEvent evt)
 {
-    [__view unregisterGesture:evt];
+    [__view unregisterGesture:evt];        
 }
   
 bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
@@ -1027,63 +1597,283 @@ bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
 
 unsigned int Platform::getGamepadsConnected()
 {
-    return 0;
+    Game* game = Game::getInstance();
+    
+    if(game->isInitialized())
+    {
+        // Locate any newly connected devices
+        for(OSXGamepad* gamepad in __gamepads)
+        {
+            NSNumber* locationID = [gamepad locationID];
+            if([__activeGamepads objectForKey:locationID] == NULL)
+            {
+                unsigned int handle = game->createGamepad([[gamepad identifierName] cStringUsingEncoding:NSASCIIStringEncoding],
+                                                          [locationID unsignedIntValue],
+                                                          [gamepad numberOfButtons],
+                                                          [gamepad numberOfSticks],
+                                                          [gamepad numberOfTriggerButtons]);
+                NSNumber* handleObj = [NSNumber numberWithUnsignedInt:handle];
+                [__activeGamepads setObject:handleObj forKey:locationID];
+                game->gamepadEvent(Gamepad::CONNECTED_EVENT, game->getGamepad(handle));
+            }
+        }
+        
+        // Detect any disconnected gamepads
+        NSMutableArray* deadGamepads = [NSMutableArray array];
+        for(NSNumber* locationID in __activeGamepads)
+        {
+            OSXGamepad* gamepad = gamepadForLocationID(locationID);
+            if(gamepad == NULL)
+            {
+                NSNumber* gameHandle = [__activeGamepads objectForKey:locationID];
+                game->gamepadEvent(Gamepad::DISCONNECTED_EVENT, game->getGamepad([gameHandle unsignedIntValue]));
+                [deadGamepads addObject:locationID];
+            }
+        }
+        [__activeGamepads removeObjectsForKeys:deadGamepads];
+    }
+    return [__gamepads count];
 }
 
 bool Platform::isGamepadConnected(unsigned int gamepadHandle)
 {
-    return false;
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    return (gamepad != NULL);
 }
 
 const char* Platform::getGamepadId(unsigned int gamepadHandle)
 {
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    if(gamepad)
+    {
+        return [[gamepad productName] cStringUsingEncoding:NSASCIIStringEncoding];
+    }
     return NULL;
 }
 
 unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
 {
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    if(gamepad)
+    {
+        return [gamepad numberOfButtons];
+    }
     return 0;
 }
 
 bool Platform::getGamepadButtonState(unsigned int gamepadHandle, unsigned int buttonIndex)
 {
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    OSXGamepadButton* button = [gamepad buttonAtIndex:buttonIndex];
+    if(button)
+    {
+        return [button state];
+    }
     return false;
 }
 
 unsigned int Platform::getGamepadJoystickCount(unsigned int gamepadHandle)
 {
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    if(gamepad)
+    {
+        return [gamepad numberOfSticks];
+    }
     return 0;
 }
 
 bool Platform::isGamepadJoystickActive(unsigned int gamepadHandle, unsigned int joystickIndex)
 {
-    return false;
+    return true;
 }
 
 float Platform::getGamepadJoystickAxisX(unsigned int gamepadHandle, unsigned int joystickIndex)
 {
-    return 0.0f;
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    OSXGamepadAxis* xAxis = [gamepad axisAtIndex:(joystickIndex*2)];
+    return [xAxis calibratedValue];
 }
 
 float Platform::getGamepadJoystickAxisY(unsigned int gamepadHandle, unsigned int joystickIndex)
 {
-    return 0.0f;
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    OSXGamepadAxis* yAxis = [gamepad axisAtIndex:((joystickIndex*2)+1)];
+    return [yAxis calibratedValue];
 }
 
 void Platform::getGamepadJoystickAxisValues(unsigned int gamepadHandle, unsigned int joystickIndex, Vector2* outValue)
 {
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    OSXGamepadAxis* xAxis = [gamepad axisAtIndex:(joystickIndex*2)];
+    OSXGamepadAxis* yAxis = [gamepad axisAtIndex:((joystickIndex*2)+1)];
+    if(outValue)
+    {
+        outValue->x = [xAxis calibratedValue];
+        outValue->y = [yAxis calibratedValue];
+    }
 }
 
 unsigned int Platform::getGamepadTriggerCount(unsigned int gamepadHandle)
 {
-    return 0;
+    OSXGamepad *gamepad = gamepadForLocationIDValue(gamepadHandle);
+    return [gamepad numberOfTriggerButtons];
 }
 
 float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int triggerIndex)
 {
+    OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
+    OSXGamepadButton* button = [gamepad triggerButtonAtIndex:triggerIndex];
+    if(button)
+    {
+        return [button stateValue];
+    }
     return 0.0f;
 }
 
 }
 
+
+OSXGamepad* gamepadForLocationID(NSNumber* locationID)
+{
+    OSXGamepad* fgamepad = NULL;
+    for(OSXGamepad* gamepad in __gamepads)
+    {
+        if([[gamepad locationID] isEqual:locationID])
+        {
+            fgamepad = gamepad;
+            break;
+        }
+    }
+    return fgamepad;
+}
+
+OSXGamepad* gamepadForLocationIDValue(unsigned int locationIDValue)
+{
+    return gamepadForLocationID([NSNumber numberWithUnsignedInt:locationIDValue]);
+}
+
+OSXGamepad* gamepadForGameHandle(int gameHandle)
+{
+    OSXGamepad* gamepad = NULL;
+    for(NSNumber* locationID in __activeGamepads)
+    {
+        NSNumber* handleID = [__activeGamepads objectForKey:locationID];
+        if([handleID integerValue] == gameHandle)
+        {
+            gamepad = gamepadForLocationID(locationID);
+            break;
+        }
+    }
+    return gamepad;
+}
+
+CFMutableDictionaryRef IOHIDCreateDeviceMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage) 
+{
+    // create a dictionary to add usage page/usages to
+    CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    if (result) {
+        if (inUsagePage) 
+        {
+            // Add key for device type to refine the matching dictionary.
+            CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage);
+            if (pageCFNumberRef) 
+            {
+                CFDictionarySetValue(result, CFSTR( kIOHIDDeviceUsagePageKey ), pageCFNumberRef);
+                CFRelease(pageCFNumberRef);
+                
+                // note: the usage is only valid if the usage page is also defined
+                if (inUsage) 
+                {
+                    CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage);
+                    if (usageCFNumberRef) 
+                    {
+                        CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
+                        CFRelease(usageCFNumberRef);
+                    } 
+                    else 
+                    {
+                        fprintf(stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__);
+                    }
+                }
+            } 
+            else 
+            {
+                fprintf( stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__);
+            }
+        }
+    } 
+    else 
+    {
+        fprintf( stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__);
+    }
+    return result;
+}
+
+CFStringRef IOHIDDeviceGetStringProperty(IOHIDDeviceRef deviceRef, CFStringRef key) 
+{
+	CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
+	if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) 
+    {
+		return NULL;
+	}
+    return (CFStringRef)typeRef;
+}
+
+int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key) 
+{
+	CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
+	if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) 
+    {
+		return 0;
+	}
+    
+    int value;
+	CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
+	return value;
+}
+
+static void hidDeviceDiscoveredCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) 
+{
+    CFNumberRef locID = (CFNumberRef)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey));
+    if(locID)
+    {
+        OSXGamepad* gamepad = [[OSXGamepad alloc] initWithDevice:inIOHIDDeviceRef];
+        [__gamepads addObject:gamepad];
+    }
+    
+}
+
+static void hidDeviceRemovalCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) 
+{
+    int removeIndex = -1;
+    NSNumber *locID = (NSNumber*)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey));
+    if(locID)
+    {
+        for(int i = 0; i < [__gamepads count]; i++)
+        {
+            OSXGamepad* gamepad = [__gamepads objectAtIndex:i];
+            if([[gamepad locationID] isEqual:locID])
+            {
+                removeIndex = i;
+                break;
+            }
+        }
+    }
+    if(removeIndex >= 0)
+    {
+        [__gamepads removeObjectAtIndex:removeIndex];
+    }
+}
+
+static void hidDeviceValueAvailableCallback(void* inContext, IOReturn inResult,  void* inSender)
+{
+    OSXGamepad* d = (OSXGamepad*)inContext;
+    do
+    {
+        IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout( ( IOHIDQueueRef ) inSender, 0. );
+        if (!valueRef) break;
+        [d hidValueAvailable:valueRef];
+        CFRelease(valueRef); // Don't forget to release our HID value reference
+    } while (1);
+}
 #endif

+ 11 - 11
gameplay/src/TextBox.cpp

@@ -4,7 +4,7 @@
 namespace gameplay
 {
 
-TextBox::TextBox() : _textIndex(0), _lastKeypress(0), _fontSize(0), _caretImage(NULL)
+TextBox::TextBox() : _lastKeypress(0), _fontSize(0), _caretImage(NULL)
 {
 }
 
@@ -250,11 +250,11 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                 {
                     case Keyboard::KEY_BACKSPACE:
                     {
-                        if (_textIndex > 0)
+                        if (textIndex > 0)
                         {
-                            --_textIndex;
-                            _text.erase(_textIndex, 1);
-                            font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, _textIndex,
+                            --textIndex;
+                            _text.erase(textIndex, 1);
+                            font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                                 textAlignment, true, rightToLeft);
 
                             _dirty = true;
@@ -272,11 +272,11 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     default:
                     {
                         // Insert character into string.
-                        _text.insert(_textIndex, 1, (char)key);
+                        _text.insert(textIndex, 1, (char)key);
                         consume = true;
 
                         // Get new location of caret.
-                        font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, _textIndex + 1,
+                        font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex + 1,
                             textAlignment, true, rightToLeft);
 
                         if (key == ' ')
@@ -286,8 +286,8 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                                 _caretLocation.y >= _textBounds.y + _textBounds.height)
                             {
                                 // If not, undo the character insertion.
-                                _text.erase(_textIndex, 1);
-                                font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, _textIndex,
+                                _text.erase(textIndex, 1);
+                                font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                                     textAlignment, true, rightToLeft);
 
                                 // No need to check again.
@@ -302,8 +302,8 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                             textBounds.width >= _textBounds.width || textBounds.height >= _textBounds.height)
                         {
                             // If not, undo the character insertion.
-                            _text.erase(_textIndex, 1);
-                            font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, _textIndex,
+                            _text.erase(textIndex, 1);
+                            font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                                 textAlignment, true, rightToLeft);
 
                             // TextBox is not dirty.

+ 0 - 5
gameplay/src/TextBox.h

@@ -148,11 +148,6 @@ protected:
      * The previous position of the TextBox's caret.
      */
     Vector2 _prevCaretLocation;
-
-    /**
-     * The index into the TextBox's string that the caret is.
-     */
-    unsigned int _textIndex;
     
     /**
      * The last character that was entered into the TextBox.

+ 4 - 1
gameplay/src/ThemeStyle.cpp

@@ -271,7 +271,10 @@ void Theme::Style::Overlay::setTextColor(const Vector4& color)
 
 const Rectangle& Theme::Style::Overlay::getImageRegion(const char* id) const
 {
-    GP_ASSERT(_imageList);
+    if (!_imageList)
+    {
+        return Rectangle::empty();
+    }
 
     ThemeImage* image = _imageList->getImage(id);
     if (image)

+ 9 - 0
gameplay/src/Transform.cpp

@@ -577,6 +577,15 @@ void Transform::translateForward(float amount)
     translate(forward);
 }
 
+void Transform::translateSmooth(const Vector3& target, float elapsedTime, float responseTime)
+{
+    if (elapsedTime > 0)
+    {
+        _translation += (target - _translation) * (elapsedTime / (elapsedTime + responseTime));
+        dirty(DIRTY_TRANSLATION);
+    }
+}
+
 void Transform::transformPoint(Vector3* point)
 {
     getMatrix();

+ 13 - 0
gameplay/src/Transform.h

@@ -688,6 +688,19 @@ public:
      */
     void translateForward(float amount);
 
+    /**
+     * Translates the camera towards the given target using a smoothing function.
+     * The given response time determines the amount of smoothing (lag). A longer
+     * response time yields a smoother result and more lag. To force the camera to
+     * follow the target closely, provide a response time that is very small relative
+     * to the given elapsed time.
+     *
+     * @param target target value.
+     * @param elapsedTime elapsed time between calls.
+     * @param responseTime response time (in the same units as elapsedTime).
+     */
+    void translateSmooth(const Vector3& target, float elapsedTime, float responseTime);
+
     /**
      * Transforms the specified point and stores the
      * result in the original point.

+ 8 - 0
gameplay/src/Vector2.cpp

@@ -269,4 +269,12 @@ void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst)
     dst->y = v1.y - v2.y;
 }
 
+void Vector2::smooth(const Vector2& target, float elapsedTime, float responseTime)
+{
+    if (elapsedTime > 0)
+    {
+        *this += (target - *this) * (elapsedTime / (elapsedTime + responseTime));
+    }
+}
+
 }

+ 13 - 0
gameplay/src/Vector2.h

@@ -317,6 +317,19 @@ public:
      */
     static void subtract(const Vector2& v1, const Vector2& v2, Vector2* dst);
 
+    /**
+     * Updates this vector towards the given target using a smoothing function.
+     * The given response time determines the amount of smoothing (lag). A longer
+     * response time yields a smoother result and more lag. To force this vector to
+     * follow the target closely, provide a response time that is very small relative
+     * to the given elapsed time.
+     *
+     * @param target target value.
+     * @param elapsedTime elapsed time between calls.
+     * @param responseTime response time (in the same units as elapsedTime).
+     */
+    void smooth(const Vector2& target, float elapsedTime, float responseTime);
+
     /**
      * Calculates the sum of this vector with the given vector.
      * 

+ 8 - 0
gameplay/src/Vector3.cpp

@@ -307,4 +307,12 @@ void Vector3::subtract(const Vector3& v1, const Vector3& v2, Vector3* dst)
     dst->z = v1.z - v2.z;
 }
 
+void Vector3::smooth(const Vector3& target, float elapsedTime, float responseTime)
+{
+    if (elapsedTime > 0)
+    {
+        *this += (target - *this) * (elapsedTime / (elapsedTime + responseTime));
+    }
+}
+
 }

+ 13 - 0
gameplay/src/Vector3.h

@@ -347,6 +347,19 @@ public:
      */
     static void subtract(const Vector3& v1, const Vector3& v2, Vector3* dst);
 
+    /**
+     * Updates this vector towards the given target using a smoothing function.
+     * The given response time determines the amount of smoothing (lag). A longer
+     * response time yields a smoother result and more lag. To force this vector to
+     * follow the target closely, provide a response time that is very small relative
+     * to the given elapsed time.
+     *
+     * @param target target value.
+     * @param elapsedTime elapsed time between calls.
+     * @param responseTime response time (in the same units as elapsedTime).
+     */
+    void smooth(const Vector3& target, float elapsedTime, float responseTime);
+
     /**
      * Calculates the sum of this vector with the given vector.
      * 

+ 1 - 0
gameplay/src/gameplay.h

@@ -9,6 +9,7 @@
 #include "Gamepad.h"
 #include "FileSystem.h"
 #include "Bundle.h"
+#include "MathUtil.h"
 
 // Math
 #include "Rectangle.h"

+ 0 - 1
gameplay/src/lua/lua_Global.cpp

@@ -554,7 +554,6 @@ void luaRegister_lua_Global()
         ScriptUtil::registerConstantString("LAYOUT_FLOW", "LAYOUT_FLOW", scopePath);
         ScriptUtil::registerConstantString("LAYOUT_VERTICAL", "LAYOUT_VERTICAL", scopePath);
         ScriptUtil::registerConstantString("LAYOUT_ABSOLUTE", "LAYOUT_ABSOLUTE", scopePath);
-        ScriptUtil::registerConstantString("LAYOUT_SCROLL", "LAYOUT_SCROLL", scopePath);
     }
 
     // Register enumeration Light::Type.

+ 47 - 0
gameplay/src/lua/lua_Joint.cpp

@@ -142,6 +142,7 @@ void luaRegister_Joint()
         {"translate", lua_Joint_translate},
         {"translateForward", lua_Joint_translateForward},
         {"translateLeft", lua_Joint_translateLeft},
+        {"translateSmooth", lua_Joint_translateSmooth},
         {"translateUp", lua_Joint_translateUp},
         {"translateX", lua_Joint_translateX},
         {"translateY", lua_Joint_translateY},
@@ -6372,6 +6373,52 @@ int lua_Joint_translateLeft(lua_State* state)
     return 0;
 }
 
+int lua_Joint_translateSmooth(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<Vector3> param1 = ScriptUtil::getObjectPointer<Vector3>(2, "Vector3", true);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 4);
+
+                Joint* instance = getInstance(state);
+                instance->translateSmooth(*param1, param2, param3);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Joint_translateSmooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Joint_translateUp(lua_State* state)
 {
     // Get the number of parameters.

+ 1 - 0
gameplay/src/lua/lua_Joint.h

@@ -135,6 +135,7 @@ int lua_Joint_transformVector(lua_State* state);
 int lua_Joint_translate(lua_State* state);
 int lua_Joint_translateForward(lua_State* state);
 int lua_Joint_translateLeft(lua_State* state);
+int lua_Joint_translateSmooth(lua_State* state);
 int lua_Joint_translateUp(lua_State* state);
 int lua_Joint_translateX(lua_State* state);
 int lua_Joint_translateY(lua_State* state);

+ 0 - 5
gameplay/src/lua/lua_LayoutType.cpp

@@ -9,7 +9,6 @@ static const char* enumStringEmpty = "";
 static const char* luaEnumString_LayoutType_LAYOUT_FLOW = "LAYOUT_FLOW";
 static const char* luaEnumString_LayoutType_LAYOUT_VERTICAL = "LAYOUT_VERTICAL";
 static const char* luaEnumString_LayoutType_LAYOUT_ABSOLUTE = "LAYOUT_ABSOLUTE";
-static const char* luaEnumString_LayoutType_LAYOUT_SCROLL = "LAYOUT_SCROLL";
 
 Layout::Type lua_enumFromString_LayoutType(const char* s)
 {
@@ -19,8 +18,6 @@ Layout::Type lua_enumFromString_LayoutType(const char* s)
         return Layout::LAYOUT_VERTICAL;
     if (strcmp(s, luaEnumString_LayoutType_LAYOUT_ABSOLUTE) == 0)
         return Layout::LAYOUT_ABSOLUTE;
-    if (strcmp(s, luaEnumString_LayoutType_LAYOUT_SCROLL) == 0)
-        return Layout::LAYOUT_SCROLL;
     GP_ERROR("Invalid enumeration value '%s' for enumeration Layout::Type.", s);
     return Layout::LAYOUT_FLOW;
 }
@@ -33,8 +30,6 @@ const char* lua_stringFromEnum_LayoutType(Layout::Type e)
         return luaEnumString_LayoutType_LAYOUT_VERTICAL;
     if (e == Layout::LAYOUT_ABSOLUTE)
         return luaEnumString_LayoutType_LAYOUT_ABSOLUTE;
-    if (e == Layout::LAYOUT_SCROLL)
-        return luaEnumString_LayoutType_LAYOUT_SCROLL;
     GP_ERROR("Invalid enumeration value '%d' for enumeration Layout::Type.", e);
     return enumStringEmpty;
 }

+ 88 - 1
gameplay/src/lua/lua_MathUtil.cpp

@@ -1,6 +1,7 @@
 #include "Base.h"
 #include "ScriptController.h"
 #include "lua_MathUtil.h"
+#include "Base.h"
 #include "MathUtil.h"
 
 namespace gameplay
@@ -12,7 +13,11 @@ void luaRegister_MathUtil()
     {
         {NULL, NULL}
     };
-    const luaL_Reg* lua_statics = NULL;
+    const luaL_Reg lua_statics[] = 
+    {
+        {"smooth", lua_MathUtil_static_smooth},
+        {NULL, NULL}
+    };
     std::vector<std::string> scopePath;
 
     ScriptUtil::registerClass("MathUtil", lua_members, NULL, lua_MathUtil__gc, lua_statics, scopePath);
@@ -65,4 +70,86 @@ int lua_MathUtil__gc(lua_State* state)
     return 0;
 }
 
+int lua_MathUtil_static_smooth(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TTABLE || lua_type(state, 1) == LUA_TLIGHTUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<float> param1 = ScriptUtil::getFloatPointer(1);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 2);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 4 off the stack.
+                float param4 = (float)luaL_checknumber(state, 4);
+
+                MathUtil::smooth(param1, param2, param3, param4);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_MathUtil_static_smooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        case 5:
+        {
+            if ((lua_type(state, 1) == LUA_TTABLE || lua_type(state, 1) == LUA_TLIGHTUSERDATA) &&
+                lua_type(state, 2) == LUA_TNUMBER &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER &&
+                lua_type(state, 5) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<float> param1 = ScriptUtil::getFloatPointer(1);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 2);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 4 off the stack.
+                float param4 = (float)luaL_checknumber(state, 4);
+
+                // Get parameter 5 off the stack.
+                float param5 = (float)luaL_checknumber(state, 5);
+
+                MathUtil::smooth(param1, param2, param3, param4, param5);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_MathUtil_static_smooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4 or 5).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 }

+ 1 - 0
gameplay/src/lua/lua_MathUtil.h

@@ -6,6 +6,7 @@ namespace gameplay
 
 // Lua bindings for MathUtil.
 int lua_MathUtil__gc(lua_State* state);
+int lua_MathUtil_static_smooth(lua_State* state);
 
 void luaRegister_MathUtil();
 

+ 47 - 0
gameplay/src/lua/lua_Node.cpp

@@ -140,6 +140,7 @@ void luaRegister_Node()
         {"translate", lua_Node_translate},
         {"translateForward", lua_Node_translateForward},
         {"translateLeft", lua_Node_translateLeft},
+        {"translateSmooth", lua_Node_translateSmooth},
         {"translateUp", lua_Node_translateUp},
         {"translateX", lua_Node_translateX},
         {"translateY", lua_Node_translateY},
@@ -6392,6 +6393,52 @@ int lua_Node_translateLeft(lua_State* state)
     return 0;
 }
 
+int lua_Node_translateSmooth(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<Vector3> param1 = ScriptUtil::getObjectPointer<Vector3>(2, "Vector3", true);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 4);
+
+                Node* instance = getInstance(state);
+                instance->translateSmooth(*param1, param2, param3);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Node_translateSmooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Node_translateUp(lua_State* state)
 {
     // Get the number of parameters.

+ 1 - 0
gameplay/src/lua/lua_Node.h

@@ -135,6 +135,7 @@ int lua_Node_transformVector(lua_State* state);
 int lua_Node_translate(lua_State* state);
 int lua_Node_translateForward(lua_State* state);
 int lua_Node_translateLeft(lua_State* state);
+int lua_Node_translateSmooth(lua_State* state);
 int lua_Node_translateUp(lua_State* state);
 int lua_Node_translateX(lua_State* state);
 int lua_Node_translateY(lua_State* state);

+ 8 - 4
gameplay/src/lua/lua_PhysicsVehicle.cpp

@@ -1031,12 +1031,13 @@ int lua_PhysicsVehicle_update(lua_State* state)
     // Attempt to match the parameters to a valid binding.
     switch (paramCount)
     {
-        case 4:
+        case 5:
         {
             if ((lua_type(state, 1) == LUA_TUSERDATA) &&
                 lua_type(state, 2) == LUA_TNUMBER &&
                 lua_type(state, 3) == LUA_TNUMBER &&
-                lua_type(state, 4) == LUA_TNUMBER)
+                lua_type(state, 4) == LUA_TNUMBER &&
+                lua_type(state, 5) == LUA_TNUMBER)
             {
                 // Get parameter 1 off the stack.
                 float param1 = (float)luaL_checknumber(state, 2);
@@ -1047,8 +1048,11 @@ int lua_PhysicsVehicle_update(lua_State* state)
                 // Get parameter 3 off the stack.
                 float param3 = (float)luaL_checknumber(state, 4);
 
+                // Get parameter 4 off the stack.
+                float param4 = (float)luaL_checknumber(state, 5);
+
                 PhysicsVehicle* instance = getInstance(state);
-                instance->update(param1, param2, param3);
+                instance->update(param1, param2, param3, param4);
                 
                 return 0;
             }
@@ -1061,7 +1065,7 @@ int lua_PhysicsVehicle_update(lua_State* state)
         }
         default:
         {
-            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_pushstring(state, "Invalid number of parameters (expected 5).");
             lua_error(state);
             break;
         }

+ 47 - 0
gameplay/src/lua/lua_Transform.cpp

@@ -70,6 +70,7 @@ void luaRegister_Transform()
         {"translate", lua_Transform_translate},
         {"translateForward", lua_Transform_translateForward},
         {"translateLeft", lua_Transform_translateLeft},
+        {"translateSmooth", lua_Transform_translateSmooth},
         {"translateUp", lua_Transform_translateUp},
         {"translateX", lua_Transform_translateX},
         {"translateY", lua_Transform_translateY},
@@ -3627,6 +3628,52 @@ int lua_Transform_translateLeft(lua_State* state)
     return 0;
 }
 
+int lua_Transform_translateSmooth(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<Vector3> param1 = ScriptUtil::getObjectPointer<Vector3>(2, "Vector3", true);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 4);
+
+                Transform* instance = getInstance(state);
+                instance->translateSmooth(*param1, param2, param3);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Transform_translateSmooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Transform_translateUp(lua_State* state)
 {
     // Get the number of parameters.

+ 1 - 0
gameplay/src/lua/lua_Transform.h

@@ -76,6 +76,7 @@ int lua_Transform_transformVector(lua_State* state);
 int lua_Transform_translate(lua_State* state);
 int lua_Transform_translateForward(lua_State* state);
 int lua_Transform_translateLeft(lua_State* state);
+int lua_Transform_translateSmooth(lua_State* state);
 int lua_Transform_translateUp(lua_State* state);
 int lua_Transform_translateX(lua_State* state);
 int lua_Transform_translateY(lua_State* state);

+ 47 - 0
gameplay/src/lua/lua_Vector2.cpp

@@ -25,6 +25,7 @@ void luaRegister_Vector2()
         {"rotate", lua_Vector2_rotate},
         {"scale", lua_Vector2_scale},
         {"set", lua_Vector2_set},
+        {"smooth", lua_Vector2_smooth},
         {"subtract", lua_Vector2_subtract},
         {"x", lua_Vector2_x},
         {"y", lua_Vector2_y},
@@ -872,6 +873,52 @@ int lua_Vector2_set(lua_State* state)
     return 0;
 }
 
+int lua_Vector2_smooth(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<Vector2> param1 = ScriptUtil::getObjectPointer<Vector2>(2, "Vector2", true);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 4);
+
+                Vector2* instance = getInstance(state);
+                instance->smooth(*param1, param2, param3);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Vector2_smooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Vector2_static_add(lua_State* state)
 {
     // Get the number of parameters.

+ 1 - 0
gameplay/src/lua/lua_Vector2.h

@@ -21,6 +21,7 @@ int lua_Vector2_normalize(lua_State* state);
 int lua_Vector2_rotate(lua_State* state);
 int lua_Vector2_scale(lua_State* state);
 int lua_Vector2_set(lua_State* state);
+int lua_Vector2_smooth(lua_State* state);
 int lua_Vector2_static_add(lua_State* state);
 int lua_Vector2_static_angle(lua_State* state);
 int lua_Vector2_static_clamp(lua_State* state);

+ 47 - 0
gameplay/src/lua/lua_Vector3.cpp

@@ -26,6 +26,7 @@ void luaRegister_Vector3()
         {"normalize", lua_Vector3_normalize},
         {"scale", lua_Vector3_scale},
         {"set", lua_Vector3_set},
+        {"smooth", lua_Vector3_smooth},
         {"subtract", lua_Vector3_subtract},
         {"x", lua_Vector3_x},
         {"y", lua_Vector3_y},
@@ -888,6 +889,52 @@ int lua_Vector3_set(lua_State* state)
     return 0;
 }
 
+int lua_Vector3_smooth(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 4:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TNIL) &&
+                lua_type(state, 3) == LUA_TNUMBER &&
+                lua_type(state, 4) == LUA_TNUMBER)
+            {
+                // Get parameter 1 off the stack.
+                ScriptUtil::LuaArray<Vector3> param1 = ScriptUtil::getObjectPointer<Vector3>(2, "Vector3", true);
+
+                // Get parameter 2 off the stack.
+                float param2 = (float)luaL_checknumber(state, 3);
+
+                // Get parameter 3 off the stack.
+                float param3 = (float)luaL_checknumber(state, 4);
+
+                Vector3* instance = getInstance(state);
+                instance->smooth(*param1, param2, param3);
+                
+                return 0;
+            }
+            else
+            {
+                lua_pushstring(state, "lua_Vector3_smooth - Failed to match the given parameters to a valid function signature.");
+                lua_error(state);
+            }
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 4).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Vector3_static_add(lua_State* state)
 {
     // Get the number of parameters.

+ 1 - 0
gameplay/src/lua/lua_Vector3.h

@@ -21,6 +21,7 @@ int lua_Vector3_negate(lua_State* state);
 int lua_Vector3_normalize(lua_State* state);
 int lua_Vector3_scale(lua_State* state);
 int lua_Vector3_set(lua_State* state);
+int lua_Vector3_smooth(lua_State* state);
 int lua_Vector3_static_add(lua_State* state);
 int lua_Vector3_static_angle(lua_State* state);
 int lua_Vector3_static_clamp(lua_State* state);