Browse Source

Merge remote-tracking branch 'blackberry/next' into gesture_events

Conflicts:
	gameplay/src/Game.h
Paul-Arthur SAUVAGEOT 12 years ago
parent
commit
094368f2b7
100 changed files with 13890 additions and 15928 deletions
  1. 5 0
      .gitignore
  2. 1 1
      README.md
  3. 2 3
      gameplay/.cproject
  4. 17 53
      gameplay/CMakeLists.txt
  5. 3 17
      gameplay/android/jni/Android.mk
  6. 880 916
      gameplay/gameplay.vcxproj
  7. 1851 1962
      gameplay/gameplay.vcxproj.filters
  8. 4 528
      gameplay/gameplay.xcodeproj/project.pbxproj
  9. 0 0
      gameplay/res/design/icon_128.ico
  10. 0 0
      gameplay/res/design/icon_16.ico
  11. 0 0
      gameplay/res/design/icon_32.ico
  12. 0 0
      gameplay/res/design/icon_64.ico
  13. 0 0
      gameplay/res/design/logo.ai
  14. 1 1
      gameplay/res/shaders/font.frag
  15. 17 12
      gameplay/res/shaders/lighting.frag
  16. 129 82
      gameplay/res/shaders/terrain.frag
  17. 114 54
      gameplay/res/shaders/terrain.vert
  18. 2 2
      gameplay/src/AnimationClip.cpp
  19. 12 0
      gameplay/src/Base.h
  20. 6 6
      gameplay/src/Bundle.cpp
  21. 2 0
      gameplay/src/Bundle.h
  22. 58 158
      gameplay/src/Button.cpp
  23. 107 137
      gameplay/src/Button.h
  24. 498 446
      gameplay/src/Camera.cpp
  25. 44 6
      gameplay/src/Camera.h
  26. 182 206
      gameplay/src/CheckBox.cpp
  27. 176 193
      gameplay/src/CheckBox.h
  28. 1526 1985
      gameplay/src/Container.cpp
  29. 609 640
      gameplay/src/Container.h
  30. 164 168
      gameplay/src/Control.cpp
  31. 104 17
      gameplay/src/Control.h
  32. 8 3
      gameplay/src/ControlFactory.cpp
  33. 18 8
      gameplay/src/ControlFactory.h
  34. 28 28
      gameplay/src/Curve.h
  35. 836 896
      gameplay/src/FileSystem.cpp
  36. 11 4
      gameplay/src/Font.cpp
  37. 10 2
      gameplay/src/Font.h
  38. 682 157
      gameplay/src/Form.cpp
  39. 52 2
      gameplay/src/Form.h
  40. 14 14
      gameplay/src/FrameBuffer.h
  41. 4 13
      gameplay/src/Game.cpp
  42. 0 12
      gameplay/src/Game.h
  43. 0 5
      gameplay/src/Game.inl
  44. 1 1
      gameplay/src/Gamepad.cpp
  45. 8 8
      gameplay/src/HeightField.h
  46. 169 171
      gameplay/src/ImageControl.cpp
  47. 152 152
      gameplay/src/ImageControl.h
  48. 293 292
      gameplay/src/Joystick.cpp
  49. 1 2
      gameplay/src/Joystick.h
  50. 1 1
      gameplay/src/Keyboard.h
  51. 125 127
      gameplay/src/Label.cpp
  52. 1 2
      gameplay/src/Label.h
  53. 1 1
      gameplay/src/Material.cpp
  54. 1 1
      gameplay/src/Material.h
  55. 14 14
      gameplay/src/Model.h
  56. 1343 1331
      gameplay/src/Node.cpp
  57. 62 58
      gameplay/src/Node.h
  58. 6 16
      gameplay/src/PhysicsVehicleWheel.cpp
  59. 3 6
      gameplay/src/PhysicsVehicleWheel.h
  60. 4 12
      gameplay/src/Platform.cpp
  61. 17 17
      gameplay/src/Platform.h
  62. 5 3
      gameplay/src/PlatformBlackBerry.cpp
  63. 51 14
      gameplay/src/PlatformMacOSX.mm
  64. 4 9
      gameplay/src/PlatformWindows.cpp
  65. 6 0
      gameplay/src/PlatformiOS.mm
  66. 4 3
      gameplay/src/Properties.cpp
  67. 2 0
      gameplay/src/Properties.h
  68. 235 266
      gameplay/src/RadioButton.cpp
  69. 198 215
      gameplay/src/RadioButton.h
  70. 17 1
      gameplay/src/RenderState.cpp
  71. 24 3
      gameplay/src/RenderState.h
  72. 50 248
      gameplay/src/Scene.cpp
  73. 38 36
      gameplay/src/Scene.h
  74. 5 5
      gameplay/src/SceneLoader.cpp
  75. 0 26
      gameplay/src/SceneRenderer.cpp
  76. 0 62
      gameplay/src/SceneRenderer.h
  77. 0 73
      gameplay/src/SceneRendererForward.cpp
  78. 0 49
      gameplay/src/SceneRendererForward.h
  79. 489 621
      gameplay/src/Slider.cpp
  80. 368 366
      gameplay/src/Slider.h
  81. 0 18
      gameplay/src/SocialAchievement.cpp
  82. 0 65
      gameplay/src/SocialAchievement.h
  83. 0 16
      gameplay/src/SocialChallenge.cpp
  84. 0 86
      gameplay/src/SocialChallenge.h
  85. 0 92
      gameplay/src/SocialController.cpp
  86. 0 102
      gameplay/src/SocialController.h
  87. 0 17
      gameplay/src/SocialPlayer.cpp
  88. 0 42
      gameplay/src/SocialPlayer.h
  89. 0 18
      gameplay/src/SocialScore.cpp
  90. 0 54
      gameplay/src/SocialScore.h
  91. 0 113
      gameplay/src/SocialSession.h
  92. 0 92
      gameplay/src/SocialSessionListener.cpp
  93. 0 95
      gameplay/src/SocialSessionListener.h
  94. 585 634
      gameplay/src/Terrain.cpp
  95. 376 429
      gameplay/src/Terrain.h
  96. 127 79
      gameplay/src/TerrainPatch.cpp
  97. 141 154
      gameplay/src/TerrainPatch.h
  98. 508 551
      gameplay/src/TextBox.cpp
  99. 278 269
      gameplay/src/TextBox.h
  100. 0 53
      gameplay/src/VisibleSet.h

+ 5 - 0
.gitignore

@@ -244,3 +244,8 @@ gameplay.xcworkspace/xcshareddata/gameplay.xccheckout
 /samples/spaceship/android/local.properties
 /samples/spaceship/sample-spaceship.xcodeproj/xcuserdata
 
+/tools/encoder/Debug
+/tools/encoder/Release
+
+/tools/luagen/Debug
+/tools/luagen/Release

+ 1 - 1
README.md

@@ -14,9 +14,9 @@ GamePlay3D is an open-source, cross-platform 3D native C++ game framework making
 - [Microsoft Windows](https://github.com/blackberry/GamePlay/wiki/Visual-Studio-Setup) (using Microsoft Visual Studio)
 - [Apple MacOS X](https://github.com/blackberry/GamePlay/wiki/Apple-Xcode-Setup) (using Apple XCode)
 - [Linux](https://github.com/blackberry/GamePlay/wiki/Linux-Setup) (using CMake)
-- [BlackBerry](https://github.com/blackberry/GamePlay/wiki/BlackBerry-Setup) (using BlackBerry Native SDK)
 - [Apple iOS](https://github.com/blackberry/GamePlay/wiki/Apple-Xcode-Setup) (using Apple XCode)
 - [Google Android](https://github.com/blackberry/GamePlay/wiki/Android-NDK-Setup) (using Google Android NDK)
+- [BlackBerry](https://github.com/blackberry/GamePlay/wiki/BlackBerry-Setup) (using BlackBerry Native SDK)
 
 ## Roadmap for 'next' branch
 - [2.0.0](https://github.com/blackberry/GamePlay/issues?milestone=6&page=1&state=open)

+ 2 - 3
gameplay/.cproject

@@ -24,7 +24,6 @@
 								<option id="com.qnx.qcc.option.compiler.defines.1481323494" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 									<listOptionValue builtIn="false" value="BT_USE_NEON"/>
-									<listOptionValue builtIn="false" value="GP_USE_SOCIAL"/>
 									<listOptionValue builtIn="false" value="GP_USE_GAMEPAD"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.2133604142" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
@@ -89,7 +88,6 @@
 								<option id="com.qnx.qcc.option.compiler.defines.398688299" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 									<listOptionValue builtIn="false" value="BT_USE_NEON"/>
-									<listOptionValue builtIn="false" value="GP_USE_SOCIAL"/>
 									<listOptionValue builtIn="false" value="GP_USE_GAMEPAD"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1670164593" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
@@ -149,7 +147,7 @@
 								<option id="com.qnx.qcc.option.compiler.security.1671403331" name="Enhanced Security (-fstack-protector-strong)" superClass="com.qnx.qcc.option.compiler.security" value="false" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.defines.1863269886" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
-									<listOptionValue builtIn="false" value="GP_USE_SOCIAL"/>
+									<listOptionValue builtIn="false" value="BT_USE_NEON"/>
 									<listOptionValue builtIn="false" value="GP_USE_GAMEPAD"/>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.847642559" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
@@ -222,4 +220,5 @@
 	<storageModule moduleId="com.qnx.tools.ide.qde.core.QNXProjectProperties"/>
 	<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
 	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+	<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
 </cproject>

+ 17 - 53
gameplay/CMakeLists.txt

@@ -187,10 +187,6 @@ set(GAMEPLAY_SRC
     src/Scene.h
     src/SceneLoader.cpp
     src/SceneLoader.h
-    src/SceneRenderer.cpp
-    src/SceneRenderer.h
-    src/SceneRendererForward.cpp
-    src/SceneRendererForward.h
     src/ScreenDisplayer.cpp
     src/ScreenDisplayer.h
     src/ScriptController.cpp
@@ -200,19 +196,6 @@ set(GAMEPLAY_SRC
     src/ScriptTarget.h
     src/Slider.cpp
     src/Slider.h
-    src/SocialAchievement.cpp
-    src/SocialAchievement.h
-    src/SocialChallenge.cpp
-    src/SocialChallenge.h
-    src/SocialController.cpp
-    src/SocialController.h
-    src/SocialPlayer.cpp
-    src/SocialPlayer.h
-    src/SocialScore.cpp
-    src/SocialScore.h
-    src/SocialSession.h
-    src/SocialSessionListener.cpp
-    src/SocialSessionListener.h
     src/SpriteBatch.cpp
     src/SpriteBatch.h
     src/Technique.cpp
@@ -246,9 +229,6 @@ set(GAMEPLAY_SRC
     src/VertexFormat.h
     src/VerticalLayout.cpp
     src/VerticalLayout.h
-    src/VisibleSet.h
-    src/VisibleSetDefault.cpp
-    src/VisibleSetDefault.h
 )
 
 set(GAMEPLAY_LUA
@@ -306,6 +286,8 @@ set(GAMEPLAY_LUA
     src/lua/lua_Button.h
     src/lua/lua_Camera.cpp
     src/lua/lua_Camera.h
+    src/lua/lua_CameraListener.h
+    src/lua/lua_CameraListener.cpp
     src/lua/lua_CameraType.cpp
     src/lua/lua_CameraType.h
     src/lua/lua_CheckBox.cpp
@@ -533,12 +515,6 @@ set(GAMEPLAY_LUA
     src/lua/lua_RenderTarget.h
     src/lua/lua_Scene.cpp
     src/lua/lua_Scene.h
-    src/lua/lua_SceneDebugFlags.cpp
-    src/lua/lua_SceneDebugFlags.h
-    src/lua/lua_SceneRenderer.cpp
-    src/lua/lua_SceneRenderer.h
-    src/lua/lua_SceneRendererForward.cpp
-    src/lua/lua_SceneRendererForward.h
     src/lua/lua_ScreenDisplayer.cpp
     src/lua/lua_ScreenDisplayer.h
     src/lua/lua_ScriptController.cpp
@@ -555,8 +531,8 @@ set(GAMEPLAY_LUA
     src/lua/lua_Terrain.h
     src/lua/lua_TerrainFlags.cpp
     src/lua/lua_TerrainFlags.h
-    src/lua/lua_TerrainListener.cpp
-    src/lua/lua_TerrainListener.h
+    src/lua/lua_TerrainPatch.cpp
+    src/lua/lua_TerrainPatch.h
     src/lua/lua_TextBox.cpp
     src/lua/lua_TextBox.h
     src/lua/lua_TextBoxInputMode.cpp
@@ -607,10 +583,6 @@ set(GAMEPLAY_LUA
     src/lua/lua_VertexFormatUsage.h
     src/lua/lua_VerticalLayout.cpp
     src/lua/lua_VerticalLayout.h
-    src/lua/lua_VisibleSet.cpp
-    src/lua/lua_VisibleSet.h
-    src/lua/lua_VisibleSetDefault.cpp
-    src/lua/lua_VisibleSetDefault.h
 )
 
 set(GAMEPLAY_RES
@@ -621,30 +593,22 @@ set(GAMEPLAY_RES
 )
 
 set(GAMEPLAY_RES_SHADERS
-    res/shaders/colored-unlit.frag
-    res/shaders/colored-unlit.vert
     res/shaders/colored.frag
     res/shaders/colored.vert
-    res/shaders/textured-bumped.frag
-    res/shaders/textured-bumped.vert
-    res/shaders/textured-unlit.frag
-    res/shaders/textured-unlit.vert
-    res/shaders/textured.frag
-    res/shaders/textured.vert
+    res/shaders/font.frag
+    res/shaders/font.vert
+    res/shaders/form.frag
+    res/shaders/form.vert
+    res/shaders/lighting.frag
+    res/shaders/lighting.vert
+    res/shaders/skinning.vert
+    res/shaders/skinning-none.vert
+    res/shaders/sprite.frag
+    res/shaders/sprite.vert
     res/shaders/terrain.frag
     res/shaders/terrain.vert
-)
-
-set(GAMEPLAY_RES_SHADERS_LIB
-    res/shaders/lib/attributes-skinning.vert
-    res/shaders/lib/attributes.vert
-    res/shaders/lib/lighting-directional.frag
-    res/shaders/lib/lighting-directional.vert
-    res/shaders/lib/lighting-point.frag
-    res/shaders/lib/lighting-point.vert
-    res/shaders/lib/lighting-spot.frag
-    res/shaders/lib/lighting-spot.vert
-    res/shaders/lib/lighting.frag
+    res/shaders/textured.frag
+    res/shaders/textured.vert
 )
 
 include_directories( 
@@ -673,7 +637,7 @@ set_target_properties(gameplay PROPERTIES
 )
 
 source_group(lua FILES ${GAMEPLAY_LUA})
-source_group(res FILES ${GAMEPLAY_RES} ${GAMEPLAY_RES} ${GAMEPLAY_RES_SHADERS} ${GAMEPLAY_RES_SHADERS_LIB})
+source_group(res FILES ${GAMEPLAY_RES} ${GAMEPLAY_RES} ${GAMEPLAY_RES_SHADERS})
 source_group(src FILES ${GAMEPLAY_SRC})
 
 

+ 3 - 17
gameplay/android/jni/Android.mk

@@ -88,18 +88,10 @@ LOCAL_SRC_FILES := \
     RenderTarget.cpp \
     Scene.cpp \
     SceneLoader.cpp \
-    SceneRenderer.cpp \
-    SceneRendererForward.cpp \
     ScreenDisplayer.cpp \
     ScriptController.cpp \
     ScriptTarget.cpp \
     Slider.cpp \
-	SocialAchievement.cpp \
-	SocialChallenge.cpp \
-	SocialController.cpp \
-	SocialPlayer.cpp \
-	SocialScore.cpp \
-	SocialSessionListener.cpp \
     SpriteBatch.cpp \
     Technique.cpp \
     Terrain.cpp \
@@ -115,7 +107,6 @@ LOCAL_SRC_FILES := \
     VertexAttributeBinding.cpp \
     VertexFormat.cpp \
     VerticalLayout.cpp \
-    VisibleSetDefault.cpp \
     lua/lua_AbsoluteLayout.cpp \
     lua/lua_AIAgent.cpp \
     lua/lua_AIAgentListener.cpp \
@@ -143,6 +134,7 @@ LOCAL_SRC_FILES := \
     lua/lua_Bundle.cpp \
     lua/lua_Button.cpp \
     lua/lua_Camera.cpp \
+    lua/lua_CameraListener.cpp \
     lua/lua_CameraType.cpp \
     lua/lua_CheckBox.cpp \
     lua/lua_Container.cpp \
@@ -257,9 +249,6 @@ LOCAL_SRC_FILES := \
     lua/lua_RenderStateStencilOperation.cpp \
     lua/lua_RenderTarget.cpp \
     lua/lua_Scene.cpp \
-    lua/lua_SceneDebugFlags.cpp \
-    lua/lua_SceneRenderer.cpp \
-    lua/lua_SceneRendererForward.cpp \
     lua/lua_ScreenDisplayer.cpp \
     lua/lua_ScriptController.cpp \
     lua/lua_ScriptTarget.cpp \
@@ -268,7 +257,7 @@ LOCAL_SRC_FILES := \
     lua/lua_Technique.cpp \
     lua/lua_Terrain.cpp \
     lua/lua_TerrainFlags.cpp \
-    lua/lua_TerrainListener.cpp \
+    lua/lua_TerrainPatch.cpp \
     lua/lua_TextBox.cpp \
     lua/lua_TextBoxInputMode.cpp \
     lua/lua_Texture.cpp \
@@ -293,10 +282,7 @@ LOCAL_SRC_FILES := \
     lua/lua_VertexFormat.cpp \
     lua/lua_VertexFormatElement.cpp \
     lua/lua_VertexFormatUsage.cpp \
-    lua/lua_VerticalLayout.cpp \
-    lua/lua_VisibleSet.cpp \
-    lua/lua_VisibleSetDefault.cpp \
-    social/GooglePlaySocialSession.cpp
+    lua/lua_VerticalLayout.cpp
 
     
 LOCAL_CFLAGS := -D__ANDROID__ -DGP_USE_SOCIAL -I"../../external-deps/lua/include" -I"../../external-deps/bullet/include" -I"../../external-deps/png/include" -I"../../external-deps/oggvorbis/include" -I"../../external-deps/openal/include"

+ 880 - 916
gameplay/gameplay.vcxproj

@@ -1,917 +1,881 @@
-<?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|Win32">
-      <Configuration>DebugMem</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="DebugMem|x64">
-      <Configuration>DebugMem</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|Win32">
-      <Configuration>Debug</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Debug|x64">
-      <Configuration>Debug</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|Win32">
-      <Configuration>Release</Configuration>
-      <Platform>Win32</Platform>
-    </ProjectConfiguration>
-    <ProjectConfiguration Include="Release|x64">
-      <Configuration>Release</Configuration>
-      <Platform>x64</Platform>
-    </ProjectConfiguration>
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="src\AbsoluteLayout.cpp" />
-    <ClCompile Include="src\AIAgent.cpp" />
-    <ClCompile Include="src\AIController.cpp" />
-    <ClCompile Include="src\AIMessage.cpp" />
-    <ClCompile Include="src\AIState.cpp" />
-    <ClCompile Include="src\AIStateMachine.cpp" />
-    <ClCompile Include="src\Animation.cpp" />
-    <ClCompile Include="src\AnimationClip.cpp" />
-    <ClCompile Include="src\AnimationController.cpp" />
-    <ClCompile Include="src\AnimationTarget.cpp" />
-    <ClCompile Include="src\AnimationValue.cpp" />
-    <ClCompile Include="src\AudioBuffer.cpp" />
-    <ClCompile Include="src\AudioController.cpp" />
-    <ClCompile Include="src\AudioListener.cpp" />
-    <ClCompile Include="src\AudioSource.cpp" />
-    <ClCompile Include="src\BoundingBox.cpp" />
-    <ClCompile Include="src\BoundingSphere.cpp" />
-    <ClCompile Include="src\Button.cpp" />
-    <ClCompile Include="src\Camera.cpp" />
-    <ClCompile Include="src\CheckBox.cpp" />
-    <ClCompile Include="src\Container.cpp" />
-    <ClCompile Include="src\Control.cpp" />
-    <ClCompile Include="src\ControlFactory.cpp" />
-    <ClCompile Include="src\Curve.cpp" />
-    <ClCompile Include="src\DebugNew.cpp" />
-    <ClCompile Include="src\DepthStencilTarget.cpp" />
-    <ClCompile Include="src\Effect.cpp" />
-    <ClCompile Include="src\FileSystem.cpp" />
-    <ClCompile Include="src\FlowLayout.cpp" />
-    <ClCompile Include="src\Font.cpp" />
-    <ClCompile Include="src\Form.cpp" />
-    <ClCompile Include="src\FrameBuffer.cpp" />
-    <ClCompile Include="src\Frustum.cpp" />
-    <ClCompile Include="src\Game.cpp" />
-    <ClCompile Include="src\Gamepad.cpp" />
-    <ClCompile Include="src\gameplay-main-android.cpp" />
-    <ClCompile Include="src\gameplay-main-blackberry.cpp" />
-    <ClCompile Include="src\gameplay-main-linux.cpp" />
-    <ClCompile Include="src\gameplay-main-windows.cpp" />
-    <ClCompile Include="src\HeightField.cpp" />
-    <ClCompile Include="src\Image.cpp" />
-    <ClCompile Include="src\ImageControl.cpp" />
-    <ClCompile Include="src\Joint.cpp" />
-    <ClCompile Include="src\Joystick.cpp" />
-    <ClCompile Include="src\Label.cpp" />
-    <ClCompile Include="src\Layout.cpp" />
-    <ClCompile Include="src\Light.cpp" />
-    <ClCompile Include="src\Logger.cpp" />
-    <ClCompile Include="src\lua\lua_AbsoluteLayout.cpp" />
-    <ClCompile Include="src\lua\lua_AIAgent.cpp" />
-    <ClCompile Include="src\lua\lua_AIAgentListener.cpp" />
-    <ClCompile Include="src\lua\lua_AIController.cpp" />
-    <ClCompile Include="src\lua\lua_AIMessage.cpp" />
-    <ClCompile Include="src\lua\lua_AIMessageParameterType.cpp" />
-    <ClCompile Include="src\lua\lua_AIState.cpp" />
-    <ClCompile Include="src\lua\lua_AIStateListener.cpp" />
-    <ClCompile Include="src\lua\lua_AIStateMachine.cpp" />
-    <ClCompile Include="src\lua\lua_all_bindings.cpp" />
-    <ClCompile Include="src\lua\lua_Animation.cpp" />
-    <ClCompile Include="src\lua\lua_AnimationClip.cpp" />
-    <ClCompile Include="src\lua\lua_AnimationClipListener.cpp" />
-    <ClCompile Include="src\lua\lua_AnimationClipListenerEventType.cpp" />
-    <ClCompile Include="src\lua\lua_AnimationController.cpp" />
-    <ClCompile Include="src\lua\lua_AnimationTarget.cpp" />
-    <ClCompile Include="src\lua\lua_AnimationValue.cpp" />
-    <ClCompile Include="src\lua\lua_AudioBuffer.cpp" />
-    <ClCompile Include="src\lua\lua_AudioController.cpp" />
-    <ClCompile Include="src\lua\lua_AudioListener.cpp" />
-    <ClCompile Include="src\lua\lua_AudioSource.cpp" />
-    <ClCompile Include="src\lua\lua_AudioSourceState.cpp" />
-    <ClCompile Include="src\lua\lua_BoundingBox.cpp" />
-    <ClCompile Include="src\lua\lua_BoundingSphere.cpp" />
-    <ClCompile Include="src\lua\lua_Bundle.cpp" />
-    <ClCompile Include="src\lua\lua_Button.cpp" />
-    <ClCompile Include="src\lua\lua_Camera.cpp" />
-    <ClCompile Include="src\lua\lua_CameraType.cpp" />
-    <ClCompile Include="src\lua\lua_CheckBox.cpp" />
-    <ClCompile Include="src\lua\lua_Container.cpp" />
-    <ClCompile Include="src\lua\lua_ContainerScroll.cpp" />
-    <ClCompile Include="src\lua\lua_Control.cpp" />
-    <ClCompile Include="src\lua\lua_ControlAlignment.cpp" />
-    <ClCompile Include="src\lua\lua_ControlAutoSize.cpp" />
-    <ClCompile Include="src\lua\lua_ControlListener.cpp" />
-    <ClCompile Include="src\lua\lua_ControlListenerEventType.cpp" />
-    <ClCompile Include="src\lua\lua_ControlState.cpp" />
-    <ClCompile Include="src\lua\lua_Curve.cpp" />
-    <ClCompile Include="src\lua\lua_CurveInterpolationType.cpp" />
-    <ClCompile Include="src\lua\lua_DepthStencilTarget.cpp" />
-    <ClCompile Include="src\lua\lua_DepthStencilTargetFormat.cpp" />
-    <ClCompile Include="src\lua\lua_Effect.cpp" />
-    <ClCompile Include="src\lua\lua_FileSystem.cpp" />
-    <ClCompile Include="src\lua\lua_FlowLayout.cpp" />
-    <ClCompile Include="src\lua\lua_Font.cpp" />
-    <ClCompile Include="src\lua\lua_FontFormat.cpp" />
-    <ClCompile Include="src\lua\lua_FontJustify.cpp" />
-    <ClCompile Include="src\lua\lua_FontStyle.cpp" />
-    <ClCompile Include="src\lua\lua_FontText.cpp" />
-    <ClCompile Include="src\lua\lua_Form.cpp" />
-    <ClCompile Include="src\lua\lua_FrameBuffer.cpp" />
-    <ClCompile Include="src\lua\lua_Frustum.cpp" />
-    <ClCompile Include="src\lua\lua_Game.cpp" />
-    <ClCompile Include="src\lua\lua_GameClearFlags.cpp" />
-    <ClCompile Include="src\lua\lua_Gamepad.cpp" />
-    <ClCompile Include="src\lua\lua_GamepadButtonMapping.cpp" />
-    <ClCompile Include="src\lua\lua_GamepadGamepadEvent.cpp" />
-    <ClCompile Include="src\lua\lua_GameState.cpp" />
-    <ClCompile Include="src\lua\lua_Gesture.cpp" />
-    <ClCompile Include="src\lua\lua_GestureGestureEvent.cpp" />
-    <ClCompile Include="src\lua\lua_Global.cpp" />
-    <ClCompile Include="src\lua\lua_HeightField.cpp" />
-    <ClCompile Include="src\lua\lua_Image.cpp" />
-    <ClCompile Include="src\lua\lua_ImageControl.cpp" />
-    <ClCompile Include="src\lua\lua_ImageFormat.cpp" />
-    <ClCompile Include="src\lua\lua_Joint.cpp" />
-    <ClCompile Include="src\lua\lua_Joystick.cpp" />
-    <ClCompile Include="src\lua\lua_Keyboard.cpp" />
-    <ClCompile Include="src\lua\lua_KeyboardKey.cpp" />
-    <ClCompile Include="src\lua\lua_KeyboardKeyEvent.cpp" />
-    <ClCompile Include="src\lua\lua_Label.cpp" />
-    <ClCompile Include="src\lua\lua_Layout.cpp" />
-    <ClCompile Include="src\lua\lua_LayoutType.cpp" />
-    <ClCompile Include="src\lua\lua_Light.cpp" />
-    <ClCompile Include="src\lua\lua_LightType.cpp" />
-    <ClCompile Include="src\lua\lua_Logger.cpp" />
-    <ClCompile Include="src\lua\lua_LoggerLevel.cpp" />
-    <ClCompile Include="src\lua\lua_Material.cpp" />
-    <ClCompile Include="src\lua\lua_MaterialParameter.cpp" />
-    <ClCompile Include="src\lua\lua_MathUtil.cpp" />
-    <ClCompile Include="src\lua\lua_Matrix.cpp" />
-    <ClCompile Include="src\lua\lua_Mesh.cpp" />
-    <ClCompile Include="src\lua\lua_MeshBatch.cpp" />
-    <ClCompile Include="src\lua\lua_MeshIndexFormat.cpp" />
-    <ClCompile Include="src\lua\lua_MeshPart.cpp" />
-    <ClCompile Include="src\lua\lua_MeshPrimitiveType.cpp" />
-    <ClCompile Include="src\lua\lua_MeshSkin.cpp" />
-    <ClCompile Include="src\lua\lua_Model.cpp" />
-    <ClCompile Include="src\lua\lua_Mouse.cpp" />
-    <ClCompile Include="src\lua\lua_MouseMouseEvent.cpp" />
-    <ClCompile Include="src\lua\lua_Node.cpp" />
-    <ClCompile Include="src\lua\lua_NodeCloneContext.cpp" />
-    <ClCompile Include="src\lua\lua_NodeType.cpp" />
-    <ClCompile Include="src\lua\lua_ParticleEmitter.cpp" />
-    <ClCompile Include="src\lua\lua_ParticleEmitterTextureBlending.cpp" />
-    <ClCompile Include="src\lua\lua_Pass.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCharacter.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObject.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectType.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionShape.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeDefinition.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeType.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsConstraint.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsController.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsControllerHitFilter.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsControllerHitResult.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsControllerListener.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsControllerListenerEventType.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsFixedConstraint.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsGenericConstraint.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsGhostObject.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsHingeConstraint.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsRigidBody.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsRigidBodyParameters.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsSocketConstraint.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsSpringConstraint.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsVehicle.cpp" />
-    <ClCompile Include="src\lua\lua_PhysicsVehicleWheel.cpp" />
-    <ClCompile Include="src\lua\lua_Plane.cpp" />
-    <ClCompile Include="src\lua\lua_Platform.cpp" />
-    <ClCompile Include="src\lua\lua_Properties.cpp" />
-    <ClCompile Include="src\lua\lua_PropertiesType.cpp" />
-    <ClCompile Include="src\lua\lua_Quaternion.cpp" />
-    <ClCompile Include="src\lua\lua_RadioButton.cpp" />
-    <ClCompile Include="src\lua\lua_Ray.cpp" />
-    <ClCompile Include="src\lua\lua_Rectangle.cpp" />
-    <ClCompile Include="src\lua\lua_Ref.cpp" />
-    <ClCompile Include="src\lua\lua_RenderState.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateAutoBinding.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateBlend.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateCullFaceSide.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateDepthFunction.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateFrontFace.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateStateBlock.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateStencilFunction.cpp" />
-    <ClCompile Include="src\lua\lua_RenderStateStencilOperation.cpp" />
-    <ClCompile Include="src\lua\lua_RenderTarget.cpp" />
-    <ClCompile Include="src\lua\lua_Scene.cpp" />
-    <ClCompile Include="src\lua\lua_SceneDebugFlags.cpp" />
-    <ClCompile Include="src\lua\lua_SceneRenderer.cpp" />
-    <ClCompile Include="src\lua\lua_SceneRendererForward.cpp" />
-    <ClCompile Include="src\lua\lua_ScreenDisplayer.cpp" />
-    <ClCompile Include="src\lua\lua_ScriptController.cpp" />
-    <ClCompile Include="src\lua\lua_ScriptTarget.cpp" />
-    <ClCompile Include="src\lua\lua_Slider.cpp" />
-    <ClCompile Include="src\lua\lua_SpriteBatch.cpp" />
-    <ClCompile Include="src\lua\lua_Technique.cpp" />
-    <ClCompile Include="src\lua\lua_Terrain.cpp" />
-    <ClCompile Include="src\lua\lua_TerrainFlags.cpp" />
-    <ClCompile Include="src\lua\lua_TerrainListener.cpp" />
-    <ClCompile Include="src\lua\lua_TextBox.cpp" />
-    <ClCompile Include="src\lua\lua_TextBoxInputMode.cpp" />
-    <ClCompile Include="src\lua\lua_Texture.cpp" />
-    <ClCompile Include="src\lua\lua_TextureFilter.cpp" />
-    <ClCompile Include="src\lua\lua_TextureFormat.cpp" />
-    <ClCompile Include="src\lua\lua_TextureSampler.cpp" />
-    <ClCompile Include="src\lua\lua_TextureWrap.cpp" />
-    <ClCompile Include="src\lua\lua_Theme.cpp" />
-    <ClCompile Include="src\lua\lua_ThemeSideRegions.cpp" />
-    <ClCompile Include="src\lua\lua_ThemeStyle.cpp" />
-    <ClCompile Include="src\lua\lua_ThemeThemeImage.cpp" />
-    <ClCompile Include="src\lua\lua_ThemeUVs.cpp" />
-    <ClCompile Include="src\lua\lua_Touch.cpp" />
-    <ClCompile Include="src\lua\lua_TouchTouchEvent.cpp" />
-    <ClCompile Include="src\lua\lua_Transform.cpp" />
-    <ClCompile Include="src\lua\lua_TransformListener.cpp" />
-    <ClCompile Include="src\lua\lua_Uniform.cpp" />
-    <ClCompile Include="src\lua\lua_Vector2.cpp" />
-    <ClCompile Include="src\lua\lua_Vector3.cpp" />
-    <ClCompile Include="src\lua\lua_Vector4.cpp" />
-    <ClCompile Include="src\lua\lua_VertexAttributeBinding.cpp" />
-    <ClCompile Include="src\lua\lua_VertexFormat.cpp" />
-    <ClCompile Include="src\lua\lua_VertexFormatElement.cpp" />
-    <ClCompile Include="src\lua\lua_VertexFormatUsage.cpp" />
-    <ClCompile Include="src\lua\lua_VerticalLayout.cpp" />
-    <ClCompile Include="src\lua\lua_VisibleSet.cpp" />
-    <ClCompile Include="src\lua\lua_VisibleSetDefault.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" />
-    <ClCompile Include="src\Matrix.cpp" />
-    <ClCompile Include="src\Mesh.cpp" />
-    <ClCompile Include="src\MeshPart.cpp" />
-    <ClCompile Include="src\MeshSkin.cpp" />
-    <ClCompile Include="src\Model.cpp" />
-    <ClCompile Include="src\Node.cpp" />
-    <ClCompile Include="src\Bundle.cpp" />
-    <ClCompile Include="src\ParticleEmitter.cpp" />
-    <ClCompile Include="src\PhysicsCharacter.cpp" />
-    <ClCompile Include="src\PhysicsCollisionObject.cpp" />
-    <ClCompile Include="src\PhysicsCollisionShape.cpp" />
-    <ClCompile Include="src\PhysicsConstraint.cpp" />
-    <ClCompile Include="src\PhysicsController.cpp" />
-    <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
-    <ClCompile Include="src\PhysicsGenericConstraint.cpp" />
-    <ClCompile Include="src\PhysicsGhostObject.cpp" />
-    <ClCompile Include="src\PhysicsHingeConstraint.cpp" />
-    <ClCompile Include="src\PhysicsRigidBody.cpp" />
-    <ClCompile Include="src\PhysicsSocketConstraint.cpp" />
-    <ClCompile Include="src\PhysicsSpringConstraint.cpp" />
-    <ClCompile Include="src\PhysicsVehicle.cpp" />
-    <ClCompile Include="src\PhysicsVehicleWheel.cpp" />
-    <ClCompile Include="src\Plane.cpp" />
-    <ClCompile Include="src\Platform.cpp" />
-    <ClCompile Include="src\PlatformAndroid.cpp" />
-    <ClCompile Include="src\PlatformBlackBerry.cpp" />
-    <ClCompile Include="src\PlatformLinux.cpp" />
-    <ClCompile Include="src\PlatformWindows.cpp" />
-    <ClCompile Include="src\Properties.cpp" />
-    <ClCompile Include="src\Quaternion.cpp" />
-    <ClCompile Include="src\RadioButton.cpp" />
-    <ClCompile Include="src\Ray.cpp" />
-    <ClCompile Include="src\Rectangle.cpp" />
-    <ClCompile Include="src\Ref.cpp" />
-    <ClCompile Include="src\RenderState.cpp" />
-    <ClCompile Include="src\RenderTarget.cpp" />
-    <ClCompile Include="src\Scene.cpp" />
-    <ClCompile Include="src\SceneLoader.cpp" />
-    <ClCompile Include="src\SceneRenderer.cpp" />
-    <ClCompile Include="src\SceneRendererForward.cpp" />
-    <ClCompile Include="src\ScreenDisplayer.cpp" />
-    <ClCompile Include="src\ScriptController.cpp" />
-    <ClCompile Include="src\ScriptTarget.cpp" />
-    <ClCompile Include="src\Slider.cpp" />
-    <ClCompile Include="src\SocialAchievement.cpp" />
-    <ClCompile Include="src\SocialChallenge.cpp" />
-    <ClCompile Include="src\SocialController.cpp" />
-    <ClCompile Include="src\SocialPlayer.cpp" />
-    <ClCompile Include="src\SocialScore.cpp" />
-    <ClCompile Include="src\SocialSessionListener.cpp" />
-    <ClCompile Include="src\social\GooglePlaySocialSession.cpp" />
-    <ClCompile Include="src\social\ScoreloopSocialSession.cpp" />
-    <ClCompile Include="src\SpriteBatch.cpp" />
-    <ClCompile Include="src\Technique.cpp" />
-    <ClCompile Include="src\Terrain.cpp" />
-    <ClCompile Include="src\TerrainPatch.cpp" />
-    <ClCompile Include="src\TextBox.cpp" />
-    <ClCompile Include="src\Texture.cpp" />
-    <ClCompile Include="src\Theme.cpp" />
-    <ClCompile Include="src\ThemeStyle.cpp" />
-    <ClCompile Include="src\Transform.cpp" />
-    <ClCompile Include="src\Vector2.cpp" />
-    <ClCompile Include="src\Vector3.cpp" />
-    <ClCompile Include="src\Vector4.cpp" />
-    <ClCompile Include="src\VertexAttributeBinding.cpp" />
-    <ClCompile Include="src\VertexFormat.cpp" />
-    <ClCompile Include="src\VerticalLayout.cpp" />
-    <ClCompile Include="src\VisibleSetDefault.cpp" />
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="src\AbsoluteLayout.h" />
-    <ClInclude Include="src\AIAgent.h" />
-    <ClInclude Include="src\AIController.h" />
-    <ClInclude Include="src\AIMessage.h" />
-    <ClInclude Include="src\AIState.h" />
-    <ClInclude Include="src\AIStateMachine.h" />
-    <ClInclude Include="src\Animation.h" />
-    <ClInclude Include="src\AnimationClip.h" />
-    <ClInclude Include="src\AnimationController.h" />
-    <ClInclude Include="src\AnimationTarget.h" />
-    <ClInclude Include="src\AnimationValue.h" />
-    <ClInclude Include="src\AudioBuffer.h" />
-    <ClInclude Include="src\AudioController.h" />
-    <ClInclude Include="src\AudioListener.h" />
-    <ClInclude Include="src\AudioSource.h" />
-    <ClInclude Include="src\Base.h" />
-    <ClInclude Include="src\BoundingBox.h" />
-    <ClInclude Include="src\BoundingSphere.h" />
-    <ClInclude Include="src\Button.h" />
-    <ClInclude Include="src\Camera.h" />
-    <ClInclude Include="src\CheckBox.h" />
-    <ClInclude Include="src\Container.h" />
-    <ClInclude Include="src\Control.h" />
-    <ClInclude Include="src\ControlFactory.h" />
-    <ClInclude Include="src\Curve.h" />
-    <ClInclude Include="src\DebugNew.h" />
-    <ClInclude Include="src\DepthStencilTarget.h" />
-    <ClInclude Include="src\Effect.h" />
-    <ClInclude Include="src\FileSystem.h" />
-    <ClInclude Include="src\FlowLayout.h" />
-    <ClInclude Include="src\Font.h" />
-    <ClInclude Include="src\Form.h" />
-    <ClInclude Include="src\FrameBuffer.h" />
-    <ClInclude Include="src\Frustum.h" />
-    <ClInclude Include="src\Game.h" />
-    <ClInclude Include="src\Gamepad.h" />
-    <ClInclude Include="src\gameplay.h" />
-    <ClInclude Include="src\Gesture.h" />
-    <ClInclude Include="src\HeightField.h" />
-    <ClInclude Include="src\Image.h" />
-    <ClInclude Include="src\ImageControl.h" />
-    <ClInclude Include="src\Joint.h" />
-    <ClInclude Include="src\Joystick.h" />
-    <ClInclude Include="src\Keyboard.h" />
-    <ClInclude Include="src\Label.h" />
-    <ClInclude Include="src\Layout.h" />
-    <ClInclude Include="src\Light.h" />
-    <ClInclude Include="src\Logger.h" />
-    <ClInclude Include="src\lua\lua_AbsoluteLayout.h" />
-    <ClInclude Include="src\lua\lua_AIAgent.h" />
-    <ClInclude Include="src\lua\lua_AIAgentListener.h" />
-    <ClInclude Include="src\lua\lua_AIController.h" />
-    <ClInclude Include="src\lua\lua_AIMessage.h" />
-    <ClInclude Include="src\lua\lua_AIMessageParameterType.h" />
-    <ClInclude Include="src\lua\lua_AIState.h" />
-    <ClInclude Include="src\lua\lua_AIStateListener.h" />
-    <ClInclude Include="src\lua\lua_AIStateMachine.h" />
-    <ClInclude Include="src\lua\lua_all_bindings.h" />
-    <ClInclude Include="src\lua\lua_Animation.h" />
-    <ClInclude Include="src\lua\lua_AnimationClip.h" />
-    <ClInclude Include="src\lua\lua_AnimationClipListener.h" />
-    <ClInclude Include="src\lua\lua_AnimationClipListenerEventType.h" />
-    <ClInclude Include="src\lua\lua_AnimationController.h" />
-    <ClInclude Include="src\lua\lua_AnimationTarget.h" />
-    <ClInclude Include="src\lua\lua_AnimationValue.h" />
-    <ClInclude Include="src\lua\lua_AudioBuffer.h" />
-    <ClInclude Include="src\lua\lua_AudioController.h" />
-    <ClInclude Include="src\lua\lua_AudioListener.h" />
-    <ClInclude Include="src\lua\lua_AudioSource.h" />
-    <ClInclude Include="src\lua\lua_AudioSourceState.h" />
-    <ClInclude Include="src\lua\lua_BoundingBox.h" />
-    <ClInclude Include="src\lua\lua_BoundingSphere.h" />
-    <ClInclude Include="src\lua\lua_Bundle.h" />
-    <ClInclude Include="src\lua\lua_Button.h" />
-    <ClInclude Include="src\lua\lua_Camera.h" />
-    <ClInclude Include="src\lua\lua_CameraType.h" />
-    <ClInclude Include="src\lua\lua_CheckBox.h" />
-    <ClInclude Include="src\lua\lua_Container.h" />
-    <ClInclude Include="src\lua\lua_ContainerScroll.h" />
-    <ClInclude Include="src\lua\lua_Control.h" />
-    <ClInclude Include="src\lua\lua_ControlAlignment.h" />
-    <ClInclude Include="src\lua\lua_ControlAutoSize.h" />
-    <ClInclude Include="src\lua\lua_ControlListener.h" />
-    <ClInclude Include="src\lua\lua_ControlListenerEventType.h" />
-    <ClInclude Include="src\lua\lua_ControlState.h" />
-    <ClInclude Include="src\lua\lua_Curve.h" />
-    <ClInclude Include="src\lua\lua_CurveInterpolationType.h" />
-    <ClInclude Include="src\lua\lua_DepthStencilTarget.h" />
-    <ClInclude Include="src\lua\lua_DepthStencilTargetFormat.h" />
-    <ClInclude Include="src\lua\lua_Effect.h" />
-    <ClInclude Include="src\lua\lua_FileSystem.h" />
-    <ClInclude Include="src\lua\lua_FlowLayout.h" />
-    <ClInclude Include="src\lua\lua_Font.h" />
-    <ClInclude Include="src\lua\lua_FontFormat.h" />
-    <ClInclude Include="src\lua\lua_FontJustify.h" />
-    <ClInclude Include="src\lua\lua_FontStyle.h" />
-    <ClInclude Include="src\lua\lua_FontText.h" />
-    <ClInclude Include="src\lua\lua_Form.h" />
-    <ClInclude Include="src\lua\lua_FrameBuffer.h" />
-    <ClInclude Include="src\lua\lua_Frustum.h" />
-    <ClInclude Include="src\lua\lua_Game.h" />
-    <ClInclude Include="src\lua\lua_GameClearFlags.h" />
-    <ClInclude Include="src\lua\lua_Gamepad.h" />
-    <ClInclude Include="src\lua\lua_GamepadButtonMapping.h" />
-    <ClInclude Include="src\lua\lua_GamepadGamepadEvent.h" />
-    <ClInclude Include="src\lua\lua_GameState.h" />
-    <ClInclude Include="src\lua\lua_Gesture.h" />
-    <ClInclude Include="src\lua\lua_GestureGestureEvent.h" />
-    <ClInclude Include="src\lua\lua_Global.h" />
-    <ClInclude Include="src\lua\lua_HeightField.h" />
-    <ClInclude Include="src\lua\lua_Image.h" />
-    <ClInclude Include="src\lua\lua_ImageControl.h" />
-    <ClInclude Include="src\lua\lua_ImageFormat.h" />
-    <ClInclude Include="src\lua\lua_Joint.h" />
-    <ClInclude Include="src\lua\lua_Joystick.h" />
-    <ClInclude Include="src\lua\lua_Keyboard.h" />
-    <ClInclude Include="src\lua\lua_KeyboardKey.h" />
-    <ClInclude Include="src\lua\lua_KeyboardKeyEvent.h" />
-    <ClInclude Include="src\lua\lua_Label.h" />
-    <ClInclude Include="src\lua\lua_Layout.h" />
-    <ClInclude Include="src\lua\lua_LayoutType.h" />
-    <ClInclude Include="src\lua\lua_Light.h" />
-    <ClInclude Include="src\lua\lua_LightType.h" />
-    <ClInclude Include="src\lua\lua_Logger.h" />
-    <ClInclude Include="src\lua\lua_LoggerLevel.h" />
-    <ClInclude Include="src\lua\lua_Material.h" />
-    <ClInclude Include="src\lua\lua_MaterialParameter.h" />
-    <ClInclude Include="src\lua\lua_MathUtil.h" />
-    <ClInclude Include="src\lua\lua_Matrix.h" />
-    <ClInclude Include="src\lua\lua_Mesh.h" />
-    <ClInclude Include="src\lua\lua_MeshBatch.h" />
-    <ClInclude Include="src\lua\lua_MeshIndexFormat.h" />
-    <ClInclude Include="src\lua\lua_MeshPart.h" />
-    <ClInclude Include="src\lua\lua_MeshPrimitiveType.h" />
-    <ClInclude Include="src\lua\lua_MeshSkin.h" />
-    <ClInclude Include="src\lua\lua_Model.h" />
-    <ClInclude Include="src\lua\lua_Mouse.h" />
-    <ClInclude Include="src\lua\lua_MouseMouseEvent.h" />
-    <ClInclude Include="src\lua\lua_Node.h" />
-    <ClInclude Include="src\lua\lua_NodeCloneContext.h" />
-    <ClInclude Include="src\lua\lua_NodeType.h" />
-    <ClInclude Include="src\lua\lua_ParticleEmitter.h" />
-    <ClInclude Include="src\lua\lua_ParticleEmitterTextureBlending.h" />
-    <ClInclude Include="src\lua\lua_Pass.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCharacter.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObject.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectType.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionShape.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeDefinition.h" />
-    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeType.h" />
-    <ClInclude Include="src\lua\lua_PhysicsConstraint.h" />
-    <ClInclude Include="src\lua\lua_PhysicsController.h" />
-    <ClInclude Include="src\lua\lua_PhysicsControllerHitFilter.h" />
-    <ClInclude Include="src\lua\lua_PhysicsControllerHitResult.h" />
-    <ClInclude Include="src\lua\lua_PhysicsControllerListener.h" />
-    <ClInclude Include="src\lua\lua_PhysicsControllerListenerEventType.h" />
-    <ClInclude Include="src\lua\lua_PhysicsFixedConstraint.h" />
-    <ClInclude Include="src\lua\lua_PhysicsGenericConstraint.h" />
-    <ClInclude Include="src\lua\lua_PhysicsGhostObject.h" />
-    <ClInclude Include="src\lua\lua_PhysicsHingeConstraint.h" />
-    <ClInclude Include="src\lua\lua_PhysicsRigidBody.h" />
-    <ClInclude Include="src\lua\lua_PhysicsRigidBodyParameters.h" />
-    <ClInclude Include="src\lua\lua_PhysicsSocketConstraint.h" />
-    <ClInclude Include="src\lua\lua_PhysicsSpringConstraint.h" />
-    <ClInclude Include="src\lua\lua_PhysicsVehicle.h" />
-    <ClInclude Include="src\lua\lua_PhysicsVehicleWheel.h" />
-    <ClInclude Include="src\lua\lua_Plane.h" />
-    <ClInclude Include="src\lua\lua_Platform.h" />
-    <ClInclude Include="src\lua\lua_Properties.h" />
-    <ClInclude Include="src\lua\lua_PropertiesType.h" />
-    <ClInclude Include="src\lua\lua_Quaternion.h" />
-    <ClInclude Include="src\lua\lua_RadioButton.h" />
-    <ClInclude Include="src\lua\lua_Ray.h" />
-    <ClInclude Include="src\lua\lua_Rectangle.h" />
-    <ClInclude Include="src\lua\lua_Ref.h" />
-    <ClInclude Include="src\lua\lua_RenderState.h" />
-    <ClInclude Include="src\lua\lua_RenderStateAutoBinding.h" />
-    <ClInclude Include="src\lua\lua_RenderStateBlend.h" />
-    <ClInclude Include="src\lua\lua_RenderStateCullFaceSide.h" />
-    <ClInclude Include="src\lua\lua_RenderStateDepthFunction.h" />
-    <ClInclude Include="src\lua\lua_RenderStateFrontFace.h" />
-    <ClInclude Include="src\lua\lua_RenderStateStateBlock.h" />
-    <ClInclude Include="src\lua\lua_RenderStateStencilFunction.h" />
-    <ClInclude Include="src\lua\lua_RenderStateStencilOperation.h" />
-    <ClInclude Include="src\lua\lua_RenderTarget.h" />
-    <ClInclude Include="src\lua\lua_Scene.h" />
-    <ClInclude Include="src\lua\lua_SceneDebugFlags.h" />
-    <ClInclude Include="src\lua\lua_SceneRenderer.h" />
-    <ClInclude Include="src\lua\lua_SceneRendererForward.h" />
-    <ClInclude Include="src\lua\lua_ScreenDisplayer.h" />
-    <ClInclude Include="src\lua\lua_ScriptController.h" />
-    <ClInclude Include="src\lua\lua_ScriptTarget.h" />
-    <ClInclude Include="src\lua\lua_Slider.h" />
-    <ClInclude Include="src\lua\lua_SpriteBatch.h" />
-    <ClInclude Include="src\lua\lua_Technique.h" />
-    <ClInclude Include="src\lua\lua_Terrain.h" />
-    <ClInclude Include="src\lua\lua_TerrainFlags.h" />
-    <ClInclude Include="src\lua\lua_TerrainListener.h" />
-    <ClInclude Include="src\lua\lua_TextBox.h" />
-    <ClInclude Include="src\lua\lua_TextBoxInputMode.h" />
-    <ClInclude Include="src\lua\lua_Texture.h" />
-    <ClInclude Include="src\lua\lua_TextureFilter.h" />
-    <ClInclude Include="src\lua\lua_TextureFormat.h" />
-    <ClInclude Include="src\lua\lua_TextureSampler.h" />
-    <ClInclude Include="src\lua\lua_TextureWrap.h" />
-    <ClInclude Include="src\lua\lua_Theme.h" />
-    <ClInclude Include="src\lua\lua_ThemeSideRegions.h" />
-    <ClInclude Include="src\lua\lua_ThemeStyle.h" />
-    <ClInclude Include="src\lua\lua_ThemeThemeImage.h" />
-    <ClInclude Include="src\lua\lua_ThemeUVs.h" />
-    <ClInclude Include="src\lua\lua_Touch.h" />
-    <ClInclude Include="src\lua\lua_TouchTouchEvent.h" />
-    <ClInclude Include="src\lua\lua_Transform.h" />
-    <ClInclude Include="src\lua\lua_TransformListener.h" />
-    <ClInclude Include="src\lua\lua_Uniform.h" />
-    <ClInclude Include="src\lua\lua_Vector2.h" />
-    <ClInclude Include="src\lua\lua_Vector3.h" />
-    <ClInclude Include="src\lua\lua_Vector4.h" />
-    <ClInclude Include="src\lua\lua_VertexAttributeBinding.h" />
-    <ClInclude Include="src\lua\lua_VertexFormat.h" />
-    <ClInclude Include="src\lua\lua_VertexFormatElement.h" />
-    <ClInclude Include="src\lua\lua_VertexFormatUsage.h" />
-    <ClInclude Include="src\lua\lua_VerticalLayout.h" />
-    <ClInclude Include="src\lua\lua_VisibleSet.h" />
-    <ClInclude Include="src\lua\lua_VisibleSetDefault.h" />
-    <ClInclude Include="src\Material.h" />
-    <ClInclude Include="src\MathUtil.h" />
-    <ClInclude Include="src\MeshBatch.h" />
-    <ClInclude Include="src\Mouse.h" />
-    <ClInclude Include="src\Pass.h" />
-    <ClInclude Include="src\MaterialParameter.h" />
-    <ClInclude Include="src\Matrix.h" />
-    <ClInclude Include="src\Mesh.h" />
-    <ClInclude Include="src\MeshPart.h" />
-    <ClInclude Include="src\MeshSkin.h" />
-    <ClInclude Include="src\Model.h" />
-    <ClInclude Include="src\Node.h" />
-    <ClInclude Include="src\Bundle.h" />
-    <ClInclude Include="src\ParticleEmitter.h" />
-    <ClInclude Include="src\PhysicsCharacter.h" />
-    <ClInclude Include="src\PhysicsCollisionObject.h" />
-    <ClInclude Include="src\PhysicsCollisionShape.h" />
-    <ClInclude Include="src\PhysicsConstraint.h" />
-    <ClInclude Include="src\PhysicsController.h" />
-    <ClInclude Include="src\PhysicsFixedConstraint.h" />
-    <ClInclude Include="src\PhysicsGenericConstraint.h" />
-    <ClInclude Include="src\PhysicsGhostObject.h" />
-    <ClInclude Include="src\PhysicsHingeConstraint.h" />
-    <ClInclude Include="src\PhysicsRigidBody.h" />
-    <ClInclude Include="src\PhysicsSocketConstraint.h" />
-    <ClInclude Include="src\PhysicsSpringConstraint.h" />
-    <ClInclude Include="src\PhysicsVehicle.h" />
-    <ClInclude Include="src\PhysicsVehicleWheel.h" />
-    <ClInclude Include="src\Plane.h" />
-    <ClInclude Include="src\Platform.h" />
-    <ClInclude Include="src\Properties.h" />
-    <ClInclude Include="src\Quaternion.h" />
-    <ClInclude Include="src\RadioButton.h" />
-    <ClInclude Include="src\Ray.h" />
-    <ClInclude Include="src\Rectangle.h" />
-    <ClInclude Include="src\Ref.h" />
-    <ClInclude Include="src\RenderState.h" />
-    <ClInclude Include="src\RenderTarget.h" />
-    <ClInclude Include="src\Scene.h" />
-    <ClInclude Include="src\SceneLoader.h" />
-    <ClInclude Include="src\SceneRenderer.h" />
-    <ClInclude Include="src\SceneRendererForward.h" />
-    <ClInclude Include="src\ScreenDisplayer.h" />
-    <ClInclude Include="src\ScriptController.h" />
-    <ClInclude Include="src\ScriptTarget.h" />
-    <ClInclude Include="src\Slider.h" />
-    <ClInclude Include="src\SocialAchievement.h" />
-    <ClInclude Include="src\SocialChallenge.h" />
-    <ClInclude Include="src\SocialController.h" />
-    <ClInclude Include="src\SocialPlayer.h" />
-    <ClInclude Include="src\SocialScore.h" />
-    <ClInclude Include="src\SocialSession.h" />
-    <ClInclude Include="src\SocialSessionListener.h" />
-    <ClInclude Include="src\social\GooglePlaySocialSession.h" />
-    <ClInclude Include="src\social\ScoreloopSocialSession.h" />
-    <ClInclude Include="src\SpriteBatch.h" />
-    <ClInclude Include="src\Stream.h" />
-    <ClInclude Include="src\Technique.h" />
-    <ClInclude Include="src\Terrain.h" />
-    <ClInclude Include="src\TerrainPatch.h" />
-    <ClInclude Include="src\TextBox.h" />
-    <ClInclude Include="src\Texture.h" />
-    <ClInclude Include="src\Theme.h" />
-    <ClInclude Include="src\ThemeStyle.h" />
-    <ClInclude Include="src\TimeListener.h" />
-    <ClInclude Include="src\Touch.h" />
-    <ClInclude Include="src\Transform.h" />
-    <ClInclude Include="src\Vector2.h" />
-    <ClInclude Include="src\Vector3.h" />
-    <ClInclude Include="src\Vector4.h" />
-    <ClInclude Include="src\VertexAttributeBinding.h" />
-    <ClInclude Include="src\VertexFormat.h" />
-    <ClInclude Include="src\VerticalLayout.h" />
-    <ClInclude Include="src\VisibleSet.h" />
-    <ClInclude Include="src\VisibleSetDefault.h" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="res\logo_black.png" />
-    <None Include="res\logo_powered_black.png" />
-    <None Include="res\logo_powered_white.png" />
-    <None Include="res\logo_white.png" />
-    <None Include="res\shaders\colored.frag" />
-    <None Include="res\shaders\colored.vert" />
-    <None Include="res\shaders\font.frag" />
-    <None Include="res\shaders\font.vert" />
-    <None Include="res\shaders\form.frag" />
-    <None Include="res\shaders\form.vert" />
-    <None Include="res\shaders\lighting.frag" />
-    <None Include="res\shaders\lighting.vert" />
-    <None Include="res\shaders\skinning-none.vert" />
-    <None Include="res\shaders\skinning.vert" />
-    <None Include="res\shaders\sprite.frag" />
-    <None Include="res\shaders\sprite.vert" />
-    <None Include="res\shaders\terrain.frag" />
-    <None Include="res\shaders\terrain.vert" />
-    <None Include="res\shaders\textured.frag" />
-    <None Include="res\shaders\textured.vert" />
-    <None Include="src\BoundingBox.inl" />
-    <None Include="src\BoundingSphere.inl" />
-    <None Include="src\Game.inl" />
-    <None Include="src\Image.inl" />
-    <None Include="src\MathUtil.inl" />
-    <None Include="src\MathUtilNeon.inl" />
-    <None Include="src\Joystick.inl" />
-    <None Include="src\Matrix.inl" />
-    <None Include="src\MeshBatch.inl" />
-    <None Include="src\Plane.inl" />
-    <None Include="src\Quaternion.inl" />
-    <None Include="src\Ray.inl" />
-    <None Include="src\ScriptController.inl" />
-    <None Include="src\Vector2.inl" />
-    <None Include="src\Vector3.inl" />
-    <None Include="src\Vector4.inl" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="src\PhysicsConstraint.inl" />
-    <None Include="src\PhysicsFixedConstraint.inl" />
-    <None Include="src\PhysicsGenericConstraint.inl" />
-    <None Include="src\PhysicsRigidBody.inl" />
-    <None Include="src\PhysicsSpringConstraint.inl" />
-  </ItemGroup>
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>{1032BA4B-57EB-4348-9E03-29DD63E80E4A}</ProjectGuid>
-    <Keyword>Win32Proj</Keyword>
-    <RootNamespace>gameplay</RootNamespace>
-  </PropertyGroup>
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>true</UseDebugLibraries>
-    <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v120</PlatformToolset>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <ConfigurationType>StaticLibrary</ConfigurationType>
-    <UseDebugLibraries>false</UseDebugLibraries>
-    <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
-    <PlatformToolset>v120</PlatformToolset>
-  </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|x64'" 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|x64'" 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|x64'" 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>windows\x86\$(Configuration)\</OutDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <OutDir>windows\x64\$(Configuration)\</OutDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
-    <OutDir>windows\x86\$(Configuration)\</OutDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'">
-    <OutDir>windows\x64\$(Configuration)\</OutDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <IntDir>windows\x86\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <IntDir>windows\x64\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
-    <IntDir>windows\x86\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'">
-    <IntDir>windows\x64\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <OutDir>windows\x86\$(Configuration)\</OutDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <OutDir>windows\x64\$(Configuration)\</OutDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <IntDir>windows\x86\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <IntDir>windows\x64\$(Configuration)\</IntDir>
-  </PropertyGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <RuntimeTypeInfo>
-      </RuntimeTypeInfo>
-      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
-      <DisableSpecificWarnings>
-      </DisableSpecificWarnings>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-    </Link>
-    <Lib>
-      <TargetMachine>MachineX86</TargetMachine>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <RuntimeTypeInfo>
-      </RuntimeTypeInfo>
-      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-    </Link>
-    <Lib>
-      <TargetMachine>MachineX64</TargetMachine>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
-    <ClCompile>
-      <PrecompiledHeader>
-      </PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;GP_USE_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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <RuntimeTypeInfo>true</RuntimeTypeInfo>
-      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
-      <DisableSpecificWarnings>
-      </DisableSpecificWarnings>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-    </Link>
-    <Lib>
-      <Verbose>
-      </Verbose>
-      <AdditionalDependencies>
-      </AdditionalDependencies>
-      <AdditionalLibraryDirectories>
-      </AdditionalLibraryDirectories>
-    </Lib>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'">
-    <ClCompile>
-      <PrecompiledHeader>
-      </PrecompiledHeader>
-      <WarningLevel>Level3</WarningLevel>
-      <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;GP_USE_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\png\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>
-      <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <DebugInformationFormat>
-      </DebugInformationFormat>
-      <DisableSpecificWarnings>
-      </DisableSpecificWarnings>
-    </ClCompile>
-    <Link>
-      <SubSystem>Windows</SubSystem>
-      <GenerateDebugInformation>true</GenerateDebugInformation>
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
-    </Link>
-  </ItemDefinitionGroup>
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <DebugInformationFormat>
-      </DebugInformationFormat>
-    </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>
+<?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|Win32">
+      <Configuration>DebugMem</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="DebugMem|x64">
+      <Configuration>DebugMem</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\AbsoluteLayout.cpp" />
+    <ClCompile Include="src\AIAgent.cpp" />
+    <ClCompile Include="src\AIController.cpp" />
+    <ClCompile Include="src\AIMessage.cpp" />
+    <ClCompile Include="src\AIState.cpp" />
+    <ClCompile Include="src\AIStateMachine.cpp" />
+    <ClCompile Include="src\Animation.cpp" />
+    <ClCompile Include="src\AnimationClip.cpp" />
+    <ClCompile Include="src\AnimationController.cpp" />
+    <ClCompile Include="src\AnimationTarget.cpp" />
+    <ClCompile Include="src\AnimationValue.cpp" />
+    <ClCompile Include="src\AudioBuffer.cpp" />
+    <ClCompile Include="src\AudioController.cpp" />
+    <ClCompile Include="src\AudioListener.cpp" />
+    <ClCompile Include="src\AudioSource.cpp" />
+    <ClCompile Include="src\BoundingBox.cpp" />
+    <ClCompile Include="src\BoundingSphere.cpp" />
+    <ClCompile Include="src\Button.cpp" />
+    <ClCompile Include="src\Camera.cpp" />
+    <ClCompile Include="src\CheckBox.cpp" />
+    <ClCompile Include="src\Container.cpp" />
+    <ClCompile Include="src\Control.cpp" />
+    <ClCompile Include="src\ControlFactory.cpp" />
+    <ClCompile Include="src\Curve.cpp" />
+    <ClCompile Include="src\DebugNew.cpp" />
+    <ClCompile Include="src\DepthStencilTarget.cpp" />
+    <ClCompile Include="src\Effect.cpp" />
+    <ClCompile Include="src\FileSystem.cpp" />
+    <ClCompile Include="src\FlowLayout.cpp" />
+    <ClCompile Include="src\Font.cpp" />
+    <ClCompile Include="src\Form.cpp" />
+    <ClCompile Include="src\FrameBuffer.cpp" />
+    <ClCompile Include="src\Frustum.cpp" />
+    <ClCompile Include="src\Game.cpp" />
+    <ClCompile Include="src\Gamepad.cpp" />
+    <ClCompile Include="src\gameplay-main-android.cpp" />
+    <ClCompile Include="src\gameplay-main-blackberry.cpp" />
+    <ClCompile Include="src\gameplay-main-linux.cpp" />
+    <ClCompile Include="src\gameplay-main-windows.cpp" />
+    <ClCompile Include="src\HeightField.cpp" />
+    <ClCompile Include="src\Image.cpp" />
+    <ClCompile Include="src\ImageControl.cpp" />
+    <ClCompile Include="src\Joint.cpp" />
+    <ClCompile Include="src\Joystick.cpp" />
+    <ClCompile Include="src\Label.cpp" />
+    <ClCompile Include="src\Layout.cpp" />
+    <ClCompile Include="src\Light.cpp" />
+    <ClCompile Include="src\Logger.cpp" />
+    <ClCompile Include="src\lua\lua_AbsoluteLayout.cpp" />
+    <ClCompile Include="src\lua\lua_AIAgent.cpp" />
+    <ClCompile Include="src\lua\lua_AIAgentListener.cpp" />
+    <ClCompile Include="src\lua\lua_AIController.cpp" />
+    <ClCompile Include="src\lua\lua_AIMessage.cpp" />
+    <ClCompile Include="src\lua\lua_AIMessageParameterType.cpp" />
+    <ClCompile Include="src\lua\lua_AIState.cpp" />
+    <ClCompile Include="src\lua\lua_AIStateListener.cpp" />
+    <ClCompile Include="src\lua\lua_AIStateMachine.cpp" />
+    <ClCompile Include="src\lua\lua_all_bindings.cpp" />
+    <ClCompile Include="src\lua\lua_Animation.cpp" />
+    <ClCompile Include="src\lua\lua_AnimationClip.cpp" />
+    <ClCompile Include="src\lua\lua_AnimationClipListener.cpp" />
+    <ClCompile Include="src\lua\lua_AnimationClipListenerEventType.cpp" />
+    <ClCompile Include="src\lua\lua_AnimationController.cpp" />
+    <ClCompile Include="src\lua\lua_AnimationTarget.cpp" />
+    <ClCompile Include="src\lua\lua_AnimationValue.cpp" />
+    <ClCompile Include="src\lua\lua_AudioBuffer.cpp" />
+    <ClCompile Include="src\lua\lua_AudioController.cpp" />
+    <ClCompile Include="src\lua\lua_AudioListener.cpp" />
+    <ClCompile Include="src\lua\lua_AudioSource.cpp" />
+    <ClCompile Include="src\lua\lua_AudioSourceState.cpp" />
+    <ClCompile Include="src\lua\lua_BoundingBox.cpp" />
+    <ClCompile Include="src\lua\lua_BoundingSphere.cpp" />
+    <ClCompile Include="src\lua\lua_Bundle.cpp" />
+    <ClCompile Include="src\lua\lua_Button.cpp" />
+    <ClCompile Include="src\lua\lua_Camera.cpp" />
+    <ClCompile Include="src\lua\lua_CameraListener.cpp" />
+    <ClCompile Include="src\lua\lua_CameraType.cpp" />
+    <ClCompile Include="src\lua\lua_CheckBox.cpp" />
+    <ClCompile Include="src\lua\lua_Container.cpp" />
+    <ClCompile Include="src\lua\lua_ContainerScroll.cpp" />
+    <ClCompile Include="src\lua\lua_Control.cpp" />
+    <ClCompile Include="src\lua\lua_ControlAlignment.cpp" />
+    <ClCompile Include="src\lua\lua_ControlAutoSize.cpp" />
+    <ClCompile Include="src\lua\lua_ControlListener.cpp" />
+    <ClCompile Include="src\lua\lua_ControlListenerEventType.cpp" />
+    <ClCompile Include="src\lua\lua_ControlState.cpp" />
+    <ClCompile Include="src\lua\lua_Curve.cpp" />
+    <ClCompile Include="src\lua\lua_CurveInterpolationType.cpp" />
+    <ClCompile Include="src\lua\lua_DepthStencilTarget.cpp" />
+    <ClCompile Include="src\lua\lua_DepthStencilTargetFormat.cpp" />
+    <ClCompile Include="src\lua\lua_Effect.cpp" />
+    <ClCompile Include="src\lua\lua_FileSystem.cpp" />
+    <ClCompile Include="src\lua\lua_FlowLayout.cpp" />
+    <ClCompile Include="src\lua\lua_Font.cpp" />
+    <ClCompile Include="src\lua\lua_FontFormat.cpp" />
+    <ClCompile Include="src\lua\lua_FontJustify.cpp" />
+    <ClCompile Include="src\lua\lua_FontStyle.cpp" />
+    <ClCompile Include="src\lua\lua_FontText.cpp" />
+    <ClCompile Include="src\lua\lua_Form.cpp" />
+    <ClCompile Include="src\lua\lua_FrameBuffer.cpp" />
+    <ClCompile Include="src\lua\lua_Frustum.cpp" />
+    <ClCompile Include="src\lua\lua_Game.cpp" />
+    <ClCompile Include="src\lua\lua_GameClearFlags.cpp" />
+    <ClCompile Include="src\lua\lua_Gamepad.cpp" />
+    <ClCompile Include="src\lua\lua_GamepadButtonMapping.cpp" />
+    <ClCompile Include="src\lua\lua_GamepadGamepadEvent.cpp" />
+    <ClCompile Include="src\lua\lua_GameState.cpp" />
+    <ClCompile Include="src\lua\lua_Gesture.cpp" />
+    <ClCompile Include="src\lua\lua_GestureGestureEvent.cpp" />
+    <ClCompile Include="src\lua\lua_Global.cpp" />
+    <ClCompile Include="src\lua\lua_HeightField.cpp" />
+    <ClCompile Include="src\lua\lua_Image.cpp" />
+    <ClCompile Include="src\lua\lua_ImageControl.cpp" />
+    <ClCompile Include="src\lua\lua_ImageFormat.cpp" />
+    <ClCompile Include="src\lua\lua_Joint.cpp" />
+    <ClCompile Include="src\lua\lua_Joystick.cpp" />
+    <ClCompile Include="src\lua\lua_Keyboard.cpp" />
+    <ClCompile Include="src\lua\lua_KeyboardKey.cpp" />
+    <ClCompile Include="src\lua\lua_KeyboardKeyEvent.cpp" />
+    <ClCompile Include="src\lua\lua_Label.cpp" />
+    <ClCompile Include="src\lua\lua_Layout.cpp" />
+    <ClCompile Include="src\lua\lua_LayoutType.cpp" />
+    <ClCompile Include="src\lua\lua_Light.cpp" />
+    <ClCompile Include="src\lua\lua_LightType.cpp" />
+    <ClCompile Include="src\lua\lua_Logger.cpp" />
+    <ClCompile Include="src\lua\lua_LoggerLevel.cpp" />
+    <ClCompile Include="src\lua\lua_Material.cpp" />
+    <ClCompile Include="src\lua\lua_MaterialParameter.cpp" />
+    <ClCompile Include="src\lua\lua_MathUtil.cpp" />
+    <ClCompile Include="src\lua\lua_Matrix.cpp" />
+    <ClCompile Include="src\lua\lua_Mesh.cpp" />
+    <ClCompile Include="src\lua\lua_MeshBatch.cpp" />
+    <ClCompile Include="src\lua\lua_MeshIndexFormat.cpp" />
+    <ClCompile Include="src\lua\lua_MeshPart.cpp" />
+    <ClCompile Include="src\lua\lua_MeshPrimitiveType.cpp" />
+    <ClCompile Include="src\lua\lua_MeshSkin.cpp" />
+    <ClCompile Include="src\lua\lua_Model.cpp" />
+    <ClCompile Include="src\lua\lua_Mouse.cpp" />
+    <ClCompile Include="src\lua\lua_MouseMouseEvent.cpp" />
+    <ClCompile Include="src\lua\lua_Node.cpp" />
+    <ClCompile Include="src\lua\lua_NodeCloneContext.cpp" />
+    <ClCompile Include="src\lua\lua_NodeType.cpp" />
+    <ClCompile Include="src\lua\lua_ParticleEmitter.cpp" />
+    <ClCompile Include="src\lua\lua_ParticleEmitterTextureBlending.cpp" />
+    <ClCompile Include="src\lua\lua_Pass.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCharacter.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObject.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectType.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionShape.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeDefinition.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeType.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsConstraint.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsController.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsControllerHitFilter.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsControllerHitResult.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsControllerListener.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsControllerListenerEventType.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsFixedConstraint.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsGenericConstraint.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsGhostObject.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsHingeConstraint.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsRigidBody.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsRigidBodyParameters.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsSocketConstraint.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsSpringConstraint.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsVehicle.cpp" />
+    <ClCompile Include="src\lua\lua_PhysicsVehicleWheel.cpp" />
+    <ClCompile Include="src\lua\lua_Plane.cpp" />
+    <ClCompile Include="src\lua\lua_Platform.cpp" />
+    <ClCompile Include="src\lua\lua_Properties.cpp" />
+    <ClCompile Include="src\lua\lua_PropertiesType.cpp" />
+    <ClCompile Include="src\lua\lua_Quaternion.cpp" />
+    <ClCompile Include="src\lua\lua_RadioButton.cpp" />
+    <ClCompile Include="src\lua\lua_Ray.cpp" />
+    <ClCompile Include="src\lua\lua_Rectangle.cpp" />
+    <ClCompile Include="src\lua\lua_Ref.cpp" />
+    <ClCompile Include="src\lua\lua_RenderState.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateAutoBinding.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateBlend.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateCullFaceSide.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateDepthFunction.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateFrontFace.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateStateBlock.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateStencilFunction.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateStencilOperation.cpp" />
+    <ClCompile Include="src\lua\lua_RenderTarget.cpp" />
+    <ClCompile Include="src\lua\lua_Scene.cpp" />
+    <ClCompile Include="src\lua\lua_ScreenDisplayer.cpp" />
+    <ClCompile Include="src\lua\lua_ScriptController.cpp" />
+    <ClCompile Include="src\lua\lua_ScriptTarget.cpp" />
+    <ClCompile Include="src\lua\lua_Slider.cpp" />
+    <ClCompile Include="src\lua\lua_SpriteBatch.cpp" />
+    <ClCompile Include="src\lua\lua_Technique.cpp" />
+    <ClCompile Include="src\lua\lua_Terrain.cpp" />
+    <ClCompile Include="src\lua\lua_TerrainFlags.cpp" />
+    <ClCompile Include="src\lua\lua_TerrainPatch.cpp" />
+    <ClCompile Include="src\lua\lua_TextBox.cpp" />
+    <ClCompile Include="src\lua\lua_TextBoxInputMode.cpp" />
+    <ClCompile Include="src\lua\lua_Texture.cpp" />
+    <ClCompile Include="src\lua\lua_TextureFilter.cpp" />
+    <ClCompile Include="src\lua\lua_TextureFormat.cpp" />
+    <ClCompile Include="src\lua\lua_TextureSampler.cpp" />
+    <ClCompile Include="src\lua\lua_TextureWrap.cpp" />
+    <ClCompile Include="src\lua\lua_Theme.cpp" />
+    <ClCompile Include="src\lua\lua_ThemeSideRegions.cpp" />
+    <ClCompile Include="src\lua\lua_ThemeStyle.cpp" />
+    <ClCompile Include="src\lua\lua_ThemeThemeImage.cpp" />
+    <ClCompile Include="src\lua\lua_ThemeUVs.cpp" />
+    <ClCompile Include="src\lua\lua_Touch.cpp" />
+    <ClCompile Include="src\lua\lua_TouchTouchEvent.cpp" />
+    <ClCompile Include="src\lua\lua_Transform.cpp" />
+    <ClCompile Include="src\lua\lua_TransformListener.cpp" />
+    <ClCompile Include="src\lua\lua_Uniform.cpp" />
+    <ClCompile Include="src\lua\lua_Vector2.cpp" />
+    <ClCompile Include="src\lua\lua_Vector3.cpp" />
+    <ClCompile Include="src\lua\lua_Vector4.cpp" />
+    <ClCompile Include="src\lua\lua_VertexAttributeBinding.cpp" />
+    <ClCompile Include="src\lua\lua_VertexFormat.cpp" />
+    <ClCompile Include="src\lua\lua_VertexFormatElement.cpp" />
+    <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" />
+    <ClCompile Include="src\Matrix.cpp" />
+    <ClCompile Include="src\Mesh.cpp" />
+    <ClCompile Include="src\MeshPart.cpp" />
+    <ClCompile Include="src\MeshSkin.cpp" />
+    <ClCompile Include="src\Model.cpp" />
+    <ClCompile Include="src\Node.cpp" />
+    <ClCompile Include="src\Bundle.cpp" />
+    <ClCompile Include="src\ParticleEmitter.cpp" />
+    <ClCompile Include="src\PhysicsCharacter.cpp" />
+    <ClCompile Include="src\PhysicsCollisionObject.cpp" />
+    <ClCompile Include="src\PhysicsCollisionShape.cpp" />
+    <ClCompile Include="src\PhysicsConstraint.cpp" />
+    <ClCompile Include="src\PhysicsController.cpp" />
+    <ClCompile Include="src\PhysicsFixedConstraint.cpp" />
+    <ClCompile Include="src\PhysicsGenericConstraint.cpp" />
+    <ClCompile Include="src\PhysicsGhostObject.cpp" />
+    <ClCompile Include="src\PhysicsHingeConstraint.cpp" />
+    <ClCompile Include="src\PhysicsRigidBody.cpp" />
+    <ClCompile Include="src\PhysicsSocketConstraint.cpp" />
+    <ClCompile Include="src\PhysicsSpringConstraint.cpp" />
+    <ClCompile Include="src\PhysicsVehicle.cpp" />
+    <ClCompile Include="src\PhysicsVehicleWheel.cpp" />
+    <ClCompile Include="src\Plane.cpp" />
+    <ClCompile Include="src\Platform.cpp" />
+    <ClCompile Include="src\PlatformAndroid.cpp" />
+    <ClCompile Include="src\PlatformBlackBerry.cpp" />
+    <ClCompile Include="src\PlatformLinux.cpp" />
+    <ClCompile Include="src\PlatformWindows.cpp" />
+    <ClCompile Include="src\Properties.cpp" />
+    <ClCompile Include="src\Quaternion.cpp" />
+    <ClCompile Include="src\RadioButton.cpp" />
+    <ClCompile Include="src\Ray.cpp" />
+    <ClCompile Include="src\Rectangle.cpp" />
+    <ClCompile Include="src\Ref.cpp" />
+    <ClCompile Include="src\RenderState.cpp" />
+    <ClCompile Include="src\RenderTarget.cpp" />
+    <ClCompile Include="src\Scene.cpp" />
+    <ClCompile Include="src\SceneLoader.cpp" />
+    <ClCompile Include="src\ScreenDisplayer.cpp" />
+    <ClCompile Include="src\ScriptController.cpp" />
+    <ClCompile Include="src\ScriptTarget.cpp" />
+    <ClCompile Include="src\Slider.cpp" />
+    <ClCompile Include="src\SpriteBatch.cpp" />
+    <ClCompile Include="src\Technique.cpp" />
+    <ClCompile Include="src\Terrain.cpp" />
+    <ClCompile Include="src\TerrainPatch.cpp" />
+    <ClCompile Include="src\TextBox.cpp" />
+    <ClCompile Include="src\Texture.cpp" />
+    <ClCompile Include="src\Theme.cpp" />
+    <ClCompile Include="src\ThemeStyle.cpp" />
+    <ClCompile Include="src\Transform.cpp" />
+    <ClCompile Include="src\Vector2.cpp" />
+    <ClCompile Include="src\Vector3.cpp" />
+    <ClCompile Include="src\Vector4.cpp" />
+    <ClCompile Include="src\VertexAttributeBinding.cpp" />
+    <ClCompile Include="src\VertexFormat.cpp" />
+    <ClCompile Include="src\VerticalLayout.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="src\AbsoluteLayout.h" />
+    <ClInclude Include="src\AIAgent.h" />
+    <ClInclude Include="src\AIController.h" />
+    <ClInclude Include="src\AIMessage.h" />
+    <ClInclude Include="src\AIState.h" />
+    <ClInclude Include="src\AIStateMachine.h" />
+    <ClInclude Include="src\Animation.h" />
+    <ClInclude Include="src\AnimationClip.h" />
+    <ClInclude Include="src\AnimationController.h" />
+    <ClInclude Include="src\AnimationTarget.h" />
+    <ClInclude Include="src\AnimationValue.h" />
+    <ClInclude Include="src\AudioBuffer.h" />
+    <ClInclude Include="src\AudioController.h" />
+    <ClInclude Include="src\AudioListener.h" />
+    <ClInclude Include="src\AudioSource.h" />
+    <ClInclude Include="src\Base.h" />
+    <ClInclude Include="src\BoundingBox.h" />
+    <ClInclude Include="src\BoundingSphere.h" />
+    <ClInclude Include="src\Button.h" />
+    <ClInclude Include="src\Camera.h" />
+    <ClInclude Include="src\CheckBox.h" />
+    <ClInclude Include="src\Container.h" />
+    <ClInclude Include="src\Control.h" />
+    <ClInclude Include="src\ControlFactory.h" />
+    <ClInclude Include="src\Curve.h" />
+    <ClInclude Include="src\DebugNew.h" />
+    <ClInclude Include="src\DepthStencilTarget.h" />
+    <ClInclude Include="src\Effect.h" />
+    <ClInclude Include="src\FileSystem.h" />
+    <ClInclude Include="src\FlowLayout.h" />
+    <ClInclude Include="src\Font.h" />
+    <ClInclude Include="src\Form.h" />
+    <ClInclude Include="src\FrameBuffer.h" />
+    <ClInclude Include="src\Frustum.h" />
+    <ClInclude Include="src\Game.h" />
+    <ClInclude Include="src\Gamepad.h" />
+    <ClInclude Include="src\gameplay.h" />
+    <ClInclude Include="src\Gesture.h" />
+    <ClInclude Include="src\HeightField.h" />
+    <ClInclude Include="src\Image.h" />
+    <ClInclude Include="src\ImageControl.h" />
+    <ClInclude Include="src\Joint.h" />
+    <ClInclude Include="src\Joystick.h" />
+    <ClInclude Include="src\Keyboard.h" />
+    <ClInclude Include="src\Label.h" />
+    <ClInclude Include="src\Layout.h" />
+    <ClInclude Include="src\Light.h" />
+    <ClInclude Include="src\Logger.h" />
+    <ClInclude Include="src\lua\lua_AbsoluteLayout.h" />
+    <ClInclude Include="src\lua\lua_AIAgent.h" />
+    <ClInclude Include="src\lua\lua_AIAgentListener.h" />
+    <ClInclude Include="src\lua\lua_AIController.h" />
+    <ClInclude Include="src\lua\lua_AIMessage.h" />
+    <ClInclude Include="src\lua\lua_AIMessageParameterType.h" />
+    <ClInclude Include="src\lua\lua_AIState.h" />
+    <ClInclude Include="src\lua\lua_AIStateListener.h" />
+    <ClInclude Include="src\lua\lua_AIStateMachine.h" />
+    <ClInclude Include="src\lua\lua_all_bindings.h" />
+    <ClInclude Include="src\lua\lua_Animation.h" />
+    <ClInclude Include="src\lua\lua_AnimationClip.h" />
+    <ClInclude Include="src\lua\lua_AnimationClipListener.h" />
+    <ClInclude Include="src\lua\lua_AnimationClipListenerEventType.h" />
+    <ClInclude Include="src\lua\lua_AnimationController.h" />
+    <ClInclude Include="src\lua\lua_AnimationTarget.h" />
+    <ClInclude Include="src\lua\lua_AnimationValue.h" />
+    <ClInclude Include="src\lua\lua_AudioBuffer.h" />
+    <ClInclude Include="src\lua\lua_AudioController.h" />
+    <ClInclude Include="src\lua\lua_AudioListener.h" />
+    <ClInclude Include="src\lua\lua_AudioSource.h" />
+    <ClInclude Include="src\lua\lua_AudioSourceState.h" />
+    <ClInclude Include="src\lua\lua_BoundingBox.h" />
+    <ClInclude Include="src\lua\lua_BoundingSphere.h" />
+    <ClInclude Include="src\lua\lua_Bundle.h" />
+    <ClInclude Include="src\lua\lua_Button.h" />
+    <ClInclude Include="src\lua\lua_Camera.h" />
+    <ClInclude Include="src\lua\lua_CameraListener.h" />
+    <ClInclude Include="src\lua\lua_CameraType.h" />
+    <ClInclude Include="src\lua\lua_CheckBox.h" />
+    <ClInclude Include="src\lua\lua_Container.h" />
+    <ClInclude Include="src\lua\lua_ContainerScroll.h" />
+    <ClInclude Include="src\lua\lua_Control.h" />
+    <ClInclude Include="src\lua\lua_ControlAlignment.h" />
+    <ClInclude Include="src\lua\lua_ControlAutoSize.h" />
+    <ClInclude Include="src\lua\lua_ControlListener.h" />
+    <ClInclude Include="src\lua\lua_ControlListenerEventType.h" />
+    <ClInclude Include="src\lua\lua_ControlState.h" />
+    <ClInclude Include="src\lua\lua_Curve.h" />
+    <ClInclude Include="src\lua\lua_CurveInterpolationType.h" />
+    <ClInclude Include="src\lua\lua_DepthStencilTarget.h" />
+    <ClInclude Include="src\lua\lua_DepthStencilTargetFormat.h" />
+    <ClInclude Include="src\lua\lua_Effect.h" />
+    <ClInclude Include="src\lua\lua_FileSystem.h" />
+    <ClInclude Include="src\lua\lua_FlowLayout.h" />
+    <ClInclude Include="src\lua\lua_Font.h" />
+    <ClInclude Include="src\lua\lua_FontFormat.h" />
+    <ClInclude Include="src\lua\lua_FontJustify.h" />
+    <ClInclude Include="src\lua\lua_FontStyle.h" />
+    <ClInclude Include="src\lua\lua_FontText.h" />
+    <ClInclude Include="src\lua\lua_Form.h" />
+    <ClInclude Include="src\lua\lua_FrameBuffer.h" />
+    <ClInclude Include="src\lua\lua_Frustum.h" />
+    <ClInclude Include="src\lua\lua_Game.h" />
+    <ClInclude Include="src\lua\lua_GameClearFlags.h" />
+    <ClInclude Include="src\lua\lua_Gamepad.h" />
+    <ClInclude Include="src\lua\lua_GamepadButtonMapping.h" />
+    <ClInclude Include="src\lua\lua_GamepadGamepadEvent.h" />
+    <ClInclude Include="src\lua\lua_GameState.h" />
+    <ClInclude Include="src\lua\lua_Gesture.h" />
+    <ClInclude Include="src\lua\lua_GestureGestureEvent.h" />
+    <ClInclude Include="src\lua\lua_Global.h" />
+    <ClInclude Include="src\lua\lua_HeightField.h" />
+    <ClInclude Include="src\lua\lua_Image.h" />
+    <ClInclude Include="src\lua\lua_ImageControl.h" />
+    <ClInclude Include="src\lua\lua_ImageFormat.h" />
+    <ClInclude Include="src\lua\lua_Joint.h" />
+    <ClInclude Include="src\lua\lua_Joystick.h" />
+    <ClInclude Include="src\lua\lua_Keyboard.h" />
+    <ClInclude Include="src\lua\lua_KeyboardKey.h" />
+    <ClInclude Include="src\lua\lua_KeyboardKeyEvent.h" />
+    <ClInclude Include="src\lua\lua_Label.h" />
+    <ClInclude Include="src\lua\lua_Layout.h" />
+    <ClInclude Include="src\lua\lua_LayoutType.h" />
+    <ClInclude Include="src\lua\lua_Light.h" />
+    <ClInclude Include="src\lua\lua_LightType.h" />
+    <ClInclude Include="src\lua\lua_Logger.h" />
+    <ClInclude Include="src\lua\lua_LoggerLevel.h" />
+    <ClInclude Include="src\lua\lua_Material.h" />
+    <ClInclude Include="src\lua\lua_MaterialParameter.h" />
+    <ClInclude Include="src\lua\lua_MathUtil.h" />
+    <ClInclude Include="src\lua\lua_Matrix.h" />
+    <ClInclude Include="src\lua\lua_Mesh.h" />
+    <ClInclude Include="src\lua\lua_MeshBatch.h" />
+    <ClInclude Include="src\lua\lua_MeshIndexFormat.h" />
+    <ClInclude Include="src\lua\lua_MeshPart.h" />
+    <ClInclude Include="src\lua\lua_MeshPrimitiveType.h" />
+    <ClInclude Include="src\lua\lua_MeshSkin.h" />
+    <ClInclude Include="src\lua\lua_Model.h" />
+    <ClInclude Include="src\lua\lua_Mouse.h" />
+    <ClInclude Include="src\lua\lua_MouseMouseEvent.h" />
+    <ClInclude Include="src\lua\lua_Node.h" />
+    <ClInclude Include="src\lua\lua_NodeCloneContext.h" />
+    <ClInclude Include="src\lua\lua_NodeType.h" />
+    <ClInclude Include="src\lua\lua_ParticleEmitter.h" />
+    <ClInclude Include="src\lua\lua_ParticleEmitterTextureBlending.h" />
+    <ClInclude Include="src\lua\lua_Pass.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCharacter.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObject.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectType.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionShape.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeDefinition.h" />
+    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeType.h" />
+    <ClInclude Include="src\lua\lua_PhysicsConstraint.h" />
+    <ClInclude Include="src\lua\lua_PhysicsController.h" />
+    <ClInclude Include="src\lua\lua_PhysicsControllerHitFilter.h" />
+    <ClInclude Include="src\lua\lua_PhysicsControllerHitResult.h" />
+    <ClInclude Include="src\lua\lua_PhysicsControllerListener.h" />
+    <ClInclude Include="src\lua\lua_PhysicsControllerListenerEventType.h" />
+    <ClInclude Include="src\lua\lua_PhysicsFixedConstraint.h" />
+    <ClInclude Include="src\lua\lua_PhysicsGenericConstraint.h" />
+    <ClInclude Include="src\lua\lua_PhysicsGhostObject.h" />
+    <ClInclude Include="src\lua\lua_PhysicsHingeConstraint.h" />
+    <ClInclude Include="src\lua\lua_PhysicsRigidBody.h" />
+    <ClInclude Include="src\lua\lua_PhysicsRigidBodyParameters.h" />
+    <ClInclude Include="src\lua\lua_PhysicsSocketConstraint.h" />
+    <ClInclude Include="src\lua\lua_PhysicsSpringConstraint.h" />
+    <ClInclude Include="src\lua\lua_PhysicsVehicle.h" />
+    <ClInclude Include="src\lua\lua_PhysicsVehicleWheel.h" />
+    <ClInclude Include="src\lua\lua_Plane.h" />
+    <ClInclude Include="src\lua\lua_Platform.h" />
+    <ClInclude Include="src\lua\lua_Properties.h" />
+    <ClInclude Include="src\lua\lua_PropertiesType.h" />
+    <ClInclude Include="src\lua\lua_Quaternion.h" />
+    <ClInclude Include="src\lua\lua_RadioButton.h" />
+    <ClInclude Include="src\lua\lua_Ray.h" />
+    <ClInclude Include="src\lua\lua_Rectangle.h" />
+    <ClInclude Include="src\lua\lua_Ref.h" />
+    <ClInclude Include="src\lua\lua_RenderState.h" />
+    <ClInclude Include="src\lua\lua_RenderStateAutoBinding.h" />
+    <ClInclude Include="src\lua\lua_RenderStateBlend.h" />
+    <ClInclude Include="src\lua\lua_RenderStateCullFaceSide.h" />
+    <ClInclude Include="src\lua\lua_RenderStateDepthFunction.h" />
+    <ClInclude Include="src\lua\lua_RenderStateFrontFace.h" />
+    <ClInclude Include="src\lua\lua_RenderStateStateBlock.h" />
+    <ClInclude Include="src\lua\lua_RenderStateStencilFunction.h" />
+    <ClInclude Include="src\lua\lua_RenderStateStencilOperation.h" />
+    <ClInclude Include="src\lua\lua_RenderTarget.h" />
+    <ClInclude Include="src\lua\lua_Scene.h" />
+    <ClInclude Include="src\lua\lua_ScreenDisplayer.h" />
+    <ClInclude Include="src\lua\lua_ScriptController.h" />
+    <ClInclude Include="src\lua\lua_ScriptTarget.h" />
+    <ClInclude Include="src\lua\lua_Slider.h" />
+    <ClInclude Include="src\lua\lua_SpriteBatch.h" />
+    <ClInclude Include="src\lua\lua_Technique.h" />
+    <ClInclude Include="src\lua\lua_Terrain.h" />
+    <ClInclude Include="src\lua\lua_TerrainFlags.h" />
+    <ClInclude Include="src\lua\lua_TerrainPatch.h" />
+    <ClInclude Include="src\lua\lua_TextBox.h" />
+    <ClInclude Include="src\lua\lua_TextBoxInputMode.h" />
+    <ClInclude Include="src\lua\lua_Texture.h" />
+    <ClInclude Include="src\lua\lua_TextureFilter.h" />
+    <ClInclude Include="src\lua\lua_TextureFormat.h" />
+    <ClInclude Include="src\lua\lua_TextureSampler.h" />
+    <ClInclude Include="src\lua\lua_TextureWrap.h" />
+    <ClInclude Include="src\lua\lua_Theme.h" />
+    <ClInclude Include="src\lua\lua_ThemeSideRegions.h" />
+    <ClInclude Include="src\lua\lua_ThemeStyle.h" />
+    <ClInclude Include="src\lua\lua_ThemeThemeImage.h" />
+    <ClInclude Include="src\lua\lua_ThemeUVs.h" />
+    <ClInclude Include="src\lua\lua_Touch.h" />
+    <ClInclude Include="src\lua\lua_TouchTouchEvent.h" />
+    <ClInclude Include="src\lua\lua_Transform.h" />
+    <ClInclude Include="src\lua\lua_TransformListener.h" />
+    <ClInclude Include="src\lua\lua_Uniform.h" />
+    <ClInclude Include="src\lua\lua_Vector2.h" />
+    <ClInclude Include="src\lua\lua_Vector3.h" />
+    <ClInclude Include="src\lua\lua_Vector4.h" />
+    <ClInclude Include="src\lua\lua_VertexAttributeBinding.h" />
+    <ClInclude Include="src\lua\lua_VertexFormat.h" />
+    <ClInclude Include="src\lua\lua_VertexFormatElement.h" />
+    <ClInclude Include="src\lua\lua_VertexFormatUsage.h" />
+    <ClInclude Include="src\lua\lua_VerticalLayout.h" />
+    <ClInclude Include="src\Material.h" />
+    <ClInclude Include="src\MathUtil.h" />
+    <ClInclude Include="src\MeshBatch.h" />
+    <ClInclude Include="src\Mouse.h" />
+    <ClInclude Include="src\Pass.h" />
+    <ClInclude Include="src\MaterialParameter.h" />
+    <ClInclude Include="src\Matrix.h" />
+    <ClInclude Include="src\Mesh.h" />
+    <ClInclude Include="src\MeshPart.h" />
+    <ClInclude Include="src\MeshSkin.h" />
+    <ClInclude Include="src\Model.h" />
+    <ClInclude Include="src\Node.h" />
+    <ClInclude Include="src\Bundle.h" />
+    <ClInclude Include="src\ParticleEmitter.h" />
+    <ClInclude Include="src\PhysicsCharacter.h" />
+    <ClInclude Include="src\PhysicsCollisionObject.h" />
+    <ClInclude Include="src\PhysicsCollisionShape.h" />
+    <ClInclude Include="src\PhysicsConstraint.h" />
+    <ClInclude Include="src\PhysicsController.h" />
+    <ClInclude Include="src\PhysicsFixedConstraint.h" />
+    <ClInclude Include="src\PhysicsGenericConstraint.h" />
+    <ClInclude Include="src\PhysicsGhostObject.h" />
+    <ClInclude Include="src\PhysicsHingeConstraint.h" />
+    <ClInclude Include="src\PhysicsRigidBody.h" />
+    <ClInclude Include="src\PhysicsSocketConstraint.h" />
+    <ClInclude Include="src\PhysicsSpringConstraint.h" />
+    <ClInclude Include="src\PhysicsVehicle.h" />
+    <ClInclude Include="src\PhysicsVehicleWheel.h" />
+    <ClInclude Include="src\Plane.h" />
+    <ClInclude Include="src\Platform.h" />
+    <ClInclude Include="src\Properties.h" />
+    <ClInclude Include="src\Quaternion.h" />
+    <ClInclude Include="src\RadioButton.h" />
+    <ClInclude Include="src\Ray.h" />
+    <ClInclude Include="src\Rectangle.h" />
+    <ClInclude Include="src\Ref.h" />
+    <ClInclude Include="src\RenderState.h" />
+    <ClInclude Include="src\RenderTarget.h" />
+    <ClInclude Include="src\Scene.h" />
+    <ClInclude Include="src\SceneLoader.h" />
+    <ClInclude Include="src\ScreenDisplayer.h" />
+    <ClInclude Include="src\ScriptController.h" />
+    <ClInclude Include="src\ScriptTarget.h" />
+    <ClInclude Include="src\Slider.h" />
+    <ClInclude Include="src\SpriteBatch.h" />
+    <ClInclude Include="src\Stream.h" />
+    <ClInclude Include="src\Technique.h" />
+    <ClInclude Include="src\Terrain.h" />
+    <ClInclude Include="src\TerrainPatch.h" />
+    <ClInclude Include="src\TextBox.h" />
+    <ClInclude Include="src\Texture.h" />
+    <ClInclude Include="src\Theme.h" />
+    <ClInclude Include="src\ThemeStyle.h" />
+    <ClInclude Include="src\TimeListener.h" />
+    <ClInclude Include="src\Touch.h" />
+    <ClInclude Include="src\Transform.h" />
+    <ClInclude Include="src\Vector2.h" />
+    <ClInclude Include="src\Vector3.h" />
+    <ClInclude Include="src\Vector4.h" />
+    <ClInclude Include="src\VertexAttributeBinding.h" />
+    <ClInclude Include="src\VertexFormat.h" />
+    <ClInclude Include="src\VerticalLayout.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\shaders\colored.frag" />
+    <None Include="res\shaders\colored.vert" />
+    <None Include="res\shaders\font.frag" />
+    <None Include="res\shaders\font.vert" />
+    <None Include="res\shaders\form.frag" />
+    <None Include="res\shaders\form.vert" />
+    <None Include="res\shaders\lighting.frag" />
+    <None Include="res\shaders\lighting.vert" />
+    <None Include="res\shaders\skinning-none.vert" />
+    <None Include="res\shaders\skinning.vert" />
+    <None Include="res\shaders\sprite.frag" />
+    <None Include="res\shaders\sprite.vert" />
+    <None Include="res\shaders\terrain.frag" />
+    <None Include="res\shaders\terrain.vert" />
+    <None Include="res\shaders\textured.frag" />
+    <None Include="res\shaders\textured.vert" />
+    <None Include="src\BoundingBox.inl" />
+    <None Include="src\BoundingSphere.inl" />
+    <None Include="src\Game.inl" />
+    <None Include="src\Image.inl" />
+    <None Include="src\MathUtil.inl" />
+    <None Include="src\MathUtilNeon.inl" />
+    <None Include="src\Joystick.inl" />
+    <None Include="src\Matrix.inl" />
+    <None Include="src\MeshBatch.inl" />
+    <None Include="src\Plane.inl" />
+    <None Include="src\Quaternion.inl" />
+    <None Include="src\Ray.inl" />
+    <None Include="src\ScriptController.inl" />
+    <None Include="src\Vector2.inl" />
+    <None Include="src\Vector3.inl" />
+    <None Include="src\Vector4.inl" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="src\PhysicsConstraint.inl" />
+    <None Include="src\PhysicsFixedConstraint.inl" />
+    <None Include="src\PhysicsGenericConstraint.inl" />
+    <None Include="src\PhysicsRigidBody.inl" />
+    <None Include="src\PhysicsSpringConstraint.inl" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{1032BA4B-57EB-4348-9E03-29DD63E80E4A}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>gameplay</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </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|x64'" 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|x64'" 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|x64'" 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>windows\x86\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <OutDir>windows\x64\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <OutDir>windows\x86\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'">
+    <OutDir>windows\x64\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <IntDir>windows\x86\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <IntDir>windows\x64\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <IntDir>windows\x86\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'">
+    <IntDir>windows\x64\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>windows\x86\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <OutDir>windows\x64\$(Configuration)\</OutDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <IntDir>windows\x86\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <IntDir>windows\x64\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>
+      </RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <DisableSpecificWarnings>
+      </DisableSpecificWarnings>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>
+      </RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <TargetMachine>MachineX64</TargetMachine>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;GP_USE_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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>true</RuntimeTypeInfo>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <DisableSpecificWarnings>
+      </DisableSpecificWarnings>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+    <Lib>
+      <Verbose>
+      </Verbose>
+      <AdditionalDependencies>
+      </AdditionalDependencies>
+      <AdditionalLibraryDirectories>
+      </AdditionalLibraryDirectories>
+    </Lib>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMem|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=0;WIN32;_DEBUG;_LIB;GP_USE_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\png\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>
+      <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DebugInformationFormat>
+      </DebugInformationFormat>
+      <DisableSpecificWarnings>
+      </DisableSpecificWarnings>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <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\png\include;..\external-deps\zlib\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <DebugInformationFormat>
+      </DebugInformationFormat>
+    </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>
 </Project>

+ 1851 - 1962
gameplay/gameplay.vcxproj.filters

@@ -1,1963 +1,1852 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Filter Include="src">
-      <UniqueIdentifier>{c4d4da1c-81e2-4944-901c-200e1c4d80e5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="res">
-      <UniqueIdentifier>{4a30ac71-e135-47d3-9f56-baac7cffe64c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="res\shaders">
-      <UniqueIdentifier>{be0b36f1-49ed-4a06-9f1f-57c654a554fe}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\lua">
-      <UniqueIdentifier>{21cf31c6-9c10-44cb-a864-d46a0e7bfe5e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\social">
-      <UniqueIdentifier>{7bd5ee6c-c0cc-4ae3-b7a9-443fb391b944}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-  <ItemGroup>
-    <ClCompile Include="src\Plane.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PlatformBlackBerry.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PlatformWindows.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Quaternion.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Ray.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Rectangle.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Ref.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Scene.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SpriteBatch.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Texture.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Transform.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector2.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector3.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Vector4.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\VertexAttributeBinding.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\VertexFormat.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Properties.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Technique.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Pass.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\RenderState.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsRigidBody.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsHingeConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsFixedConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsGenericConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsSocketConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsSpringConstraint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SceneLoader.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\RenderTarget.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PlatformAndroid.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AbsoluteLayout.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\RadioButton.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Slider.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\VerticalLayout.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Theme.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\TextBox.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsCharacter.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsCollisionObject.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsGhostObject.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsCollisionShape.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ThemeStyle.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ScriptController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ScreenDisplayer.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AIAgent.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AIController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AIMessage.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ScriptTarget.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PlatformLinux.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsVehicle.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\PhysicsVehicleWheel.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Terrain.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\TerrainPatch.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Platform.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SocialController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\social\ScoreloopSocialSession.cpp">
-      <Filter>src\social</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SocialAchievement.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SocialPlayer.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SocialScore.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SocialChallenge.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SocialSessionListener.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SceneRenderer.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\SceneRendererForward.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\VisibleSetDefault.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\social\GooglePlaySocialSession.cpp">
-      <Filter>src\social</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AIState.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AIStateMachine.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Animation.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationClip.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationTarget.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AnimationValue.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioBuffer.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioController.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioListener.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\AudioSource.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\BoundingBox.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\BoundingSphere.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Bundle.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Button.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Camera.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\CheckBox.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Container.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Control.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Curve.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\DebugNew.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\DepthStencilTarget.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Effect.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\FileSystem.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\FlowLayout.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Font.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Form.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\FrameBuffer.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Frustum.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Game.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Gamepad.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\gameplay-main-android.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\gameplay-main-blackberry.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\gameplay-main-linux.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\gameplay-main-windows.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\HeightField.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Image.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ImageControl.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Joint.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Joystick.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Label.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Layout.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Light.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Logger.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Material.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MaterialParameter.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MathUtil.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Matrix.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Mesh.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MeshBatch.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MeshPart.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\MeshSkin.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Model.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\Node.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ParticleEmitter.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\ControlFactory.cpp">
-      <Filter>src</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AbsoluteLayout.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIAgent.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIAgentListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIController.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIMessage.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIMessageParameterType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIState.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIStateListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AIStateMachine.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_all_bindings.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Animation.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AnimationClip.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AnimationClipListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AnimationClipListenerEventType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AnimationController.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AnimationTarget.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AnimationValue.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AudioBuffer.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AudioController.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AudioListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AudioSource.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_AudioSourceState.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_BoundingBox.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_BoundingSphere.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Bundle.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Button.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Camera.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_CameraType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_CheckBox.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Container.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ContainerScroll.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Control.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ControlAlignment.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ControlAutoSize.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ControlListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ControlListenerEventType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ControlState.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Curve.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_CurveInterpolationType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_DepthStencilTarget.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_DepthStencilTargetFormat.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Effect.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FileSystem.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FlowLayout.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Font.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FontFormat.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FontJustify.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FontStyle.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FontText.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Form.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_FrameBuffer.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Frustum.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Game.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_GameClearFlags.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Gamepad.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_GamepadButtonMapping.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_GamepadGamepadEvent.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_GameState.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Gesture.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_GestureGestureEvent.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Global.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_HeightField.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Image.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ImageControl.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ImageFormat.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Joint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Joystick.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Keyboard.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_KeyboardKey.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_KeyboardKeyEvent.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Label.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Layout.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_LayoutType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Light.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_LightType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Logger.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_LoggerLevel.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Material.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MaterialParameter.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MathUtil.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Matrix.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Mesh.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MeshBatch.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MeshIndexFormat.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MeshPart.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MeshPrimitiveType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MeshSkin.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Model.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Mouse.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_MouseMouseEvent.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Node.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_NodeCloneContext.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_NodeType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ParticleEmitter.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ParticleEmitterTextureBlending.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Pass.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCharacter.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObject.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionShape.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeDefinition.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsConstraint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsController.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsControllerHitFilter.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsControllerHitResult.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsControllerListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsControllerListenerEventType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsFixedConstraint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsGenericConstraint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsGhostObject.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsHingeConstraint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsRigidBody.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsRigidBodyParameters.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsSocketConstraint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsSpringConstraint.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsVehicle.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PhysicsVehicleWheel.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Plane.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Platform.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Properties.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_PropertiesType.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Quaternion.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RadioButton.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Ray.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Rectangle.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Ref.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderState.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateAutoBinding.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateBlend.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateCullFaceSide.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateDepthFunction.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateFrontFace.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateStateBlock.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateStencilFunction.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderStateStencilOperation.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_RenderTarget.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Scene.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_SceneDebugFlags.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_SceneRenderer.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_SceneRendererForward.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ScreenDisplayer.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ScriptController.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ScriptTarget.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Slider.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_SpriteBatch.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Technique.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Terrain.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TerrainFlags.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TerrainListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TextBox.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TextBoxInputMode.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Texture.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TextureFilter.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TextureFormat.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TextureSampler.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TextureWrap.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Theme.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ThemeSideRegions.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ThemeStyle.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ThemeThemeImage.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_ThemeUVs.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Touch.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TouchTouchEvent.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Transform.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_TransformListener.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Uniform.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Vector2.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Vector3.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_Vector4.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VertexAttributeBinding.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VertexFormat.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VertexFormatElement.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VertexFormatUsage.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VerticalLayout.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VisibleSet.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-    <ClCompile Include="src\lua\lua_VisibleSetDefault.cpp">
-      <Filter>src\lua</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="src\Plane.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Platform.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Quaternion.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Ray.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Rectangle.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Ref.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Scene.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SpriteBatch.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Texture.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Transform.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Vector2.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Vector3.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Vector4.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VertexAttributeBinding.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VertexFormat.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ParticleEmitter.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Properties.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Technique.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Pass.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\RenderState.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsRigidBody.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsSpringConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsFixedConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsGenericConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsHingeConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsSocketConstraint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SceneLoader.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\RenderTarget.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Touch.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AbsoluteLayout.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\RadioButton.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Slider.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VerticalLayout.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Theme.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\TextBox.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsCharacter.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsCollisionObject.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\TimeListener.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsGhostObject.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsCollisionShape.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ScreenDisplayer.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ThemeStyle.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ScriptController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AIAgent.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AIController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ScriptTarget.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsVehicleWheel.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\PhysicsVehicle.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Stream.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Terrain.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\TerrainPatch.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialSession.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialAchievement.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialPlayer.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialSessionListener.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialScore.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\social\ScoreloopSocialSession.h">
-      <Filter>src\social</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SocialChallenge.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SceneRenderer.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\SceneRendererForward.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VisibleSet.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\VisibleSetDefault.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\social\GooglePlaySocialSession.h">
-      <Filter>src\social</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AIMessage.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AIState.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AIStateMachine.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Animation.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationClip.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationTarget.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AnimationValue.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioBuffer.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioController.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioListener.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\AudioSource.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Base.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\BoundingBox.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\BoundingSphere.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Bundle.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Button.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Camera.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\CheckBox.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Container.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Control.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Curve.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\DebugNew.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\DepthStencilTarget.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Effect.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\FileSystem.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\FlowLayout.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Font.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Form.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\FrameBuffer.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Frustum.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Game.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Gamepad.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\gameplay.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Gesture.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\HeightField.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Image.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ImageControl.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Joint.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Joystick.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Keyboard.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Label.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Layout.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Light.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Logger.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Material.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MaterialParameter.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MathUtil.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Matrix.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Mesh.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MeshBatch.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MeshPart.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\MeshSkin.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Model.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Mouse.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\Node.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\ControlFactory.h">
-      <Filter>src</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AbsoluteLayout.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIAgent.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIAgentListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIController.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIMessage.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIMessageParameterType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIState.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIStateListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AIStateMachine.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_all_bindings.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Animation.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AnimationClip.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AnimationClipListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AnimationClipListenerEventType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AnimationController.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AnimationTarget.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AnimationValue.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AudioBuffer.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AudioController.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AudioListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AudioSource.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_AudioSourceState.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_BoundingBox.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_BoundingSphere.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Bundle.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Button.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Camera.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_CameraType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_CheckBox.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Container.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ContainerScroll.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Control.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ControlAlignment.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ControlAutoSize.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ControlListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ControlListenerEventType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ControlState.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Curve.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_CurveInterpolationType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_DepthStencilTarget.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_DepthStencilTargetFormat.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Effect.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FileSystem.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FlowLayout.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Font.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FontFormat.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FontJustify.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FontStyle.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FontText.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Form.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_FrameBuffer.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Frustum.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Game.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_GameClearFlags.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Gamepad.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_GamepadButtonMapping.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_GamepadGamepadEvent.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_GameState.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Gesture.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_GestureGestureEvent.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Global.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_HeightField.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Image.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ImageControl.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ImageFormat.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Joint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Joystick.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Keyboard.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_KeyboardKey.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_KeyboardKeyEvent.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Label.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Layout.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_LayoutType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Light.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_LightType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Logger.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_LoggerLevel.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Material.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MaterialParameter.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MathUtil.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Matrix.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Mesh.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MeshBatch.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MeshIndexFormat.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MeshPart.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MeshPrimitiveType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MeshSkin.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Model.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Mouse.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_MouseMouseEvent.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Node.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_NodeCloneContext.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_NodeType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ParticleEmitter.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ParticleEmitterTextureBlending.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Pass.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCharacter.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObject.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionShape.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeDefinition.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsConstraint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsController.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsControllerHitFilter.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsControllerHitResult.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsControllerListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsControllerListenerEventType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsFixedConstraint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsGenericConstraint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsGhostObject.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsHingeConstraint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsRigidBody.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsRigidBodyParameters.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsSocketConstraint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsSpringConstraint.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsVehicle.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PhysicsVehicleWheel.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Plane.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Platform.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Properties.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_PropertiesType.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Quaternion.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RadioButton.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Ray.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Rectangle.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Ref.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderState.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateAutoBinding.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateBlend.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateCullFaceSide.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateDepthFunction.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateFrontFace.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateStateBlock.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateStencilFunction.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderStateStencilOperation.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_RenderTarget.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Scene.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_SceneDebugFlags.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_SceneRenderer.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_SceneRendererForward.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ScreenDisplayer.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ScriptController.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ScriptTarget.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Slider.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_SpriteBatch.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Technique.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Terrain.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TerrainFlags.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TerrainListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TextBox.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TextBoxInputMode.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Texture.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TextureFilter.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TextureFormat.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TextureSampler.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TextureWrap.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Theme.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ThemeSideRegions.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ThemeStyle.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ThemeThemeImage.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_ThemeUVs.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Touch.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TouchTouchEvent.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Transform.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_TransformListener.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Uniform.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Vector2.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Vector3.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_Vector4.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VertexAttributeBinding.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VertexFormat.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VertexFormatElement.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VertexFormatUsage.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VerticalLayout.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VisibleSet.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-    <ClInclude Include="src\lua\lua_VisibleSetDefault.h">
-      <Filter>src\lua</Filter>
-    </ClInclude>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="res\logo_black.png">
-      <Filter>res</Filter>
-    </None>
-    <None Include="res\logo_powered_black.png">
-      <Filter>res</Filter>
-    </None>
-    <None Include="res\logo_powered_white.png">
-      <Filter>res</Filter>
-    </None>
-    <None Include="res\logo_white.png">
-      <Filter>res</Filter>
-    </None>
-    <None Include="src\ScriptController.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\BoundingBox.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\BoundingSphere.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Game.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Image.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Joystick.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\MathUtil.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\MathUtilNeon.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Matrix.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\MeshBatch.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="res\shaders\colored.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\colored.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\font.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\font.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\form.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\form.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\lighting.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\lighting.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\sprite.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\sprite.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\terrain.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\terrain.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\textured.frag">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\textured.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\skinning.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-    <None Include="res\shaders\skinning-none.vert">
-      <Filter>res\shaders</Filter>
-    </None>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="src\PhysicsFixedConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsGenericConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsSpringConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsRigidBody.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Plane.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Quaternion.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Ray.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Vector2.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Vector3.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\Vector4.inl">
-      <Filter>src</Filter>
-    </None>
-    <None Include="src\PhysicsConstraint.inl">
-      <Filter>src</Filter>
-    </None>
-  </ItemGroup>
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{c4d4da1c-81e2-4944-901c-200e1c4d80e5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="res">
+      <UniqueIdentifier>{4a30ac71-e135-47d3-9f56-baac7cffe64c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="res\shaders">
+      <UniqueIdentifier>{be0b36f1-49ed-4a06-9f1f-57c654a554fe}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\lua">
+      <UniqueIdentifier>{21cf31c6-9c10-44cb-a864-d46a0e7bfe5e}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="src\Plane.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PlatformBlackBerry.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PlatformWindows.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Quaternion.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Ray.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Rectangle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Ref.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Scene.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\SpriteBatch.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Texture.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Transform.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Vector2.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Vector3.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Vector4.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\VertexAttributeBinding.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\VertexFormat.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Properties.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Technique.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Pass.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\RenderState.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsController.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsRigidBody.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsConstraint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsHingeConstraint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsFixedConstraint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsGenericConstraint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsSocketConstraint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsSpringConstraint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\SceneLoader.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\RenderTarget.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PlatformAndroid.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AbsoluteLayout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\RadioButton.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Slider.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\VerticalLayout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Theme.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\TextBox.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsCharacter.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsCollisionObject.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsGhostObject.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsCollisionShape.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ThemeStyle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ScriptController.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ScreenDisplayer.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIAgent.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIController.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIMessage.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ScriptTarget.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PlatformLinux.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsVehicle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\PhysicsVehicleWheel.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Terrain.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\TerrainPatch.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Platform.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIState.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AIStateMachine.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Animation.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AnimationClip.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AnimationController.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AnimationTarget.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AnimationValue.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AudioBuffer.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AudioController.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AudioListener.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\AudioSource.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\BoundingBox.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\BoundingSphere.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Bundle.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Button.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Camera.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\CheckBox.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Container.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Control.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Curve.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DebugNew.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\DepthStencilTarget.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Effect.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FileSystem.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FlowLayout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Font.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Form.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\FrameBuffer.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Frustum.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Game.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Gamepad.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\gameplay-main-android.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\gameplay-main-blackberry.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\gameplay-main-linux.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\gameplay-main-windows.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\HeightField.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Image.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ImageControl.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Joint.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Joystick.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Label.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Layout.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Light.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Logger.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Material.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\MaterialParameter.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\MathUtil.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Matrix.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Mesh.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\MeshBatch.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\MeshPart.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\MeshSkin.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Model.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Node.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ParticleEmitter.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\ControlFactory.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AbsoluteLayout.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIAgent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIAgentListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIController.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIMessage.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIMessageParameterType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIState.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIStateListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AIStateMachine.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_all_bindings.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Animation.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AnimationClip.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AnimationClipListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AnimationClipListenerEventType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AnimationController.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AnimationTarget.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AnimationValue.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AudioBuffer.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AudioController.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AudioListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AudioSource.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_AudioSourceState.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_BoundingBox.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_BoundingSphere.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Bundle.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Button.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Camera.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_CameraType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_CheckBox.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Container.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ContainerScroll.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Control.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ControlAlignment.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ControlAutoSize.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ControlListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ControlListenerEventType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ControlState.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Curve.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_CurveInterpolationType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_DepthStencilTarget.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_DepthStencilTargetFormat.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Effect.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FileSystem.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FlowLayout.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Font.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FontFormat.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FontJustify.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FontStyle.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FontText.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Form.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_FrameBuffer.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Frustum.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Game.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_GameClearFlags.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Gamepad.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_GamepadButtonMapping.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_GamepadGamepadEvent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_GameState.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Gesture.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_GestureGestureEvent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Global.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_HeightField.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Image.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ImageControl.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ImageFormat.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Joint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Joystick.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Keyboard.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_KeyboardKey.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_KeyboardKeyEvent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Label.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Layout.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_LayoutType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Light.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_LightType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Logger.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_LoggerLevel.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Material.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MaterialParameter.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MathUtil.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Matrix.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Mesh.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MeshBatch.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MeshIndexFormat.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MeshPart.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MeshPrimitiveType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MeshSkin.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Model.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Mouse.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_MouseMouseEvent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Node.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_NodeCloneContext.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_NodeType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ParticleEmitter.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ParticleEmitterTextureBlending.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Pass.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCharacter.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObject.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionObjectType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionShape.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeDefinition.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsCollisionShapeType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsConstraint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsController.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsControllerHitFilter.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsControllerHitResult.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsControllerListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsControllerListenerEventType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsFixedConstraint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsGenericConstraint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsGhostObject.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsHingeConstraint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsRigidBody.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsRigidBodyParameters.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsSocketConstraint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsSpringConstraint.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsVehicle.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PhysicsVehicleWheel.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Plane.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Platform.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Properties.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_PropertiesType.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Quaternion.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RadioButton.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Ray.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Rectangle.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Ref.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderState.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateAutoBinding.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateBlend.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateCullFaceSide.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateDepthFunction.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateFrontFace.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateStateBlock.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateStencilFunction.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderStateStencilOperation.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_RenderTarget.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Scene.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ScreenDisplayer.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ScriptController.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ScriptTarget.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Slider.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_SpriteBatch.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Technique.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Terrain.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TerrainFlags.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TextBox.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TextBoxInputMode.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Texture.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TextureFilter.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TextureFormat.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TextureSampler.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TextureWrap.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Theme.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ThemeSideRegions.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ThemeStyle.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ThemeThemeImage.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_ThemeUVs.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Touch.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TouchTouchEvent.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Transform.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TransformListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Uniform.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Vector2.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Vector3.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_Vector4.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_VertexAttributeBinding.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_VertexFormat.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_VertexFormatElement.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_VertexFormatUsage.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_VerticalLayout.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_TerrainPatch.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+    <ClCompile Include="src\lua\lua_CameraListener.cpp">
+      <Filter>src\lua</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="src\Plane.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Platform.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Quaternion.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Ray.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Rectangle.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Ref.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Scene.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\SpriteBatch.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Texture.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Transform.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Vector2.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Vector3.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Vector4.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\VertexAttributeBinding.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\VertexFormat.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ParticleEmitter.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Properties.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Technique.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Pass.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\RenderState.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsController.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsRigidBody.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsConstraint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsSpringConstraint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsFixedConstraint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsGenericConstraint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsHingeConstraint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsSocketConstraint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\SceneLoader.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\RenderTarget.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Touch.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AbsoluteLayout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\RadioButton.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Slider.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\VerticalLayout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Theme.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\TextBox.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsCharacter.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsCollisionObject.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\TimeListener.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsGhostObject.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsCollisionShape.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ScreenDisplayer.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ThemeStyle.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ScriptController.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIAgent.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIController.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ScriptTarget.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsVehicleWheel.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\PhysicsVehicle.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Stream.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Terrain.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\TerrainPatch.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIMessage.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIState.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AIStateMachine.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Animation.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AnimationClip.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AnimationController.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AnimationTarget.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AnimationValue.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AudioBuffer.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AudioController.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AudioListener.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\AudioSource.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Base.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\BoundingBox.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\BoundingSphere.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Bundle.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Button.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Camera.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\CheckBox.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Container.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Control.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Curve.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DebugNew.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\DepthStencilTarget.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Effect.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FileSystem.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FlowLayout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Font.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Form.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\FrameBuffer.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Frustum.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Game.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Gamepad.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\gameplay.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Gesture.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\HeightField.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Image.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ImageControl.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Joint.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Joystick.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Keyboard.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Label.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Layout.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Light.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Logger.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Material.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\MaterialParameter.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\MathUtil.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Matrix.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Mesh.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\MeshBatch.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\MeshPart.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\MeshSkin.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Model.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Mouse.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Node.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\ControlFactory.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AbsoluteLayout.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIAgent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIAgentListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIController.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIMessage.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIMessageParameterType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIState.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIStateListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AIStateMachine.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_all_bindings.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Animation.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AnimationClip.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AnimationClipListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AnimationClipListenerEventType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AnimationController.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AnimationTarget.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AnimationValue.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AudioBuffer.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AudioController.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AudioListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AudioSource.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_AudioSourceState.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_BoundingBox.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_BoundingSphere.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Bundle.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Button.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Camera.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_CameraType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_CheckBox.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Container.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ContainerScroll.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Control.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ControlAlignment.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ControlAutoSize.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ControlListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ControlListenerEventType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ControlState.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Curve.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_CurveInterpolationType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_DepthStencilTarget.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_DepthStencilTargetFormat.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Effect.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FileSystem.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FlowLayout.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Font.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FontFormat.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FontJustify.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FontStyle.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FontText.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Form.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_FrameBuffer.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Frustum.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Game.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_GameClearFlags.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Gamepad.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_GamepadButtonMapping.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_GamepadGamepadEvent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_GameState.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Gesture.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_GestureGestureEvent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Global.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_HeightField.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Image.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ImageControl.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ImageFormat.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Joint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Joystick.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Keyboard.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_KeyboardKey.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_KeyboardKeyEvent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Label.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Layout.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_LayoutType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Light.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_LightType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Logger.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_LoggerLevel.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Material.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MaterialParameter.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MathUtil.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Matrix.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Mesh.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MeshBatch.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MeshIndexFormat.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MeshPart.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MeshPrimitiveType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MeshSkin.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Model.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Mouse.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_MouseMouseEvent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Node.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_NodeCloneContext.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_NodeType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ParticleEmitter.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ParticleEmitterTextureBlending.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Pass.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCharacter.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObject.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionListenerEventType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectCollisionPair.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionObjectType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionShape.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeDefinition.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsCollisionShapeType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsConstraint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsController.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsControllerHitFilter.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsControllerHitResult.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsControllerListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsControllerListenerEventType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsFixedConstraint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsGenericConstraint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsGhostObject.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsHingeConstraint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsRigidBody.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsRigidBodyParameters.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsSocketConstraint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsSpringConstraint.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsVehicle.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PhysicsVehicleWheel.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Plane.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Platform.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Properties.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_PropertiesType.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Quaternion.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RadioButton.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Ray.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Rectangle.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Ref.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderState.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateAutoBinding.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateBlend.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateCullFaceSide.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateDepthFunction.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateFrontFace.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateStateBlock.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateStencilFunction.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderStateStencilOperation.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_RenderTarget.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Scene.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ScreenDisplayer.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ScriptController.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ScriptTarget.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Slider.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_SpriteBatch.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Technique.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Terrain.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TerrainFlags.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TextBox.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TextBoxInputMode.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Texture.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TextureFilter.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TextureFormat.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TextureSampler.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TextureWrap.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Theme.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ThemeSideRegions.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ThemeStyle.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ThemeThemeImage.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_ThemeUVs.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Touch.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TouchTouchEvent.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Transform.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TransformListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Uniform.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Vector2.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Vector3.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_Vector4.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_VertexAttributeBinding.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_VertexFormat.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_VertexFormatElement.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_VertexFormatUsage.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_VerticalLayout.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_TerrainPatch.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+    <ClInclude Include="src\lua\lua_CameraListener.h">
+      <Filter>src\lua</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="src\ScriptController.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\BoundingBox.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\BoundingSphere.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Game.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Image.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Joystick.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\MathUtil.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\MathUtilNeon.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Matrix.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\MeshBatch.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="res\shaders\colored.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\colored.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\font.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\font.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\form.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\form.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\lighting.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\lighting.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\sprite.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\sprite.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\terrain.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\terrain.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\textured.frag">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\textured.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\skinning.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+    <None Include="res\shaders\skinning-none.vert">
+      <Filter>res\shaders</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="src\PhysicsFixedConstraint.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\PhysicsGenericConstraint.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\PhysicsSpringConstraint.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\PhysicsRigidBody.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Plane.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Quaternion.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Ray.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector2.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector3.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Vector4.inl">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\PhysicsConstraint.inl">
+      <Filter>src</Filter>
+    </None>
+  </ItemGroup>
 </Project>

File diff suppressed because it is too large
+ 4 - 528
gameplay/gameplay.xcodeproj/project.pbxproj


+ 0 - 0
gameplay/res/icon_128.ico → gameplay/res/design/icon_128.ico


+ 0 - 0
gameplay/res/icon_16.ico → gameplay/res/design/icon_16.ico


+ 0 - 0
gameplay/res/icon_32.ico → gameplay/res/design/icon_32.ico


+ 0 - 0
gameplay/res/icon_64.ico → gameplay/res/design/icon_64.ico


+ 0 - 0
gameplay/res/logo.ai → gameplay/res/design/logo.ai


+ 1 - 1
gameplay/res/shaders/font.frag

@@ -1,6 +1,6 @@
 #ifdef OPENGL_ES
-precision highp float;
 #extension GL_OES_standard_derivatives : enable
+precision highp float;
 #endif
 
 ///////////////////////////////////////////////////////////

+ 17 - 12
gameplay/res/shaders/lighting.frag

@@ -1,22 +1,27 @@
 
 vec3 computeLighting(vec3 normalVector, vec3 lightDirection, vec3 lightColor, float attenuation)
 {
-    float diffuse = clamp(dot(normalVector, lightDirection), 0.0, 1.0);
-    vec3 diffuseColor = lightColor * _baseColor.rgb * diffuse;
+    float diffuse = max(dot(normalVector, lightDirection), 0.0);
+     vec3 diffuseColor = lightColor * _baseColor.rgb * diffuse * attenuation;
 
     #if defined(SPECULAR)
 
-	// Blinn-Phong shading
-    vec3 vertexToEye = normalize(v_cameraDirection); 
-    vec3 halfDirection = normalize(lightDirection + v_cameraDirection);
-    float specularAngle = max(dot(halfDirection, normalVector), 0.0);
-    vec3 specularColor = vec3(pow(specularAngle, u_specularExponent));
+	// Phong shading
+    //vec3 vertexToEye = normalize(v_cameraDirection);
+    //vec3 specularAngle = normalize(normalVector * diffuse * 2.0 - lightDirection);  
+    //vec3 specularColor = vec3(pow(clamp(dot(specularAngle, vertexToEye), 0.0, 1.0), u_specularExponent)); 
 
-    return (diffuseColor + specularColor) * attenuation;
+    // Blinn-Phong shading
+    vec3 vertexToEye = normalize(v_cameraDirection);
+    vec3 halfVector = normalize(lightDirection + vertexToEye);
+    float specularAngle = clamp(dot(normalVector, halfVector), 0.0, 1.0);
+    vec3 specularColor = vec3(pow(specularAngle, u_specularExponent)) * attenuation;
+
+    return diffuseColor + specularColor;
 
     #else
     
-        return diffuseColor * attenuation;
+    return diffuseColor;
     
     #endif
 }
@@ -65,7 +70,7 @@ vec3 getLitPixel()
     {
         // Compute range attenuation
         vec3 ldir = v_vertexToSpotLightDirection[i] * u_spotLightRangeInverse[i];
-        float att = clamp(1.0 - dot(ldir, ldir), 0.0, 1.0);
+        float attenuation = clamp(1.0 - dot(ldir, ldir), 0.0, 1.0);
         vec3 vertexToSpotLightDirection = normalize(v_vertexToSpotLightDirection[i]);
 
         // TODO: 
@@ -78,8 +83,8 @@ vec3 getLitPixel()
         float spotCurrentAngleCos = dot(spotLightDirection, -vertexToSpotLightDirection);
 
 		// Apply spot attenuation
-        att *= smoothstep(u_spotLightOuterAngleCos[i], u_spotLightInnerAngleCos[i], spotCurrentAngleCos);
-        combinedColor += computeLighting(normalVector, vertexToSpotLightDirection, u_spotLightColor[i], att);
+        attenuation *= smoothstep(u_spotLightOuterAngleCos[i], u_spotLightInnerAngleCos[i], spotCurrentAngleCos);
+        combinedColor += computeLighting(normalVector, vertexToSpotLightDirection, u_spotLightColor[i], attenuation);
     }
     #endif
     

+ 129 - 82
gameplay/res/shaders/terrain.frag

@@ -1,82 +1,129 @@
-#ifdef OPENGL_ES
-precision highp float;
-#endif
-
-// Uniforms
-uniform vec3 u_ambientColor;                    // Ambient color
-uniform vec3 u_lightColor;                      // Light color
-uniform vec3 u_lightDirection;					// Light direction
-#if defined(DEBUG_PATCHES)
-uniform float u_row;                            // Patch row
-uniform float u_column;                         // Patch column
-#endif
-#if (LAYER_COUNT > 0)
-uniform sampler2D u_samplers[SAMPLER_COUNT];    // Surface layer samplers
-#endif
-#if defined (NORMAL_MAP)
-uniform sampler2D u_normalMap;                  // Normal map
-#endif
-
-// Varyings
-#if defined(NORMAL_MAP)
-vec3 v_normalVector;                            // Normal vector variable (from normal map)
-#else
-varying vec3 v_normalVector;					// Normal vector from vertex shader
-#endif
-varying vec2 v_texCoord0;
-#if (LAYER_COUNT > 0)
-varying vec2 v_texCoordLayer0;
-#endif
-#if (LAYER_COUNT > 1)
-varying vec2 v_texCoordLayer1;
-#endif
-#if (LAYER_COUNT > 2)
-varying vec2 v_texCoordLayer2;
-#endif
-
-// Lighting
-#include "lighting.frag"
-#include "lighting-directional.frag"
-
-#if (LAYER_COUNT > 1)
-void blendLayer(sampler2D textureMap, vec2 texCoord, float alphaBlend)
-{
-    // Sample full intensity diffuse color
-    vec3 diffuse = texture2D(textureMap,  mod(texCoord, vec2(1,1))).rgb;
-
-    _baseColor.rgb = _baseColor.rgb * (1.0 - alphaBlend) + diffuse * alphaBlend;
-}
-#endif
-
-void main()
-{
-#if (LAYER_COUNT > 0)
-    // Sample base texture
-	_baseColor.rgb = texture2D(u_samplers[TEXTURE_INDEX_0], mod(v_texCoordLayer0, vec2(1,1))).rgb;
-    _baseColor.a = 1.0;
-#else
-    // If no layers are defined, simply use a white color
-    _baseColor = vec4(1,1,1,1);
-#endif
-
-#if (LAYER_COUNT > 1)
-    blendLayer(u_samplers[TEXTURE_INDEX_1], v_texCoordLayer1, texture2D(u_samplers[BLEND_INDEX_1], v_texCoord0)[BLEND_CHANNEL_1]);
-#endif
-#if (LAYER_COUNT > 2)
-    blendLayer(u_samplers[TEXTURE_INDEX_2], v_texCoordLayer2, texture2D(u_samplers[BLEND_INDEX_2], v_texCoord0)[BLEND_CHANNEL_2]);
-#endif
-
-#if defined(DEBUG_PATCHES)
-    // If patch debug drawing is enabled, tint patches alternate colors
-    float tint = mod(u_row + mod(u_column, 2.0), 2.0);
-    _baseColor.rgb = _baseColor.rgb * 0.75 + vec3(1.0-tint, tint, 0) * 0.25;
-#endif
-
-    // Light the pixel
-#if defined(NORMAL_MAP)
-    v_normalVector = normalize(texture2D(u_normalMap, v_texCoord0).xyz * 2.0 - 1.0);
-#endif
-
-    gl_FragColor.a = _baseColor.a;
-    gl_FragColor.rgb = getLitPixel();
-}
+#ifdef OPENGL_ES
+precision highp float;
+#endif
+
+#ifndef DIRECTIONAL_LIGHT_COUNT
+#define DIRECTIONAL_LIGHT_COUNT 0
+#endif
+#ifndef SPOT_LIGHT_COUNT
+#define SPOT_LIGHT_COUNT 0
+#endif
+#ifndef POINT_LIGHT_COUNT
+#define POINT_LIGHT_COUNT 0
+#endif
+#if (DIRECTIONAL_LIGHT_COUNT > 0) || (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)
+#define LIGHTING
+#endif
+
+///////////////////////////////////////////////////////////
+// Uniforms
+uniform vec3 u_ambientColor; 
+
+#if defined(LIGHTING)
+
+#if (DIRECTIONAL_LIGHT_COUNT > 0)
+uniform vec3 u_directionalLightColor[DIRECTIONAL_LIGHT_COUNT];
+uniform vec3 u_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];
+#endif
+
+#if (POINT_LIGHT_COUNT > 0)
+uniform vec3 u_pointLightColor[POINT_LIGHT_COUNT];
+uniform vec3 u_pointLightPosition[POINT_LIGHT_COUNT];
+uniform float u_pointLightRangeInverse[POINT_LIGHT_COUNT];
+#endif
+
+#if (SPOT_LIGHT_COUNT > 0)
+uniform vec3 u_spotLightColor[SPOT_LIGHT_COUNT];
+uniform vec3 u_spotLightDirection[SPOT_LIGHT_COUNT];
+uniform float u_spotLightRangeInverse[SPOT_LIGHT_COUNT];
+uniform float u_spotLightInnerAngleCos[SPOT_LIGHT_COUNT];
+uniform float u_spotLightOuterAngleCos[SPOT_LIGHT_COUNT];
+#endif
+
+#if defined (NORMAL_MAP)
+uniform sampler2D u_normalMap; 
+#endif
+
+#endif
+
+#if defined(DEBUG_PATCHES)
+uniform float u_row;
+uniform float u_column;
+#endif
+
+#if (LAYER_COUNT > 0)
+uniform sampler2D u_surfaceLayerMaps[SAMPLER_COUNT];
+#endif
+
+///////////////////////////////////////////////////////////
+// Variables
+vec4 _baseColor;
+
+///////////////////////////////////////////////////////////
+// Varyings
+#if defined(LIGHTING)
+vec3 v_normalVector;
+#endif
+
+varying vec2 v_texCoord0;
+
+#if (LAYER_COUNT > 0)
+varying vec2 v_texCoordLayer0;
+#endif
+#if (LAYER_COUNT > 1)
+varying vec2 v_texCoordLayer1;
+#endif
+#if (LAYER_COUNT > 2)
+varying vec2 v_texCoordLayer2;
+#endif
+#if (LAYER_COUNT > 1)
+void blendLayer(sampler2D textureMap, vec2 texCoord, float alphaBlend)
+{
+    vec3 diffuse = texture2D(textureMap,  mod(texCoord, vec2(1,1))).rgb;
+    _baseColor.rgb = _baseColor.rgb * (1.0 - alphaBlend) + diffuse * alphaBlend;
+}
+#endif
+
+#if defined(LIGHTING)
+#include "lighting.frag"
+#endif
+
+
+void main()
+{
+    #if (LAYER_COUNT > 0)
+    // Sample base texture
+	_baseColor.rgb = texture2D(u_surfaceLayerMaps[TEXTURE_INDEX_0], mod(v_texCoordLayer0, vec2(1,1))).rgb;
+    _baseColor.a = 1.0;
+    #else
+    // If no layers are defined, simply use a white color
+    _baseColor = vec4(1, 1, 1, 1);
+    #endif
+
+    #if (LAYER_COUNT > 1)
+    blendLayer(u_surfaceLayerMaps[TEXTURE_INDEX_1], v_texCoordLayer1, texture2D(u_surfaceLayerMaps[BLEND_INDEX_1], v_texCoord0)[BLEND_CHANNEL_1]);
+    #endif
+    #if (LAYER_COUNT > 2)
+    blendLayer(u_surfaceLayerMaps[TEXTURE_INDEX_2], v_texCoordLayer2, texture2D(u_surfaceLayerMaps[BLEND_INDEX_2], v_texCoord0)[BLEND_CHANNEL_2]);
+    #endif
+
+    #if defined(DEBUG_PATCHES)
+    float tint = mod(u_row + mod(u_column, 2.0), 2.0);
+    _baseColor.rgb = _baseColor.rgb * 0.75 + vec3(1.0-tint, tint, 0) * 0.25;
+    #endif
+
+    #if defined(LIGHTING)
+
+    #if defined(NORMAL_MAP)
+    v_normalVector = normalize(texture2D(u_normalMap, v_texCoord0).xyz * 2.0 - 1.0);
+    #endif
+
+    gl_FragColor.a = _baseColor.a;
+    gl_FragColor.rgb = getLitPixel();
+
+    #else
+
+    gl_FragColor.rgb = _baseColor;
+
+    #endif
+}

+ 114 - 54
gameplay/res/shaders/terrain.vert

@@ -1,54 +1,114 @@
-///////////////////////////////////////////////////////////
-// Attributes
-attribute vec4 a_position;
-#ifndef NORMAL_MAP
-attribute vec3 a_normal;
-#endif
-attribute vec2 a_texCoord0;
-
-// Uniforms
-uniform mat4 u_worldViewProjectionMatrix;
-#ifndef NORMAL_MAP
-uniform mat4 u_normalMatrix;
-#endif
-uniform vec3 u_lightDirection;
-
-// Varyings
-#ifndef NORMAL_MAP
-varying vec3 v_normalVector;
-#endif
-varying vec2 v_texCoord0;
-#if LAYER_COUNT > 0
-varying vec2 v_texCoordLayer0;
-#endif
-#if LAYER_COUNT > 1
-varying vec2 v_texCoordLayer1;
-#endif
-#if LAYER_COUNT > 2
-varying vec2 v_texCoordLayer2;
-#endif
-
-void main()
-{
-    // Transform position to clip space.
-    gl_Position = u_worldViewProjectionMatrix * a_position;
-
-#ifndef NORMAL_MAP
-    // Pass normal to fragment shader
-    v_normalVector = (u_normalMatrix * vec4(a_normal.x, a_normal.y, a_normal.z, 0)).xyz;
-#endif
-
-    // Pass base texture coord
-    v_texCoord0 = a_texCoord0;
-
-    // Pass repeated texture coordinates for each layer
-#if LAYER_COUNT > 0
-    v_texCoordLayer0 = a_texCoord0 * TEXTURE_REPEAT_0;
-#endif
-#if LAYER_COUNT > 1
-    v_texCoordLayer1 = a_texCoord0 * TEXTURE_REPEAT_1;
-#endif
-#if LAYER_COUNT > 2
-    v_texCoordLayer2 = a_texCoord0 * TEXTURE_REPEAT_2;
-#endif
-}
+#ifndef DIRECTIONAL_LIGHT_COUNT
+#define DIRECTIONAL_LIGHT_COUNT 0
+#endif
+#ifndef SPOT_LIGHT_COUNT
+#define SPOT_LIGHT_COUNT 0
+#endif
+#ifndef POINT_LIGHT_COUNT
+#define POINT_LIGHT_COUNT 0
+#endif
+#if (DIRECTIONAL_LIGHT_COUNT > 0) || (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)
+#define LIGHTING
+#endif
+
+///////////////////////////////////////////////////////////
+// Attributes
+attribute vec4 a_position;
+#if !defined(NORMAL_MAP) && defined(LIGHTING)
+attribute vec3 a_normal;
+#endif
+attribute vec2 a_texCoord0;
+
+///////////////////////////////////////////////////////////
+// Uniforms
+uniform mat4 u_worldViewProjectionMatrix;
+#if !defined(NORMAL_MAP) && defined(LIGHTING)
+uniform mat4 u_normalMatrix;
+#endif
+
+#if defined(LIGHTING)
+
+uniform mat4 u_inverseTransposeWorldViewMatrix;
+
+#if (POINT_LIGHT_COUNT > 0) || (SPOT_LIGHT_COUNT > 0)
+uniform mat4 u_worldViewMatrix;
+#endif
+
+#if (DIRECTIONAL_LIGHT_COUNT > 0)
+uniform vec3 u_directionalLightDirection[DIRECTIONAL_LIGHT_COUNT];
+#endif
+
+#if (POINT_LIGHT_COUNT > 0) 
+uniform vec3 u_pointLightPosition[POINT_LIGHT_COUNT];
+#endif
+
+#if (SPOT_LIGHT_COUNT > 0)
+uniform vec3 u_spotLightPosition[SPOT_LIGHT_COUNT];
+uniform vec3 u_spotLightDirection[SPOT_LIGHT_COUNT];
+#endif
+
+#endif
+
+///////////////////////////////////////////////////////////
+// Varyings
+
+#if defined(LIGHTING)
+varying vec3 v_normalVector;
+
+#if (DIRECTIONAL_LIGHT_COUNT > 0) 
+varying vec3 v_lightDirection[DIRECTIONAL_LIGHT_COUNT];
+#endif
+
+#if (POINT_LIGHT_COUNT > 0)
+varying vec3 v_vertexToPointLightDirection[POINT_LIGHT_COUNT];
+#endif
+
+#if (SPOT_LIGHT_COUNT > 0)
+varying vec3 v_vertexToSpotLightDirection[SPOT_LIGHT_COUNT];
+#endif
+
+#include "lighting.vert"
+
+#endif
+
+varying vec2 v_texCoord0;
+#if LAYER_COUNT > 0
+varying vec2 v_texCoordLayer0;
+#endif
+#if LAYER_COUNT > 1
+varying vec2 v_texCoordLayer1;
+#endif
+#if LAYER_COUNT > 2
+varying vec2 v_texCoordLayer2;
+#endif
+
+
+void main()
+{
+    // Transform position to clip space.
+    gl_Position = u_worldViewProjectionMatrix * a_position;
+
+    #if defined(LIGHTING)
+    
+    #if !defined(NORMAL_MAP) 
+    v_normalVector = (u_normalMatrix * vec4(a_normal.x, a_normal.y, a_normal.z, 0)).xyz;
+    #endif
+
+    applyLight(a_position);
+
+    #endif
+
+    // Pass base texture coord
+    v_texCoord0 = a_texCoord0;
+
+    // Pass repeated texture coordinates for each layer
+    #if LAYER_COUNT > 0
+    v_texCoordLayer0 = a_texCoord0 * TEXTURE_REPEAT_0;
+    #endif
+    #if LAYER_COUNT > 1
+    v_texCoordLayer1 = a_texCoord0 * TEXTURE_REPEAT_1;
+    #endif
+    #if LAYER_COUNT > 2
+    v_texCoordLayer2 = a_texCoord0 * TEXTURE_REPEAT_2;
+    #endif
+}

+ 2 - 2
gameplay/src/AnimationClip.cpp

@@ -12,7 +12,7 @@ namespace gameplay
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
     : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), 
       _stateBits(0x00), _repeatCount(1.0f), _loopBlendTime(0), _activeDuration(_duration * _repeatCount), _speed(1.0f), _timeStarted(0), 
-      _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f),
       _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL), _scriptListeners(NULL)
 {
     GP_ASSERT(_animation);
@@ -124,7 +124,7 @@ float AnimationClip::getRepeatCount() const
 
 void AnimationClip::setActiveDuration(unsigned long duration)
 {
-    GP_ASSERT(duration > 0.0f);
+    GP_ASSERT(duration >= 0);
 
     if (duration == REPEAT_INDEFINITE)
     {

+ 12 - 0
gameplay/src/Base.h

@@ -75,6 +75,12 @@ extern void print(const char* format, ...);
 #define GP_ASSERT(expression)
 #endif
 
+#if defined(WIN32) && defined(_MSC_VER)
+#define DEBUG_BREAK() __debugbreak()
+#else
+#define DEBUG_BREAK()
+#endif
+
 // Error macro.
 #ifdef GP_ERRORS_AS_WARNINGS
 #define GP_ERROR GP_WARN
@@ -84,6 +90,7 @@ extern void print(const char* format, ...);
         gameplay::Logger::log(gameplay::Logger::LEVEL_ERROR, "%s -- ", __current__func__); \
         gameplay::Logger::log(gameplay::Logger::LEVEL_ERROR, __VA_ARGS__); \
         gameplay::Logger::log(gameplay::Logger::LEVEL_ERROR, "\n"); \
+        DEBUG_BREAK(); \
         assert(0); \
         std::exit(-1); \
     } while (0)
@@ -304,6 +311,11 @@ typedef GLuint RenderBufferHandle;
     typedef unsigned long SocialAchievementHandle;
     typedef unsigned long SocialScoreHandle;
     typedef unsigned long SocialChallengeHandle;
+#elif defined(__APPLE__)
+    typedef void* SocialPlayerHandle;
+    typedef void* SocialAchievementHandle;
+    typedef void* SocialScoreHandle;
+    typedef void* SocialChallengeHandle;
 #else
     typedef unsigned int SocialPlayerHandle;
     typedef unsigned int SocialAchievementHandle;

+ 6 - 6
gameplay/src/Bundle.cpp

@@ -189,7 +189,7 @@ Bundle* Bundle::create(const char* path)
     Stream* stream = FileSystem::open(path);
     if (!stream)
     {
-        GP_ERROR("Failed to open file '%s'.", path);
+        GP_WARN("Failed to open file '%s'.", path);
         return NULL;
     }
 
@@ -198,7 +198,7 @@ Bundle* Bundle::create(const char* path)
     if (stream->read(sig, 1, 9) != 9 || memcmp(sig, "\xABGPB\xBB\r\n\x1A\n", 9) != 0)
     {
         SAFE_DELETE(stream);
-        GP_ERROR("Invalid GPB header for bundle '%s'.", path);
+        GP_WARN("Invalid GPB header for bundle '%s'.", path);
         return NULL;
     }
 
@@ -207,14 +207,14 @@ Bundle* Bundle::create(const char* path)
     if (stream->read(version, 1, 2) != 2)
     {
         SAFE_DELETE(stream);
-        GP_ERROR("Failed to read GPB version for bundle '%s'.", path);
+        GP_WARN("Failed to read GPB version for bundle '%s'.", path);
         return NULL;
     }
     // Check for the minimal 
     if (version[0] != BUNDLE_VERSION_MAJOR_REQUIRED || version[1] < BUNDLE_VERSION_MINOR_REQUIRED)
     {
         SAFE_DELETE(stream);
-        GP_ERROR("Unsupported version (%d.%d) for bundle '%s' (expected %d.%d).", (int)version[0], (int)version[1], path, BUNDLE_VERSION_MAJOR_REQUIRED, BUNDLE_VERSION_MINOR_REQUIRED);
+        GP_WARN("Unsupported version (%d.%d) for bundle '%s' (expected %d.%d).", (int)version[0], (int)version[1], path, BUNDLE_VERSION_MAJOR_REQUIRED, BUNDLE_VERSION_MINOR_REQUIRED);
         return NULL;
     }
 
@@ -223,7 +223,7 @@ Bundle* Bundle::create(const char* path)
     if (stream->read(&refCount, 4, 1) != 1)
     {
         SAFE_DELETE(stream);
-        GP_ERROR("Failed to read ref table for bundle '%s'.", path);
+        GP_WARN("Failed to read ref table for bundle '%s'.", path);
         return NULL;
     }
 
@@ -236,7 +236,7 @@ Bundle* Bundle::create(const char* path)
             stream->read(&refs[i].offset, 4, 1) != 1)
         {
             SAFE_DELETE(stream);
-            GP_ERROR("Failed to read ref number %d for bundle '%s'.", i, path);
+            GP_WARN("Failed to read ref number %d for bundle '%s'.", i, path);
             SAFE_DELETE_ARRAY(refs);
             return NULL;
         }

+ 2 - 0
gameplay/src/Bundle.h

@@ -29,6 +29,8 @@ public:
      * release() method must be called. Note that calling release() does
      * NOT free any actual game objects created/returned from the Bundle
      * instance and those objects must be released separately.
+     * 
+     * @return The new Bundle or NULL if there was an error.
      * @script{create}
      */
     static Bundle* create(const char* path);

+ 58 - 158
gameplay/src/Button.cpp

@@ -1,158 +1,58 @@
-#include "Base.h"
-#include "Button.h"
-#include "Gamepad.h"
-
-namespace gameplay
-{
-
-Button::Button() : _dataBinding(0)
-{
-}
-
-Button::~Button()
-{
-}
-
-Button* Button::create(const char* id, Theme::Style* style)
-{
-    Button* button = new Button();
-
-    button->_id = id;
-    button->_style = style;
-
-    return button;
-}
-
-Control* Button::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    Button* button = new Button();
-    button->initialize(style, properties);
-
-    // Different types of data bindings can be named differently in a button namespace.
-    // Gamepad button mappings have the name "mapping" and correspond to Gamepad::ButtonMapping enums.
-    const char* mapping = properties->getString("mapping");
-    if (mapping)
-    {
-        button->_dataBinding = Gamepad::getButtonMappingFromString(mapping);
-    }
-
-    return button;
-}
-
-bool Button::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    switch (evt)
-    {
-    case Touch::TOUCH_PRESS:
-        if (_contactIndex == INVALID_CONTACT_INDEX)
-        {
-            if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-            {
-                _contactIndex = (int) contactIndex;
-                setState(Control::ACTIVE);
-                notifyListeners(Control::Listener::PRESS);
-                return _consumeInputEvents;
-            }
-            else
-            {
-                setState(Control::NORMAL);
-            }
-        }
-        break;
-
-    case Touch::TOUCH_RELEASE:
-        if (_contactIndex == (int) contactIndex)
-        {
-            _contactIndex = INVALID_CONTACT_INDEX;
-            notifyListeners(Control::Listener::RELEASE);
-            if (!_parent->isScrolling() &&
-                x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-            {
-                setState(Control::FOCUS);
-                notifyListeners(Control::Listener::CLICK);
-            }
-            else
-            {
-                setState(Control::NORMAL);
-            }
-            return _consumeInputEvents;
-        }
-        break;
-    case Touch::TOUCH_MOVE:
-        return Control::touchEvent(evt, x, y, contactIndex);
-    }
-
-    return false;
-}
-
-bool Button::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
-{
-    switch (evt)
-    {
-    case Gamepad::BUTTON_EVENT:
-        if (_state == Control::FOCUS)
-        {
-            if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
-                gamepad->isButtonDown(Gamepad::BUTTON_X))
-            {
-                notifyListeners(Control::Listener::PRESS);
-                setState(Control::ACTIVE);
-                return _consumeInputEvents;
-            }
-        }
-        else if (_state == Control::ACTIVE)
-        {
-            if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
-                !gamepad->isButtonDown(Gamepad::BUTTON_X))
-            {
-                notifyListeners(Control::Listener::RELEASE);
-                notifyListeners(Control::Listener::CLICK);
-                setState(Control::FOCUS);
-                return _consumeInputEvents;
-            }
-        }
-        break;
-    default:
-        break;
-    }
-
-    return false;
-}
-
-bool Button::keyEvent(Keyboard::KeyEvent evt, int key)
-{
-    if (evt == Keyboard::KEY_PRESS && key == Keyboard::KEY_RETURN)
-    {
-        notifyListeners(Control::Listener::PRESS);
-        setState(Control::ACTIVE);
-        return _consumeInputEvents;
-    }
-    else if (_state == ACTIVE && evt == Keyboard::KEY_RELEASE && key == Keyboard::KEY_RETURN)
-    {
-        notifyListeners(Control::Listener::RELEASE);
-        notifyListeners(Control::Listener::CLICK);
-        setState(Control::FOCUS);
-        return _consumeInputEvents;
-    }
-
-    return false;
-}
-
-const char* Button::getType() const
-{
-    return "button";
-}
-
-const unsigned int Button::getDataBinding() const
-{
-    return _dataBinding;
-}
-
-void Button::setDataBinding(unsigned int dataBinding)
-{
-    _dataBinding = dataBinding;
-}
-
-}
+#include "Base.h"
+#include "Button.h"
+#include "Gamepad.h"
+
+namespace gameplay
+{
+
+Button::Button() : _dataBinding(0)
+{
+    _canFocus = true;
+}
+
+Button::~Button()
+{
+}
+
+Button* Button::create(const char* id, Theme::Style* style)
+{
+    Button* button = new Button();
+
+    button->_id = id;
+    button->_style = style;
+
+    return button;
+}
+
+Control* Button::create(Theme::Style* style, Properties* properties)
+{
+    Button* button = new Button();
+    button->initialize(style, properties);
+
+    // Different types of data bindings can be named differently in a button namespace.
+    // Gamepad button mappings have the name "mapping" and correspond to Gamepad::ButtonMapping enums.
+    const char* mapping = properties->getString("mapping");
+    if (mapping)
+    {
+        button->_dataBinding = Gamepad::getButtonMappingFromString(mapping);
+    }
+
+    return button;
+}
+
+const char* Button::getType() const
+{
+    return "button";
+}
+
+const unsigned int Button::getDataBinding() const
+{
+    return _dataBinding;
+}
+
+void Button::setDataBinding(unsigned int dataBinding)
+{
+    _dataBinding = dataBinding;
+}
+
+}

+ 107 - 137
gameplay/src/Button.h

@@ -1,137 +1,107 @@
-#ifndef BUTTON_H_
-#define BUTTON_H_
-
-#include "Container.h"
-#include "Label.h"
-#include "Touch.h"
-#include "Theme.h"
-#include "Properties.h"
-
-namespace gameplay
-{
-
-/**
- * Defines a button UI control. This is essentially a label that can have a callback method set on it.
- *
- * The following properties are available for buttons:
-
- @verbatim
-    button <buttonID>
-    {
-         style       = <styleID>
-         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
-         position    = <x, y>
-         autoWidth   = <bool>
-         autoHeight  = <bool>
-         size        = <width, height>
-         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
-         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
-         text        = <string>
-         consumeEvents = <bool>  // Whether the button propagates input events to the Game's input event handler. Default is true.
-    }
- @endverbatim
- */
-class Button : public Label
-{
-    friend class Container;
-    friend class Gamepad;
-	friend class ControlFactory;
-
-public:
-
-    /**
-     * Create a new button control.
-     *
-     * @param id The control's ID.
-     * @param style The control's style.
-     *
-     * @return The new button.
-     * @script{create}
-     */
-    static Button* create(const char* id, Theme::Style* style);
-
-protected:
-
-    /**
-     * Constructor.
-     */
-    Button();
-
-    /**
-     * Destructor.
-     */
-    virtual ~Button();
-
-    /**
-     * Create a button with a given style and properties.
-     *
-     * @param style The style to apply to this button.
-     * @param properties The properties to set on this button.
-     * @param theme The theme to set on this control if needed.
-	 *
-     * @return The new button.
-     */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
-
-    /**
-     * Touch callback on touch events.  Controls return true if they consume the touch event.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by the control.
-     *
-     * @see Touch::TouchEvent
-     */
-    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-
-    /**
-     * Gamepad callback on gamepad events.
-     *
-     * @see Control::gamepadEvent
-     */
-    virtual bool gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
-
-    /**
-     * Keyboard callback on key events.
-     *
-     * @see Keyboard::KeyEvent
-     * @see Keyboard::Key
-     */
-    virtual bool keyEvent(Keyboard::KeyEvent evt, int key);
-
-    /**
-     * @see Control::getType
-     */
-    const char* getType() const;
-
-    /**
-     * Gets the data binding index for this control.
-     *
-     * @return The data binding index for control. 
-     */
-    const unsigned int getDataBinding() const;
-
-    /**
-     * Sets the data binding provider for this control.
-     *
-     * @param dataBinding The data binding index for control. 
-     */
-    void setDataBinding(unsigned int dataBinding);
-
-private:
-
-    /**
-     * Constructor.
-     */
-    Button(const Button& copy);
-
-    unsigned int _dataBinding;
-
-};
-
-}
-
-#endif
+#ifndef BUTTON_H_
+#define BUTTON_H_
+
+#include "Container.h"
+#include "Label.h"
+#include "Touch.h"
+#include "Theme.h"
+#include "Properties.h"
+
+namespace gameplay
+{
+
+/**
+ * Defines a button UI control. This is essentially a label that can have a callback method set on it.
+ *
+ * The following properties are available for buttons:
+
+ @verbatim
+    button <buttonID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+         consumeEvents = <bool>  // Whether the button propagates input events to the Game's input event handler. Default is true.
+    }
+ @endverbatim
+ */
+class Button : public Label
+{
+    friend class Container;
+    friend class Gamepad;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Create a new button control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new button.
+     * @script{create}
+     */
+    static Button* create(const char* id, Theme::Style* style);
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    Button();
+
+    /**
+     * Destructor.
+     */
+    virtual ~Button();
+
+    /**
+     * Create a button with a given style and properties.
+     *
+     * @param style The style to apply to this button.
+     * @param properties The properties to set on this button.
+     *
+     * @return The new button.
+     */
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
+    /**
+     * Gets the data binding index for this control.
+     *
+     * @return The data binding index for control. 
+     */
+    const unsigned int getDataBinding() const;
+
+    /**
+     * Sets the data binding provider for this control.
+     *
+     * @param dataBinding The data binding index for control. 
+     */
+    void setDataBinding(unsigned int dataBinding);
+
+private:
+
+    /**
+     * Constructor.
+     */
+    Button(const Button& copy);
+
+    unsigned int _dataBinding;
+
+};
+
+}
+
+#endif

+ 498 - 446
gameplay/src/Camera.cpp

@@ -1,446 +1,498 @@
-#include "Base.h"
-#include "Camera.h"
-#include "Game.h"
-#include "Node.h"
-#include "Game.h"
-#include "PhysicsController.h"
-
-// Camera dirty bits
-#define CAMERA_DIRTY_VIEW 1
-#define CAMERA_DIRTY_PROJ 2
-#define CAMERA_DIRTY_VIEW_PROJ 4
-#define CAMERA_DIRTY_INV_VIEW 8
-#define CAMERA_DIRTY_INV_VIEW_PROJ 16
-#define CAMERA_DIRTY_BOUNDS 32
-#define CAMERA_DIRTY_ALL (CAMERA_DIRTY_VIEW | CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS)
-
-// Other misc camera bits
-#define CAMERA_CUSTOM_PROJECTION 64
-
-namespace gameplay
-{
-
-Camera::Camera(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
-    : _type(PERSPECTIVE), _fieldOfView(fieldOfView), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
-      _bits(CAMERA_DIRTY_ALL), _node(NULL)
-{
-}
-
-Camera::Camera(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
-    : _type(ORTHOGRAPHIC), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
-      _bits(CAMERA_DIRTY_ALL), _node(NULL)
-{
-    // Orthographic camera.
-    _zoom[0] = zoomX;
-    _zoom[1] = zoomY;
-}
-
-Camera::~Camera()
-{
-}
-
-Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
-{
-    return new Camera(fieldOfView, aspectRatio, nearPlane, farPlane);
-}
-
-Camera* Camera::createOrthographic(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
-{
-    return new Camera(zoomX, zoomY, aspectRatio, nearPlane, farPlane);
-}
-
-Camera* Camera::create(Properties* properties)
-{
-    GP_ASSERT(properties);
-
-    // Read camera type
-    std::string typeStr;
-    if (properties->exists("type"))
-        typeStr = properties->getString("type");
-    Camera::Type type;
-    if (typeStr == "PERSPECTIVE")
-    {
-        type = Camera::PERSPECTIVE;
-    }
-    else if (typeStr == "ORTHOGRAPHIC")
-    {
-        type = Camera::ORTHOGRAPHIC;
-    }
-    else
-    {
-        GP_ERROR("Invalid 'type' parameter for camera definition.");
-        return NULL;
-    }
-
-    // Read common parameters
-    float aspectRatio, nearPlane, farPlane;
-    if (properties->exists("aspectRatio"))
-    {
-        aspectRatio = properties->getFloat("aspectRatio");
-    }
-    else
-    {
-        // Use default aspect ratio
-        aspectRatio = (float)Game::getInstance()->getWidth() / Game::getInstance()->getHeight();
-    }
-
-    if (properties->exists("nearPlane"))
-        nearPlane = properties->getFloat("nearPlane");
-    else
-        nearPlane = 0.2f; // use some reasonable default value
-
-    if (properties->exists("farPlane"))
-        farPlane = properties->getFloat("farPlane");
-    else
-        farPlane = 100; // use some reasonable default value
-
-    Camera* camera = NULL;
-
-    switch (type)
-    {
-    case Camera::PERSPECTIVE:
-        // If field of view is not specified, use a default of 60 degrees
-        camera = createPerspective(
-            properties->exists("fieldOfView") ? properties->getFloat("fieldOfView") : 60.0f,
-            aspectRatio, nearPlane, farPlane);
-        break;
-
-    case Camera::ORTHOGRAPHIC:
-        // If zoomX and zoomY are not specified, use screen width/height
-        camera = createOrthographic(
-            properties->exists("zoomX") ? properties->getFloat("zoomX") : Game::getInstance()->getWidth(),
-            properties->exists("zoomY") ? properties->getFloat("zoomY") : Game::getInstance()->getHeight(),
-            aspectRatio, nearPlane, farPlane);
-        break;
-    }
-
-    return camera;
-}
-
-Camera::Type Camera::getCameraType() const
-{
-    return _type;
-}
-
-float Camera::getFieldOfView() const
-{
-    GP_ASSERT(_type == Camera::PERSPECTIVE);
-
-    return _fieldOfView;
-}
-
-void Camera::setFieldOfView(float fieldOfView)
-{
-    GP_ASSERT(_type == Camera::PERSPECTIVE);
-
-    _fieldOfView = fieldOfView;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-float Camera::getZoomX() const
-{
-    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
-    return _zoom[0];
-}
-
-void Camera::setZoomX(float zoomX)
-{
-    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
-    _zoom[0] = zoomX;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-float Camera::getZoomY() const
-{
-    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
-    return _zoom[1];
-}
-
-void Camera::setZoomY(float zoomY)
-{
-    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
-    _zoom[1] = zoomY;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-float Camera::getAspectRatio() const
-{
-    return _aspectRatio;
-}
-
-void Camera::setAspectRatio(float aspectRatio)
-{
-    _aspectRatio = aspectRatio;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-float Camera::getNearPlane() const
-{
-    return _nearPlane;
-}
-
-void Camera::setNearPlane(float nearPlane)
-{
-    _nearPlane = nearPlane;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-float Camera::getFarPlane() const
-{
-    return _farPlane;
-}
-
-void Camera::setFarPlane(float farPlane)
-{
-    _farPlane = farPlane;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-Node* Camera::getNode() const
-{
-    return _node;
-}
-
-void Camera::setNode(Node* node)
-{
-    if (_node != node)
-    {
-        if (_node)
-        {
-            _node->removeListener(this);
-        }
-
-        // Connect the new node.
-        _node = node;
-
-        if (_node)
-        {
-            _node->addListener(this);
-        }
-
-        _bits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-    }
-}
-
-const Matrix& Camera::getViewMatrix() const
-{
-    if (_bits & CAMERA_DIRTY_VIEW)
-    {
-        if (_node)
-        {
-            // The view matrix is the inverse of our transform matrix.
-            _node->getWorldMatrix().invert(&_view);
-        }
-        else
-        {
-            _view.setIdentity();
-        }
-
-        _bits &= ~CAMERA_DIRTY_VIEW;
-    }
-
-    return _view;
-}
-
-const Matrix& Camera::getInverseViewMatrix() const
-{
-    if (_bits & CAMERA_DIRTY_INV_VIEW)
-    {
-        getViewMatrix().invert(&_inverseView);
-
-        _bits &= ~CAMERA_DIRTY_INV_VIEW;
-    }
-
-    return _inverseView;
-}
-
-const Matrix& Camera::getProjectionMatrix() const
-{
-    if (!(_bits & CAMERA_CUSTOM_PROJECTION) && (_bits & CAMERA_DIRTY_PROJ))
-    {
-        if (_type == PERSPECTIVE)
-        {
-            Matrix::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
-        }
-        else
-        {
-            // Create an ortho projection with the origin at the bottom left of the viewport, +X to the right and +Y up.
-            Matrix::createOrthographic(_zoom[0], _zoom[1], _nearPlane, _farPlane, &_projection);
-        }
-
-        _bits &= ~CAMERA_DIRTY_PROJ;
-    }
-
-    return _projection;
-}
-
-void Camera::setProjectionMatrix(const Matrix& matrix)
-{
-    _projection = matrix;
-    _bits |= CAMERA_CUSTOM_PROJECTION;
-    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-void Camera::resetProjectionMatrix()
-{
-    if (_bits & CAMERA_CUSTOM_PROJECTION)
-    {
-        _bits &= ~CAMERA_CUSTOM_PROJECTION;
-        _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-    }
-}
-
-const Matrix& Camera::getViewProjectionMatrix() const
-{
-    if (_bits & CAMERA_DIRTY_VIEW_PROJ)
-    {
-        Matrix::multiply(getProjectionMatrix(), getViewMatrix(), &_viewProjection);
-
-        _bits &= ~CAMERA_DIRTY_VIEW_PROJ;
-    }
-
-    return _viewProjection;
-}
-
-const Matrix& Camera::getInverseViewProjectionMatrix() const
-{
-    if (_bits & CAMERA_DIRTY_INV_VIEW_PROJ)
-    {
-        getViewProjectionMatrix().invert(&_inverseViewProjection);
-
-        _bits &= ~CAMERA_DIRTY_INV_VIEW_PROJ;
-    }
-
-    return _inverseViewProjection;
-}
-
-const Frustum& Camera::getFrustum() const
-{
-    if (_bits & CAMERA_DIRTY_BOUNDS)
-    {
-        // Update our bounding frustum from our view projection matrix.
-        _bounds.set(getViewProjectionMatrix());
-
-        _bits &= ~CAMERA_DIRTY_BOUNDS;
-    }
-
-    return _bounds;
-}
-
-void Camera::project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth) const
-{
-    GP_ASSERT(x);
-    GP_ASSERT(y);
-
-    // Transform the point to clip-space.
-    Vector4 clipPos;
-    getViewProjectionMatrix().transformVector(Vector4(position.x, position.y, position.z, 1.0f), &clipPos);
-
-    // Compute normalized device coordinates.
-    GP_ASSERT(clipPos.w != 0.0f);
-    float ndcX = clipPos.x / clipPos.w;
-    float ndcY = clipPos.y / clipPos.w;
-
-    // Compute screen coordinates by applying our viewport transformation.
-    *x = viewport.x + (ndcX + 1.0f) * 0.5f * viewport.width;
-    *y = viewport.y + (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
-    if (depth)
-    {
-        float ndcZ = clipPos.z / clipPos.w;
-        *depth = ndcZ + 1.0f / 2.0f;
-    }
-}
-
-void Camera::project(const Rectangle& viewport, const Vector3& position, Vector2* out) const
-{
-    GP_ASSERT(out);
-    float x, y;
-    project(viewport, position, &x, &y);
-    out->set(x, y);
-}
-
-void Camera::project(const Rectangle& viewport, const Vector3& position, Vector3* out) const
-{
-    GP_ASSERT(out);
-    float x, y, depth;
-    project(viewport, position, &x, &y, &depth);
-    out->set(x, y, depth);
-}
-
-void Camera::unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst) const
-{
-    GP_ASSERT(dst);
-    
-    // Create our screen space position in NDC.
-    GP_ASSERT(viewport.width != 0.0f && viewport.height != 0.0f);
-    Vector4 screen((x - viewport.x) / viewport.width, ((viewport.height - y) - viewport.y) / viewport.height, depth, 1.0f);
-
-    // Map to range -1 to 1.
-    screen.x = screen.x * 2.0f - 1.0f;
-    screen.y = screen.y * 2.0f - 1.0f;
-    screen.z = screen.z * 2.0f - 1.0f;
-
-    // Transform the screen-space NDC by our inverse view projection matrix.
-    getInverseViewProjectionMatrix().transformVector(screen, &screen);
-
-    // Divide by our W coordinate.
-    if (screen.w != 0.0f)
-    {
-        screen.x /= screen.w;
-        screen.y /= screen.w;
-        screen.z /= screen.w;
-    }
-
-    dst->set(screen.x, screen.y, screen.z);
-}
-
-void Camera::pickRay(const Rectangle& viewport, float x, float y, Ray* dst) const
-{
-    GP_ASSERT(dst);
-
-    // Get the world-space position at the near clip plane.
-    Vector3 nearPoint;
-    unproject(viewport, x, y, 0.0f, &nearPoint);
-
-    // Get the world-space position at the far clip plane.
-    Vector3 farPoint;
-    unproject(viewport, x, y, 1.0f, &farPoint);
-
-    // Set the direction of the ray.
-    Vector3 direction;
-    Vector3::subtract(farPoint, nearPoint, &direction);
-    direction.normalize();
-
-    dst->set(nearPoint, direction);
-}
-
-Camera* Camera::clone(NodeCloneContext &context) const
-{
-    Camera* cameraClone = NULL;
-    if (getCameraType() == PERSPECTIVE)
-    {
-        cameraClone = createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane);
-    }
-    else if (getCameraType() == ORTHOGRAPHIC)
-    {
-        cameraClone = createOrthographic(getZoomX(), getZoomY(), getAspectRatio(), _nearPlane, _farPlane);
-    }
-    GP_ASSERT(cameraClone);
-
-    if (Node* node = context.findClonedNode(getNode()))
-    {
-        cameraClone->setNode(node);
-    }
-    return cameraClone;
-}
-
-void Camera::transformChanged(Transform* transform, long cookie)
-{
-    _bits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
-}
-
-}
+#include "Base.h"
+#include "Camera.h"
+#include "Game.h"
+#include "Node.h"
+#include "Game.h"
+#include "PhysicsController.h"
+
+// Camera dirty bits
+#define CAMERA_DIRTY_VIEW 1
+#define CAMERA_DIRTY_PROJ 2
+#define CAMERA_DIRTY_VIEW_PROJ 4
+#define CAMERA_DIRTY_INV_VIEW 8
+#define CAMERA_DIRTY_INV_VIEW_PROJ 16
+#define CAMERA_DIRTY_BOUNDS 32
+#define CAMERA_DIRTY_ALL (CAMERA_DIRTY_VIEW | CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS)
+
+// Other misc camera bits
+#define CAMERA_CUSTOM_PROJECTION 64
+
+namespace gameplay
+{
+
+Camera::Camera(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
+    : _type(PERSPECTIVE), _fieldOfView(fieldOfView), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
+    _bits(CAMERA_DIRTY_ALL), _node(NULL), _listeners(NULL)
+{
+}
+
+Camera::Camera(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
+    : _type(ORTHOGRAPHIC), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
+	_bits(CAMERA_DIRTY_ALL), _node(NULL), _listeners(NULL)
+{
+    // Orthographic camera.
+    _zoom[0] = zoomX;
+    _zoom[1] = zoomY;
+}
+
+Camera::~Camera()
+{
+}
+
+Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
+{
+    return new Camera(fieldOfView, aspectRatio, nearPlane, farPlane);
+}
+
+Camera* Camera::createOrthographic(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
+{
+    return new Camera(zoomX, zoomY, aspectRatio, nearPlane, farPlane);
+}
+
+Camera* Camera::create(Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    // Read camera type
+    std::string typeStr;
+    if (properties->exists("type"))
+        typeStr = properties->getString("type");
+    Camera::Type type;
+    if (typeStr == "PERSPECTIVE")
+    {
+        type = Camera::PERSPECTIVE;
+    }
+    else if (typeStr == "ORTHOGRAPHIC")
+    {
+        type = Camera::ORTHOGRAPHIC;
+    }
+    else
+    {
+        GP_ERROR("Invalid 'type' parameter for camera definition.");
+        return NULL;
+    }
+
+    // Read common parameters
+    float aspectRatio, nearPlane, farPlane;
+    if (properties->exists("aspectRatio"))
+    {
+        aspectRatio = properties->getFloat("aspectRatio");
+    }
+    else
+    {
+        // Use default aspect ratio
+        aspectRatio = (float)Game::getInstance()->getWidth() / Game::getInstance()->getHeight();
+    }
+
+    if (properties->exists("nearPlane"))
+        nearPlane = properties->getFloat("nearPlane");
+    else
+        nearPlane = 0.2f; // use some reasonable default value
+
+    if (properties->exists("farPlane"))
+        farPlane = properties->getFloat("farPlane");
+    else
+        farPlane = 100; // use some reasonable default value
+
+    Camera* camera = NULL;
+
+    switch (type)
+    {
+    case Camera::PERSPECTIVE:
+        // If field of view is not specified, use a default of 60 degrees
+        camera = createPerspective(
+            properties->exists("fieldOfView") ? properties->getFloat("fieldOfView") : 60.0f,
+            aspectRatio, nearPlane, farPlane);
+        break;
+
+    case Camera::ORTHOGRAPHIC:
+        // If zoomX and zoomY are not specified, use screen width/height
+        camera = createOrthographic(
+            properties->exists("zoomX") ? properties->getFloat("zoomX") : Game::getInstance()->getWidth(),
+            properties->exists("zoomY") ? properties->getFloat("zoomY") : Game::getInstance()->getHeight(),
+            aspectRatio, nearPlane, farPlane);
+        break;
+    }
+
+    return camera;
+}
+
+Camera::Type Camera::getCameraType() const
+{
+    return _type;
+}
+
+float Camera::getFieldOfView() const
+{
+    GP_ASSERT(_type == Camera::PERSPECTIVE);
+
+    return _fieldOfView;
+}
+
+void Camera::setFieldOfView(float fieldOfView)
+{
+    GP_ASSERT(_type == Camera::PERSPECTIVE);
+
+    _fieldOfView = fieldOfView;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+    cameraChanged();
+}
+
+float Camera::getZoomX() const
+{
+    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
+
+    return _zoom[0];
+}
+
+void Camera::setZoomX(float zoomX)
+{
+    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
+
+    _zoom[0] = zoomX;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+    cameraChanged();
+}
+
+float Camera::getZoomY() const
+{
+    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
+
+    return _zoom[1];
+}
+
+void Camera::setZoomY(float zoomY)
+{
+    GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
+
+    _zoom[1] = zoomY;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+    cameraChanged();
+}
+
+float Camera::getAspectRatio() const
+{
+    return _aspectRatio;
+}
+
+void Camera::setAspectRatio(float aspectRatio)
+{
+    _aspectRatio = aspectRatio;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+    cameraChanged();
+}
+
+float Camera::getNearPlane() const
+{
+    return _nearPlane;
+}
+
+void Camera::setNearPlane(float nearPlane)
+{
+    _nearPlane = nearPlane;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+    cameraChanged();
+}
+
+float Camera::getFarPlane() const
+{
+    return _farPlane;
+}
+
+void Camera::setFarPlane(float farPlane)
+{
+    _farPlane = farPlane;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+    cameraChanged();
+}
+
+Node* Camera::getNode() const
+{
+    return _node;
+}
+
+void Camera::setNode(Node* node)
+{
+    if (_node != node)
+    {
+        if (_node)
+        {
+            _node->removeListener(this);
+        }
+
+        // Connect the new node.
+        _node = node;
+
+        if (_node)
+        {
+            _node->addListener(this);
+        }
+
+        _bits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+        cameraChanged();
+    }
+}
+
+const Matrix& Camera::getViewMatrix() const
+{
+    if (_bits & CAMERA_DIRTY_VIEW)
+    {
+        if (_node)
+        {
+            // The view matrix is the inverse of our transform matrix.
+            _node->getWorldMatrix().invert(&_view);
+        }
+        else
+        {
+            _view.setIdentity();
+        }
+
+        _bits &= ~CAMERA_DIRTY_VIEW;
+    }
+
+    return _view;
+}
+
+const Matrix& Camera::getInverseViewMatrix() const
+{
+    if (_bits & CAMERA_DIRTY_INV_VIEW)
+    {
+        getViewMatrix().invert(&_inverseView);
+
+        _bits &= ~CAMERA_DIRTY_INV_VIEW;
+    }
+
+    return _inverseView;
+}
+
+const Matrix& Camera::getProjectionMatrix() const
+{
+    if (!(_bits & CAMERA_CUSTOM_PROJECTION) && (_bits & CAMERA_DIRTY_PROJ))
+    {
+        if (_type == PERSPECTIVE)
+        {
+            Matrix::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
+        }
+        else
+        {
+            // Create an ortho projection with the origin at the bottom left of the viewport, +X to the right and +Y up.
+            Matrix::createOrthographic(_zoom[0], _zoom[1], _nearPlane, _farPlane, &_projection);
+        }
+
+        _bits &= ~CAMERA_DIRTY_PROJ;
+    }
+
+    return _projection;
+}
+
+void Camera::setProjectionMatrix(const Matrix& matrix)
+{
+    _projection = matrix;
+    _bits |= CAMERA_CUSTOM_PROJECTION;
+    _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+
+    cameraChanged();
+}
+
+void Camera::resetProjectionMatrix()
+{
+    if (_bits & CAMERA_CUSTOM_PROJECTION)
+    {
+        _bits &= ~CAMERA_CUSTOM_PROJECTION;
+        _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+
+        cameraChanged();
+    }
+}
+
+const Matrix& Camera::getViewProjectionMatrix() const
+{
+    if (_bits & CAMERA_DIRTY_VIEW_PROJ)
+    {
+        Matrix::multiply(getProjectionMatrix(), getViewMatrix(), &_viewProjection);
+
+        _bits &= ~CAMERA_DIRTY_VIEW_PROJ;
+    }
+
+    return _viewProjection;
+}
+
+const Matrix& Camera::getInverseViewProjectionMatrix() const
+{
+    if (_bits & CAMERA_DIRTY_INV_VIEW_PROJ)
+    {
+        getViewProjectionMatrix().invert(&_inverseViewProjection);
+
+        _bits &= ~CAMERA_DIRTY_INV_VIEW_PROJ;
+    }
+
+    return _inverseViewProjection;
+}
+
+const Frustum& Camera::getFrustum() const
+{
+    if (_bits & CAMERA_DIRTY_BOUNDS)
+    {
+        // Update our bounding frustum from our view projection matrix.
+        _bounds.set(getViewProjectionMatrix());
+
+        _bits &= ~CAMERA_DIRTY_BOUNDS;
+    }
+
+    return _bounds;
+}
+
+void Camera::project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth) const
+{
+    GP_ASSERT(x);
+    GP_ASSERT(y);
+
+    // Transform the point to clip-space.
+    Vector4 clipPos;
+    getViewProjectionMatrix().transformVector(Vector4(position.x, position.y, position.z, 1.0f), &clipPos);
+
+    // Compute normalized device coordinates.
+    GP_ASSERT(clipPos.w != 0.0f);
+    float ndcX = clipPos.x / clipPos.w;
+    float ndcY = clipPos.y / clipPos.w;
+
+    // Compute screen coordinates by applying our viewport transformation.
+    *x = viewport.x + (ndcX + 1.0f) * 0.5f * viewport.width;
+    *y = viewport.y + (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
+    if (depth)
+    {
+        float ndcZ = clipPos.z / clipPos.w;
+        *depth = (ndcZ + 1.0f) / 2.0f;
+    }
+}
+
+void Camera::project(const Rectangle& viewport, const Vector3& position, Vector2* out) const
+{
+    GP_ASSERT(out);
+    float x, y;
+    project(viewport, position, &x, &y);
+    out->set(x, y);
+}
+
+void Camera::project(const Rectangle& viewport, const Vector3& position, Vector3* out) const
+{
+    GP_ASSERT(out);
+    float x, y, depth;
+    project(viewport, position, &x, &y, &depth);
+    out->set(x, y, depth);
+}
+
+void Camera::unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst) const
+{
+    GP_ASSERT(dst);
+    
+    // Create our screen space position in NDC.
+    GP_ASSERT(viewport.width != 0.0f && viewport.height != 0.0f);
+    Vector4 screen((x - viewport.x) / viewport.width, ((viewport.height - y) - viewport.y) / viewport.height, depth, 1.0f);
+
+    // Map to range -1 to 1.
+    screen.x = screen.x * 2.0f - 1.0f;
+    screen.y = screen.y * 2.0f - 1.0f;
+    screen.z = screen.z * 2.0f - 1.0f;
+
+    // Transform the screen-space NDC by our inverse view projection matrix.
+    getInverseViewProjectionMatrix().transformVector(screen, &screen);
+
+    // Divide by our W coordinate.
+    if (screen.w != 0.0f)
+    {
+        screen.x /= screen.w;
+        screen.y /= screen.w;
+        screen.z /= screen.w;
+    }
+
+    dst->set(screen.x, screen.y, screen.z);
+}
+
+void Camera::pickRay(const Rectangle& viewport, float x, float y, Ray* dst) const
+{
+    GP_ASSERT(dst);
+
+    // Get the world-space position at the near clip plane.
+    Vector3 nearPoint;
+    unproject(viewport, x, y, 0.0f, &nearPoint);
+
+    // Get the world-space position at the far clip plane.
+    Vector3 farPoint;
+    unproject(viewport, x, y, 1.0f, &farPoint);
+
+    // Set the direction of the ray.
+    Vector3 direction;
+    Vector3::subtract(farPoint, nearPoint, &direction);
+    direction.normalize();
+
+    dst->set(nearPoint, direction);
+}
+
+Camera* Camera::clone(NodeCloneContext &context) const
+{
+    Camera* cameraClone = NULL;
+    if (getCameraType() == PERSPECTIVE)
+    {
+        cameraClone = createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane);
+    }
+    else if (getCameraType() == ORTHOGRAPHIC)
+    {
+        cameraClone = createOrthographic(getZoomX(), getZoomY(), getAspectRatio(), _nearPlane, _farPlane);
+    }
+    GP_ASSERT(cameraClone);
+
+    if (Node* node = context.findClonedNode(getNode()))
+    {
+        cameraClone->setNode(node);
+    }
+    return cameraClone;
+}
+
+void Camera::transformChanged(Transform* transform, long cookie)
+{
+    _bits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
+
+    cameraChanged();
+}
+
+void Camera::cameraChanged()
+{
+    if (_listeners == NULL)
+        return;
+
+    for (std::list<Camera::Listener*>::iterator itr = _listeners->begin(); itr != _listeners->end(); ++itr)
+    {
+        Camera::Listener* listener = (*itr);
+        listener->cameraChanged(this);
+    }
+}
+
+void Camera::addListener(Camera::Listener* listener)
+{
+    GP_ASSERT(listener);
+
+    if (_listeners == NULL)
+        _listeners = new std::list<Camera::Listener*>();
+
+    _listeners->push_back(listener);
+}
+
+void Camera::removeListener(Camera::Listener* listener)
+{
+    GP_ASSERT(listener);
+
+    if (_listeners)
+    {
+        for (std::list<Camera::Listener*>::iterator itr = _listeners->begin(); itr != _listeners->end(); ++itr)
+        {
+            if ((*itr) == listener)
+            {
+                _listeners->erase(itr);
+                break;
+            }
+        }
+    }
+}
+
+}

+ 44 - 6
gameplay/src/Camera.h

@@ -31,6 +31,24 @@ public:
         ORTHOGRAPHIC = 2
     };
 
+    /**
+     * Listener interface for camera events.
+     */
+    class Listener
+    {
+    public:
+
+        virtual ~Listener() { }
+
+        /**
+         * Handles when an camera settings change or the transform changed for the node its attached to.
+         *
+         * @param transform The Transform object that was changed.
+         * @param cookie Cookie value that was specified when the listener was registered.
+         */
+        virtual void cameraChanged(Camera* camera) = 0;
+    };
+
     /**
      * Creates a perspective camera.
      *
@@ -194,10 +212,10 @@ public:
     /**
      * Sets a custom projection matrix to be used by the camera.
      *
-     * Setting a custom projection matrix results in the internally 
-     * computed projection matrix being completely overriden until
+     * Setting a custom projection matrix results in the internally
+     * computed projection matrix being completely overridden until
      * the resetProjectionMatrix method is called. A custom projection
-     * matrix is normally not neccessary, but can be used for special
+     * matrix is normally not necessary, but can be used for special
      * projection effects, such as setting an oblique view frustum
      * for near plane clipping.
      *
@@ -287,6 +305,20 @@ public:
      */
     void pickRay(const Rectangle& viewport, float x, float y, Ray* dst) const;
 
+    /**
+    * Adds a camera listener.
+    *
+    * @param listener The listener to add.
+    */
+    void addListener(Camera::Listener* listener);
+
+    /**
+     * Removes a camera listener.
+     *
+     * @param listener The listener to remove.
+     */
+    void removeListener(Camera::Listener* listener);
+
 private:
 
     /**
@@ -311,21 +343,26 @@ private:
 
     /**
      * Clones the camera and returns a new camera.
-     * 
+     *
      * @param context The clone context.
      * @return The newly created camera.
      */
     Camera* clone(NodeCloneContext &context) const;
 
+    /**
+     * Sets the node associated with this camera.
+     */
+    void setNode(Node* node);
+
     /**
      * @see Transform::Listener::transformChanged
      */
     void transformChanged(Transform* transform, long cookie);
 
     /**
-     * Sets the node associated with this camera.
+     *
      */
-    void setNode(Node* node);
+    void cameraChanged();
 
     Camera::Type _type;
     float _fieldOfView;
@@ -341,6 +378,7 @@ private:
     mutable Frustum _bounds;
     mutable int _bits;
     Node* _node;
+    std::list<Camera::Listener*>* _listeners;
 };
 
 }

+ 182 - 206
gameplay/src/CheckBox.cpp

@@ -1,206 +1,182 @@
-#include "Base.h"
-#include "CheckBox.h"
-#include "Game.h"
-
-namespace gameplay
-{
-
-CheckBox::CheckBox() : _checked(false), _image(NULL)
-{
-}
-
-CheckBox::~CheckBox()
-{
-
-}
-
-CheckBox* CheckBox::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    CheckBox* checkBox = new CheckBox();
-    if (id)
-        checkBox->_id = id;
-    checkBox->setStyle(style);
-
-    return checkBox;
-}
-
-Control* CheckBox::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    GP_ASSERT(properties);
-
-    CheckBox* checkBox = new CheckBox();
-    checkBox->initialize(style, properties);
-    properties->getVector2("imageSize", &checkBox->_imageSize);
-    checkBox->_checked = properties->getBool("checked");
-
-    return checkBox;
-}
-
-bool CheckBox::isChecked()
-{
-    return _checked;
-}
-
-void CheckBox::setChecked(bool checked)
-{
-    if (_checked != checked)
-    {
-        _checked = checked;
-        _dirty = true;
-        notifyListeners(Control::Listener::VALUE_CHANGED);
-    }
-}
-
-void CheckBox::setImageSize(float width, float height)
-{
-    _imageSize.set(width, height);
-    _dirty = true;
-}
-
-const Vector2& CheckBox::getImageSize() const
-{
-    return _imageSize;
-}
-
-void CheckBox::addListener(Control::Listener* listener, int eventFlags)
-{
-    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
-    {
-        GP_ERROR("TEXT_CHANGED event is not applicable to CheckBox.");
-        eventFlags &= ~Control::Listener::TEXT_CHANGED;
-    }
-
-    Control::addListener(listener, eventFlags);
-}
-
-bool CheckBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    switch (evt)
-    {
-    case Touch::TOUCH_RELEASE:
-        if (_contactIndex == (int) contactIndex && _state == Control::ACTIVE)
-        {
-            if (!_parent->isScrolling() &&
-                x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-            {
-                setChecked( !_checked );
-            }
-        }
-        break;
-    }
-    return Button::touchEvent(evt, x, y, contactIndex);
-}
-
-bool CheckBox::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
-{
-    switch (evt)
-    {
-    case Gamepad::BUTTON_EVENT:
-        if (_state == Control::ACTIVE)
-        {
-            if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
-                !gamepad->isButtonDown(Gamepad::BUTTON_X))
-            {
-                setChecked( !_checked );
-            }
-        }
-        break;
-    }
-
-    return Button::gamepadEvent(evt, gamepad, analogIndex);
-}
-
-bool CheckBox::keyEvent(Keyboard::KeyEvent evt, int key)
-{
-    if (_state == ACTIVE && evt == Keyboard::KEY_RELEASE && key == Keyboard::KEY_RETURN)
-    {
-        setChecked( !_checked );
-    }
-
-    return Button::keyEvent(evt, key);
-}
-
-void CheckBox::update(const Control* container, const Vector2& offset)
-{
-    Label::update(container, offset);
-
-    Vector2 size;
-    if (_imageSize.isZero())
-    {
-        if (_checked)
-        {
-            const Rectangle& selectedRegion = getImageRegion("checked", _state);
-            size.set(selectedRegion.width, selectedRegion.height);
-        }
-        else
-        {
-            const Rectangle& unselectedRegion = getImageRegion("unchecked", _state);
-            size.set(unselectedRegion.width, unselectedRegion.height);
-        }
-    }
-    else
-    {
-        size.set(_imageSize);
-    }
-    
-    if (_autoWidth == Control::AUTO_SIZE_FIT)
-    {
-        // Text-only width was already measured in Label::update - append image
-        setWidth(size.x + _bounds.width + 5);
-    }
-
-    if (_autoHeight == Control::AUTO_SIZE_FIT)
-    {
-        // Text-only width was already measured in Label::update - append image
-        setHeight(std::max(getHeight(), size.y));
-    }
-
-    _textBounds.x += size.x + 5;
-    
-    if (_checked)
-    {
-        _image = getImage("checked", _state);
-    }
-    else
-    {
-        _image = getImage("unchecked", _state);
-    }
-}
-
-void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
-{
-    GP_ASSERT(spriteBatch);
-    GP_ASSERT(_image);
-
-    // Left, v-center.
-    // TODO: Set an alignment for icons.
-    
-    const Rectangle& region = _image->getRegion();
-    const Theme::UVs& uvs = _image->getUVs();
-    Vector4 color = _image->getColor();
-    color.w *= _opacity;
-
-    Vector2 size;
-    if (_imageSize.isZero())
-    {
-        size.set(region.width, region.height);
-    }
-    else
-    {
-        size.set(_imageSize);
-    }
-
-    Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
-
-    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
-}
-
-const char* CheckBox::getType() const
-{
-    return "checkBox";
-}
-
-}
+#include "Base.h"
+#include "CheckBox.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+CheckBox::CheckBox() : _checked(false), _image(NULL)
+{
+}
+
+CheckBox::~CheckBox()
+{
+
+}
+
+CheckBox* CheckBox::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    CheckBox* checkBox = new CheckBox();
+    if (id)
+        checkBox->_id = id;
+    checkBox->setStyle(style);
+
+    return checkBox;
+}
+
+Control* CheckBox::create(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    CheckBox* checkBox = new CheckBox();
+    checkBox->initialize(style, properties);
+    properties->getVector2("imageSize", &checkBox->_imageSize);
+    checkBox->_checked = properties->getBool("checked");
+
+    return checkBox;
+}
+
+bool CheckBox::isChecked()
+{
+    return _checked;
+}
+
+void CheckBox::setChecked(bool checked)
+{
+    if (_checked != checked)
+    {
+        _checked = checked;
+        _dirty = true;
+        notifyListeners(Control::Listener::VALUE_CHANGED);
+    }
+}
+
+void CheckBox::setImageSize(float width, float height)
+{
+    _imageSize.set(width, height);
+    _dirty = true;
+}
+
+const Vector2& CheckBox::getImageSize() const
+{
+    return _imageSize;
+}
+
+void CheckBox::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
+    {
+        GP_ERROR("TEXT_CHANGED event is not applicable to CheckBox.");
+        eventFlags &= ~Control::Listener::TEXT_CHANGED;
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
+bool CheckBox::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+    if (getState() == ACTIVE && evt == Keyboard::KEY_RELEASE && key == Keyboard::KEY_RETURN)
+    {
+        setChecked( !_checked );
+    }
+
+    return Button::keyEvent(evt, key);
+}
+
+void CheckBox::controlEvent(Control::Listener::EventType evt)
+{
+    Button::controlEvent(evt);
+
+    switch (evt)
+    {
+    case Control::Listener::CLICK:
+        setChecked( !_checked );
+        break;
+    }
+}
+
+void CheckBox::update(const Control* container, const Vector2& offset)
+{
+    Label::update(container, offset);
+
+    Control::State state = getState();
+
+    Vector2 size;
+    if (_imageSize.isZero())
+    {
+        if (_checked)
+        {
+            const Rectangle& selectedRegion = getImageRegion("checked", state);
+            size.set(selectedRegion.width, selectedRegion.height);
+        }
+        else
+        {
+            const Rectangle& unselectedRegion = getImageRegion("unchecked", state);
+            size.set(unselectedRegion.width, unselectedRegion.height);
+        }
+    }
+    else
+    {
+        size.set(_imageSize);
+    }
+    
+    if (_autoWidth == Control::AUTO_SIZE_FIT)
+    {
+        // Text-only width was already measured in Label::update - append image
+        setWidth(size.x + _bounds.width + 5);
+    }
+
+    if (_autoHeight == Control::AUTO_SIZE_FIT)
+    {
+        // Text-only width was already measured in Label::update - append image
+        setHeight(std::max(getHeight(), size.y));
+    }
+
+    _textBounds.x += size.x + 5;
+    
+    if (_checked)
+    {
+        _image = getImage("checked", state);
+    }
+    else
+    {
+        _image = getImage("unchecked", state);
+    }
+}
+
+void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    GP_ASSERT(spriteBatch);
+    GP_ASSERT(_image);
+
+    // Left, v-center.
+    // TODO: Set an alignment for icons.
+    
+    const Rectangle& region = _image->getRegion();
+    const Theme::UVs& uvs = _image->getUVs();
+    Vector4 color = _image->getColor();
+    color.w *= _opacity;
+
+    Vector2 size;
+    if (_imageSize.isZero())
+    {
+        size.set(region.width, region.height);
+    }
+    else
+    {
+        size.set(_imageSize);
+    }
+
+    Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
+
+    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
+}
+
+const char* CheckBox::getType() const
+{
+    return "checkBox";
+}
+
+}

+ 176 - 193
gameplay/src/CheckBox.h

@@ -1,193 +1,176 @@
-#ifndef CHECKBOX_H_
-#define CHECKBOX_H_
-
-#include "Theme.h"
-#include "Properties.h"
-#include "Touch.h"
-#include "Button.h"
-
-namespace gameplay
-{
-
-/**
- * Defines a checkbox UI control.  This is a button that toggles between two icons when clicked.
- *
- * The following properties are available for checkboxes:
-
- @verbatim
-    checkBox <checkBoxID>
-    {
-         style       = <styleID>
-         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
-         position    = <x, y>
-         autoWidth   = <bool>
-         autoHeight  = <bool>
-         size        = <width, height>
-         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
-         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
-         text        = <string>
-         checked     = <bool>
-         iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.
-         consumeEvents = <bool>  // Whether the checkbox propagates input events to the Game's input event handler. Default is true.
-    }
- @endverbatim
- */
-class CheckBox : public Button
-{
-    friend class Container;
-	friend class ControlFactory;
-
-public:
-
-    /**
-     * Create a new check box control.
-     *
-     * @param id The control's ID.
-     * @param style The control's style.
-     *
-     * @return The new check box.
-     * @script{create}
-     */
-    static CheckBox* create(const char* id, Theme::Style* style);
-
-    /**
-     * Gets whether this checkbox is checked.
-     *
-     * @return Whether this checkbox is checked.
-     */
-    bool isChecked();
-
-    /**
-     * Sets whether the checkbox is checked.
-     *
-     * @param checked TRUE if the checkbox is checked; FALSE if the checkbox is not checked.
-     */
-    void setChecked(bool checked);
-
-    /**
-     * Set the size to draw the checkbox icon.
-     *
-     * @param width The width to draw the checkbox icon.
-     * @param height The height to draw the checkbox icon.
-     */
-    void setImageSize(float width, float height);
-
-    /**
-     * Get the size at which the checkbox icon will be drawn.
-     *
-     * @return The size of the checkbox icon.
-     */
-    const Vector2& getImageSize() const;
-
-    /**
-     * @see Control::getType
-     */
-    const char* getType() const;
-
-    /**
-     * Add a listener to be notified of specific events affecting
-     * this control.  Event types can be OR'ed together.
-     * E.g. To listen to touch-press and touch-release events,
-     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
-     * as the second parameter.
-     *
-     * @param listener The listener to add.
-     * @param eventFlags The events to listen for.
-     */
-    virtual void addListener(Control::Listener* listener, int eventFlags);
-
-protected:
-
-    /**
-     * Constructor.
-     */
-    CheckBox();
-
-    /**
-     * Destructor.
-     */
-    ~CheckBox();
-
-    /**
-     * Create a checkbox with a given style and properties.
-     *
-     * @param style The style to apply to this checkbox.
-     * @param properties The properties to set on this checkbox.
-     * @param theme The theme to set on this control if needed
-	 *
-     * @return The new checkbox.
-     */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
-
-    /**
-     * Touch callback on touch events.  Controls return true if they consume the touch event.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by the control.
-     *
-     * @see Touch::TouchEvent
-     */
-    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-
-    /**
-     * Gamepad callback on gamepad events.
-     *
-     * @see Control::gamepadEvent
-     */
-    bool gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
-
-    /**
-     * Keyboard callback on key events.
-     *
-     * @see Keyboard::KeyEvent
-     * @see Keyboard::Key
-     */
-    bool keyEvent(Keyboard::KeyEvent evt, int key);
-
-    /**
-     * Called when a control's properties change.  Updates this control's internal rendering
-     * properties, such as its text viewport.
-     *
-     * @param container This control's parent container.
-     * @param offset The position offset.
-     */
-    void update(const Control* container, const Vector2& offset);
-
-    /**
-     * Draw the checkbox icon associated with this control.
-     *
-     * @param spriteBatch The sprite batch containing this control's icons.
-     * @param clip The container position this control is relative to.
-     */
-    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-    /**
-     * Whether this checkbox is currently checked.
-     */
-    bool _checked;
-
-    /**
-     * The size to draw the checkbox icon, if different from its size in the texture.
-     */
-    Vector2 _imageSize;
-
-    /**
-     * The Theme::ThemeImage to display for the checkbox.
-     */
-    Theme::ThemeImage* _image;
-
-private:
-
-    /*
-     * Constructor.
-     */
-    CheckBox(const CheckBox& copy);
-};
-
-}
-
-#endif
+#ifndef CHECKBOX_H_
+#define CHECKBOX_H_
+
+#include "Theme.h"
+#include "Properties.h"
+#include "Touch.h"
+#include "Button.h"
+
+namespace gameplay
+{
+
+/**
+ * Defines a checkbox UI control.  This is a button that toggles between two icons when clicked.
+ *
+ * The following properties are available for checkboxes:
+
+ @verbatim
+    checkBox <checkBoxID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+         checked     = <bool>
+         iconSize    = <width, height>   // The size to draw the checkbox icon, if different from its size in the texture.
+         consumeEvents = <bool>  // Whether the checkbox propagates input events to the Game's input event handler. Default is true.
+    }
+ @endverbatim
+ */
+class CheckBox : public Button
+{
+    friend class Container;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Create a new check box control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new check box.
+     * @script{create}
+     */
+    static CheckBox* create(const char* id, Theme::Style* style);
+
+    /**
+     * Gets whether this checkbox is checked.
+     *
+     * @return Whether this checkbox is checked.
+     */
+    bool isChecked();
+
+    /**
+     * Sets whether the checkbox is checked.
+     *
+     * @param checked TRUE if the checkbox is checked; FALSE if the checkbox is not checked.
+     */
+    void setChecked(bool checked);
+
+    /**
+     * Set the size to draw the checkbox icon.
+     *
+     * @param width The width to draw the checkbox icon.
+     * @param height The height to draw the checkbox icon.
+     */
+    void setImageSize(float width, float height);
+
+    /**
+     * Get the size at which the checkbox icon will be drawn.
+     *
+     * @return The size of the checkbox icon.
+     */
+    const Vector2& getImageSize() const;
+
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    CheckBox();
+
+    /**
+     * Destructor.
+     */
+    ~CheckBox();
+
+    /**
+     * Create a checkbox with a given style and properties.
+     *
+     * @param style The style to apply to this checkbox.
+     * @param properties The properties to set on this checkbox.
+     *
+     * @return The new checkbox.
+     */
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    /**
+     * Keyboard callback on key events.
+     *
+     * @see Keyboard::KeyEvent
+     * @see Keyboard::Key
+     */
+    bool keyEvent(Keyboard::KeyEvent evt, int key);
+
+    /**
+     * @see Control#controlEvent
+     */
+    void controlEvent(Control::Listener::EventType evt);
+
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param container This control's parent container.
+     * @param offset The position offset.
+     */
+    void update(const Control* container, const Vector2& offset);
+
+    /**
+     * Draw the checkbox icon associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The container position this control is relative to.
+     */
+    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    /**
+     * Whether this checkbox is currently checked.
+     */
+    bool _checked;
+
+    /**
+     * The size to draw the checkbox icon, if different from its size in the texture.
+     */
+    Vector2 _imageSize;
+
+    /**
+     * The Theme::ThemeImage to display for the checkbox.
+     */
+    Theme::ThemeImage* _image;
+
+private:
+
+    /*
+     * Constructor.
+     */
+    CheckBox(const CheckBox& copy);
+};
+
+}
+
+#endif

+ 1526 - 1985
gameplay/src/Container.cpp

@@ -1,1985 +1,1526 @@
-#include "Base.h"
-#include "Container.h"
-#include "Layout.h"
-#include "AbsoluteLayout.h"
-#include "FlowLayout.h"
-#include "VerticalLayout.h"
-#include "Label.h"
-#include "Button.h"
-#include "CheckBox.h"
-#include "RadioButton.h"
-#include "Slider.h"
-#include "TextBox.h"
-#include "Joystick.h"
-#include "ImageControl.h"
-#include "Game.h"
-#include "ControlFactory.h"
-
-namespace gameplay
-{
-
-// If the user stops scrolling for this amount of time (in millis) before touch/click release, don't apply inertia.
-static const long SCROLL_INERTIA_DELAY = 100L;
-// Factor to multiply friction by before applying to velocity.
-static const float SCROLL_FRICTION_FACTOR = 5.0f;
-// Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
-static const float SCROLL_THRESHOLD = 10.0f;
-// Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
-static const float JOYSTICK_THRESHOLD = 0.75f;
-// Scroll speed when using a DPad -- max scroll speed when using a joystick.
-static const float GAMEPAD_SCROLL_SPEED = 500.0f;
-// If the DPad or joystick is held down, this is the initial delay in milliseconds between focus change events.
-static const float FOCUS_CHANGE_REPEAT_DELAY = 300.0f;
-
-/**
- * Sort function for use with _controls.sort(), based on Z-Order.
- * 
- * @param c1 The first control
- * @param c2 The second control
- * return true if the first controls z index is less than the second.
- */
-static bool sortControlsByZOrder(Control* c1, Control* c2);
-
-void Container::clearContacts()
-{
-	for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
-		_contactIndices[i] = false;
-}
-
-Container::Container()
-    : _layout(NULL), _scrollBarTopCap(NULL), _scrollBarVertical(NULL), _scrollBarBottomCap(NULL),
-      _scrollBarLeftCap(NULL), _scrollBarHorizontal(NULL), _scrollBarRightCap(NULL),
-      _scroll(SCROLL_NONE), _scrollBarBounds(Rectangle::empty()), _scrollPosition(Vector2::zero()),
-      _scrollBarsAutoHide(false), _scrollBarOpacity(1.0f), _scrolling(false),
-      _scrollingVeryFirstX(0), _scrollingVeryFirstY(0), _scrollingFirstX(0), _scrollingFirstY(0), _scrollingLastX(0), _scrollingLastY(0),
-      _scrollingStartTimeX(0), _scrollingStartTimeY(0), _scrollingLastTime(0),
-      _scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f), _scrollWheelSpeed(400.0f),
-      _scrollingRight(false), _scrollingDown(false),
-      _scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
-      _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0),
-      _focusPressed(0), _selectButtonDown(false),
-      _lastFrameTime(0), _focusChangeRepeat(false),
-      _focusChangeStartTime(0), _focusChangeRepeatDelay(FOCUS_CHANGE_REPEAT_DELAY), _focusChangeCount(0),
-      _totalWidth(0), _totalHeight(0),
-      _initializedWithScroll(false), _scrollWheelRequiresFocus(false), _allowRelayout(true)
-{
-	clearContacts();
-}
-
-Container::~Container()
-{
-    std::vector<Control*>::iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        SAFE_RELEASE((*it));
-    }
-    SAFE_RELEASE(_layout);
-}
-
-Container* Container::create(const char* id, Theme::Style* style, Layout::Type layoutType)
-{
-    GP_ASSERT(style);
-
-    Container* container = Container::create(layoutType);
-    if (id)
-        container->_id = id;
-    container->_style = style;
-    return container;
-}
-
-Container* Container::create(Layout::Type type)
-{
-    Layout* layout = NULL;
-    switch (type)
-    {
-    case Layout::LAYOUT_ABSOLUTE:
-        layout = AbsoluteLayout::create();
-        break;
-    case Layout::LAYOUT_FLOW:
-        layout = FlowLayout::create();
-        break;
-    case Layout::LAYOUT_VERTICAL:
-        layout = VerticalLayout::create();
-        break;
-    default:
-        layout = AbsoluteLayout::create();
-        break;
-    }
-
-    Container* container = new Container();
-    container->_layout = layout;
-
-    return container;
-}
-
-Control* Container::create(Theme::Style* style, Properties* properties, Theme* theme)
-{
-    GP_ASSERT(properties);
-
-    // Parse layout
-    Container* container;
-    Properties* layoutNS = properties->getNamespace("layout", true, false);
-    if (layoutNS)
-    {
-        Layout::Type layoutType = getLayoutType(layoutNS->getString("type"));
-        container = Container::create(layoutType);
-        switch (layoutType)
-        {
-        case Layout::LAYOUT_FLOW:
-            static_cast<FlowLayout*>(container->getLayout())->setSpacing(layoutNS->getInt("horizontalSpacing"), layoutNS->getInt("verticalSpacing"));
-            break;
-        case Layout::LAYOUT_VERTICAL:
-            static_cast<VerticalLayout*>(container->getLayout())->setSpacing(layoutNS->getInt("spacing"));
-            break;
-        }
-    }
-    else
-    {
-        container = Container::create(getLayoutType(properties->getString("layout")));
-    }
-
-    container->initialize(style, properties);
-    container->_scroll = getScroll(properties->getString("scroll"));
-    container->_scrollBarsAutoHide = properties->getBool("scrollBarsAutoHide");
-    if (container->_scrollBarsAutoHide)
-    {
-        container->_scrollBarOpacity = 0.0f;
-    }
-    
-    container->_scrollWheelRequiresFocus = properties->getBool("scrollWheelRequiresFocus");
-    if (properties->exists("scrollingFriction"))
-        container->_scrollingFriction = properties->getFloat("scrollingFriction");
-    if (properties->exists("scrollWheelSpeed"))
-        container->_scrollWheelSpeed = properties->getFloat("scrollWheelSpeed");
-
-    container->addControls(theme, properties);
-    container->_layout->update(container, container->_scrollPosition);
-
-    return container;
-}
-
-void Container::addControls(Theme* theme, Properties* properties)
-{
-    GP_ASSERT(theme);
-    GP_ASSERT(properties);
-
-    // Add all the controls to this container.
-    Properties* controlSpace = properties->getNextNamespace();
-    while (controlSpace != NULL)
-    {
-        Control* control = NULL;
-
-        const char* controlStyleName = controlSpace->getString("style");
-        Theme::Style* controlStyle = NULL;
-        if (controlStyleName)
-        {
-            controlStyle = theme->getStyle(controlStyleName);
-        }
-        else
-        {
-            controlStyle = theme->getEmptyStyle();
-        }
-
-        std::string controlName(controlSpace->getNamespace());
-        std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);
-
-		// Create our control from the factory of registered controls.
-		control = ControlFactory::getInstance()->createControl(controlName.c_str(), controlStyle, controlSpace, theme);
-
-        // Add the new control to the form.
-        if (control)
-        {
-            addControl(control);
-            control->release();
-        }
-
-        // Get the next control.
-        controlSpace = properties->getNextNamespace();
-    }
-
-    // Sort controls by Z-Order.
-    sortControls();
-}
-
-Layout* Container::getLayout()
-{
-    return _layout;
-}
-
-unsigned int Container::addControl(Control* control)
-{
-    GP_ASSERT(control);
-
-    if (control->_parent && control->_parent != this)
-    {
-        control->_parent->removeControl(control);
-    }
-
-    if (control->getZIndex() == -1)
-    {
-        control->setZIndex(_zIndexDefault++);
-    }
-
-    if (control->getFocusIndex() == -1)
-    {
-        control->setFocusIndex(_focusIndexDefault++);
-    }
-
-    int focusIndex = control->getFocusIndex();
-    if (focusIndex > _focusIndexMax)
-        _focusIndexMax = focusIndex;
-
-    if (control->_parent != this)
-    {
-        _controls.push_back(control);
-        control->addRef();
-        control->_parent = this;
-        sortControls();
-        return (unsigned int)(_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 (unsigned int)i;
-            }
-        }
-
-        // Should never reach this.
-        GP_ASSERT(false);
-        return 0;
-    }
-}
-
-void Container::insertControl(Control* control, unsigned int index)
-{
-    GP_ASSERT(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;
-    Control* control = *it;
-    _controls.erase(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)
-        {
-            c->_parent = NULL;
-            SAFE_RELEASE(c);
-            _controls.erase(it);
-            return;
-        }
-    }
-}
-
-void Container::removeControl(Control* control)
-{
-    GP_ASSERT(control);
-    std::vector<Control*>::iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        if (*it == control)
-        {
-            control->_parent = NULL;
-            SAFE_RELEASE(control);
-            _controls.erase(it);
-            return;
-        }
-    }
-}
-
-Control* Container::getControl(unsigned int index) const
-{
-    std::vector<Control*>::const_iterator it = _controls.begin() + index;
-    return *it;
-}
-
-Control* Container::getControl(const char* id) const
-{
-    GP_ASSERT(id);
-    std::vector<Control*>::const_iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        Control* c = *it;
-        GP_ASSERT(c);
-        if (strcmp(id, c->getId()) == 0)
-        {
-            return c;
-        }
-        else if (c->isContainer())
-        {
-            Control* cc = ((Container*)c)->getControl(id);
-            if (cc)
-            {
-                return cc;
-            }
-        }
-    }
-    return NULL;
-}
-
-const std::vector<Control*>& Container::getControls() const
-{
-    return _controls;
-}
-
-void Container::setScroll(Scroll scroll)
-{
-    if (scroll != _scroll)
-    {
-        _scroll = scroll;
-        _dirty = true;
-    }
-}
-
-Container::Scroll Container::getScroll() const
-{
-    return _scroll;
-}
-
-void Container::setScrollBarsAutoHide(bool autoHide)
-{
-    if (autoHide != _scrollBarsAutoHide)
-    {
-        _scrollBarsAutoHide = autoHide;
-        _dirty = true;
-    }
-}
-
-bool Container::isScrollBarsAutoHide() const
-{
-    return _scrollBarsAutoHide;
-}
-
-bool Container::isScrolling() const
-{
-    if (_parent && _parent->isScrolling())
-        return true;
-
-    return (_scrolling &&
-            (abs(_scrollingLastX - _scrollingVeryFirstX) > SCROLL_THRESHOLD ||
-             abs(_scrollingLastY - _scrollingVeryFirstY) > SCROLL_THRESHOLD));
-}
-
-const Vector2& Container::getScrollPosition() const
-{
-    return _scrollPosition;
-}
-
-void Container::setScrollPosition(const Vector2& scrollPosition)
-{
-    _scrollPosition = scrollPosition;
-}
-
-Animation* Container::getAnimation(const char* id) const
-{
-    std::vector<Control*>::const_iterator itr = _controls.begin();
-    std::vector<Control*>::const_iterator end = _controls.end();
-    Control* control = NULL;
-    for (; itr != end; itr++)
-    {
-        control = *itr;
-        GP_ASSERT(control);
-        Animation* animation = control->getAnimation(id);
-        if (animation)
-            return animation;
-
-        if (control->isContainer())
-        {
-            animation = ((Container*)control)->getAnimation(id);
-            if (animation)
-                return animation;
-        }
-    }
-    return NULL;
-}
-
-const char* Container::getType() const
-{
-    return "container";
-}
-
-bool Container::getScrollWheelRequiresFocus() const
-{
-    return _scrollWheelRequiresFocus;
-}
-
-void Container::setScrollWheelRequiresFocus(bool required)
-{
-    _scrollWheelRequiresFocus = required;
-}
-
-void Container::update(const Control* container, const Vector2& offset)
-{
-    // Update this container's viewport.
-    Control::update(container, offset);
-
-    // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
-    if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
-    {
-        _scrollBarLeftCap = getImage("scrollBarLeftCap", _state);
-        _scrollBarHorizontal = getImage("horizontalScrollBar", _state);
-        _scrollBarRightCap = getImage("scrollBarRightCap", _state);
-
-        GP_ASSERT(_scrollBarLeftCap && _scrollBarHorizontal && _scrollBarRightCap);
-
-        _viewportBounds.height -= _scrollBarHorizontal->getRegion().height;
-        _viewportClipBounds.height -= _scrollBarHorizontal->getRegion().height;
-    }
-
-    if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
-    {
-        _scrollBarTopCap = getImage("scrollBarTopCap", _state);
-        _scrollBarVertical = getImage("verticalScrollBar", _state);
-        _scrollBarBottomCap = getImage("scrollBarBottomCap", _state);
-
-        GP_ASSERT(_scrollBarTopCap && _scrollBarVertical && _scrollBarBottomCap);
-
-        _viewportBounds.width -= _scrollBarVertical->getRegion().width;
-        _viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
-    }
-
-    GP_ASSERT(_layout);
-    if (_scroll != SCROLL_NONE)
-    {
-        updateScroll();
-    }
-    else
-    {
-        _layout->update(this, Vector2::zero());
-    }
-
-    // Handle automatically sizing based on our children
-    if (_autoWidth == Control::AUTO_SIZE_FIT || _autoHeight == Control::AUTO_SIZE_FIT)
-    {
-        Vector2 oldSize(_bounds.width, _bounds.height);
-        bool sizeChanged = false;
-        bool relayout = false;
-
-        if (_autoWidth == Control::AUTO_SIZE_FIT)
-        {
-            // Size ourself to tightly fit the width of our children
-            float width = 0;
-            for (std::vector<Control*>::const_iterator it = _controls.begin(); it < _controls.end(); ++it)
-            {
-                Control* ctrl = *it;
-                if (ctrl->isXPercentage() || ctrl->isWidthPercentage())
-                {
-                    // We (this control's parent) are resizing and our child's layout
-                    // depends on our size, so we need to dirty it
-                    ctrl->_dirty = true;
-                    relayout = _allowRelayout;
-                }
-                else
-                {
-                    float w = ctrl->getX() + ctrl->getWidth();
-                    if (width < w)
-                        width = w;
-                }
-            }
-            width += getBorder(_state).left + getBorder(_state).right + getPadding().left + getPadding().right;
-            if (width != oldSize.x)
-            {
-                setWidth(width);
-                sizeChanged = true;
-            }
-        }
-
-        if (_autoHeight == Control::AUTO_SIZE_FIT)
-        {
-            // Size ourself to tightly fit the height of our children
-            float height = 0;
-            for (std::vector<Control*>::const_iterator it = _controls.begin(); it < _controls.end(); ++it)
-            {
-                Control* ctrl = *it;
-                if (ctrl->isYPercentage() || ctrl->isHeightPercentage())
-                {
-                    // We (this control's parent) are resizing and our child's layout
-                    // depends on our size, so we need to dirty it
-                    ctrl->_dirty = true;
-                    relayout = _allowRelayout;
-                }
-                else
-                {
-                    float h = ctrl->getY() + ctrl->getHeight();
-                    if (height < h)
-                        height = h;
-                }
-            }
-            height += getBorder(_state).top + getBorder(_state).bottom + getPadding().top + getPadding().bottom;
-            if (height != oldSize.y)
-            {
-                setHeight(height);
-                sizeChanged = true;
-            }
-        }
-
-        if (sizeChanged && relayout)
-        {
-            // Our size changed and as a result we need to force another layout.
-            // Prevent infinitely recursive layouts by disabling relayout for the next call.
-            _allowRelayout = false;
-            update(container, offset);
-            _allowRelayout = true;
-        }
-    }
-}
-
-void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
-{
-    if (needsClear)
-    {
-        GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
-        float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
-        GL_ASSERT( glScissor(_clearBounds.x, clearY, _clearBounds.width, _clearBounds.height) );
-        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
-        GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
-        needsClear = false;
-        cleared = true;
-    }
-    else if (!cleared)
-    {
-        needsClear = true;
-    }
-
-    if (!_visible)
-    {
-        _dirty = false;
-        return;
-    }
-
-    spriteBatch->start();
-    Control::drawBorder(spriteBatch, clip);
-    spriteBatch->finish();
-
-    std::vector<Control*>::const_iterator it;
-    Rectangle boundsUnion = Rectangle::empty();
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        Control* control = *it;
-        GP_ASSERT(control);
-        if (!needsClear || control->isDirty() || control->_clearBounds.intersects(boundsUnion))
-        {
-            control->draw(spriteBatch, _viewportClipBounds, needsClear, cleared, targetHeight);
-            Rectangle::combine(control->_clearBounds, boundsUnion, &boundsUnion);
-        }
-    }
-
-    if (_scroll != SCROLL_NONE && (_scrollBarOpacity > 0.0f))
-    {
-        // Draw scroll bars.
-        Rectangle clipRegion(_viewportClipBounds);
-
-        spriteBatch->start();
-
-        if (_scrollBarBounds.height > 0 && ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL))
-        {
-            const Rectangle& topRegion = _scrollBarTopCap->getRegion();
-            const Theme::UVs& topUVs = _scrollBarTopCap->getUVs();
-            Vector4 topColor = _scrollBarTopCap->getColor();
-            topColor.w *= _scrollBarOpacity * _opacity;
-
-            const Rectangle& verticalRegion = _scrollBarVertical->getRegion();
-            const Theme::UVs& verticalUVs = _scrollBarVertical->getUVs();
-            Vector4 verticalColor = _scrollBarVertical->getColor();
-            verticalColor.w *= _scrollBarOpacity * _opacity;
-
-            const Rectangle& bottomRegion = _scrollBarBottomCap->getRegion();
-            const Theme::UVs& bottomUVs = _scrollBarBottomCap->getUVs();
-            Vector4 bottomColor = _scrollBarBottomCap->getColor();
-            bottomColor.w *= _scrollBarOpacity * _opacity;
-
-            clipRegion.width += verticalRegion.width;
-
-            Rectangle bounds(_viewportBounds.x + _viewportBounds.width, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
-            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
-
-            bounds.y += topRegion.height;
-            bounds.height = _scrollBarBounds.height - topRegion.height - bottomRegion.height;
-            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, verticalUVs.u1, verticalUVs.v1, verticalUVs.u2, verticalUVs.v2, verticalColor, clipRegion);
-
-            bounds.y += bounds.height;
-            bounds.height = bottomRegion.height;
-            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, bottomUVs.u1, bottomUVs.v1, bottomUVs.u2, bottomUVs.v2, bottomColor, clipRegion);
-        }
-
-        if (_scrollBarBounds.width > 0 && ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL))
-        {
-            const Rectangle& leftRegion = _scrollBarLeftCap->getRegion();
-            const Theme::UVs& leftUVs = _scrollBarLeftCap->getUVs();
-            Vector4 leftColor = _scrollBarLeftCap->getColor();
-            leftColor.w *= _scrollBarOpacity * _opacity;
-
-            const Rectangle& horizontalRegion = _scrollBarHorizontal->getRegion();
-            const Theme::UVs& horizontalUVs = _scrollBarHorizontal->getUVs();
-            Vector4 horizontalColor = _scrollBarHorizontal->getColor();
-            horizontalColor.w *= _scrollBarOpacity * _opacity;
-
-            const Rectangle& rightRegion = _scrollBarRightCap->getRegion();
-            const Theme::UVs& rightUVs = _scrollBarRightCap->getUVs();
-            Vector4 rightColor = _scrollBarRightCap->getColor();
-            rightColor.w *= _scrollBarOpacity * _opacity;
-
-            clipRegion.height += horizontalRegion.height;
-        
-            Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.y + _viewportBounds.height, leftRegion.width, leftRegion.height);
-            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
-
-            bounds.x += leftRegion.width;
-            bounds.width = _scrollBarBounds.width - leftRegion.width - rightRegion.width;
-            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, horizontalUVs.u1, horizontalUVs.v1, horizontalUVs.u2, horizontalUVs.v2, horizontalColor, clipRegion);
-
-            bounds.x += bounds.width;
-            bounds.width = rightRegion.width;
-            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, rightUVs.u1, rightUVs.v1, rightUVs.u2, rightUVs.v2, rightColor, clipRegion);
-        }
-
-        spriteBatch->finish();
-
-        if (_scrollingVelocity.isZero())
-        {
-            _dirty = false;
-        }
-    }
-    else
-    {
-        _dirty = false;
-    }
-}
-
-bool Container::isDirty()
-{
-    if (_dirty)
-    {
-        return true;
-    }
-    else
-    {
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            GP_ASSERT(*it);
-            if ((*it)->isDirty())
-            {
-                return true;
-            }
-        }
-    }
-
-    return false;
-}
-
-bool Container::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    return pointerEvent(false, evt, x, y, (int)contactIndex);
-}
-
-bool Container::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
-{
-    return pointerEvent(true, evt, x, y, 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();
-
-    bool eventConsumed = false;
-
-    std::vector<Control*>::const_iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        Control* control = *it;
-        GP_ASSERT(control);
-        if (!control->isEnabled() || !control->isVisible())
-        {
-            continue;
-        }
-
-        if ((control->hasFocus() || control->getState() == ACTIVE) && control->keyEvent(evt, key))
-        {
-            eventConsumed |= true;
-            break;
-        }
-    }
-
-    switch (evt)
-    {
-        case Keyboard::KEY_PRESS:
-        {
-            if (!eventConsumed)
-            {
-                switch (key)
-                {
-                case Keyboard::KEY_TAB:
-                    _focusPressed |= NEXT;
-                    if (moveFocus(NEXT))
-                        eventConsumed |= true;
-                    break;
-                case Keyboard::KEY_UP_ARROW:
-                    _focusPressed |= UP;
-                    if (moveFocus(UP))
-                        eventConsumed |= true;
-                    break;
-                case Keyboard::KEY_DOWN_ARROW:
-                    _focusPressed |= DOWN;
-                    if (moveFocus(DOWN))
-                        eventConsumed |= true;
-                    break;
-                case Keyboard::KEY_LEFT_ARROW:
-                    _focusPressed |= LEFT;
-                    if (moveFocus(LEFT))
-                        eventConsumed |= true;
-                    break;
-                case Keyboard::KEY_RIGHT_ARROW:
-                    _focusPressed |= RIGHT;
-                    if (moveFocus(RIGHT))
-                        eventConsumed |= true;
-                    break;
-                }
-            }
-            break;
-        }
-        case Keyboard::KEY_RELEASE:
-        {
-            switch (key)
-            {
-            case Keyboard::KEY_TAB:
-                _focusPressed &= ~NEXT;
-                eventConsumed |= true;
-                break;
-            case Keyboard::KEY_UP_ARROW:
-                _focusPressed &= ~UP;
-                eventConsumed |= true;
-                break;
-            case Keyboard::KEY_DOWN_ARROW:
-                _focusPressed &= ~DOWN;
-                eventConsumed |= true;
-                break;
-            case Keyboard::KEY_LEFT_ARROW:
-                _focusPressed &= ~LEFT;
-                eventConsumed |= true;
-                break;
-            case Keyboard::KEY_RIGHT_ARROW:
-                _focusPressed &= ~RIGHT;
-                eventConsumed |= true;
-                break;
-            }
-            break;
-        }
-    }
-
-    release();
-    return eventConsumed;
-}
-
-void Container::guaranteeFocus(Control* inFocus)
-{
-    std::vector<Control*>::const_iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        Control* control = *it;
-        GP_ASSERT(control);
-        if (control == inFocus)
-            continue;
-
-        if (control->isContainer())
-        {
-            ((Container*)control)->guaranteeFocus(inFocus);
-        }
-        else if (control->hasFocus())
-        {
-            control->setState(NORMAL);
-            return;
-        }
-    }
-}
-
-bool Container::moveFocus(Direction direction, Control* outsideControl)
-{
-    _direction = direction;
-
-    Control* start = outsideControl;
-    if (!start)
-    {
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            Control* control = *it;
-            GP_ASSERT(control);
-            if (control->hasFocus())
-            {
-                start = control;
-                break;
-            }
-        }
-    }
-
-    int focusIndex = 0;
-    Control* next = NULL;
-    if (start)
-    {
-        const Rectangle& startBounds = start->getAbsoluteBounds();
-        Vector2 vStart, vNext;
-        float distance = FLT_MAX;
-        start->setState(Control::NORMAL);
-
-        switch(direction)
-        {
-        case UP:
-            vStart.set(startBounds.x + startBounds.width * 0.5f,
-                        startBounds.y);
-            break;
-        case DOWN:
-            vStart.set(startBounds.x + startBounds.width * 0.5f,
-                        startBounds.bottom());
-            break;
-        case LEFT:
-            vStart.set(startBounds.x,
-                        startBounds.y + startBounds.height * 0.5f);
-            break;
-        case RIGHT:
-            vStart.set(startBounds.right(),
-                        startBounds.y + startBounds.height * 0.5f);
-            break;
-        case NEXT:
-            break;
-        }
-
-        if (direction != NEXT)
-        {
-            std::vector<Control*>::const_iterator itt;
-            for (itt = _controls.begin(); itt < _controls.end(); itt++)
-            {
-                Control* nextControl = *itt;
-
-                if (nextControl == start || nextControl->getFocusIndex() < 0 ||
-                    !nextControl->isEnabled() || !nextControl->isVisible())
-                {
-                    // Control is not focusable.
-                    continue;
-                }
-
-                const Rectangle& nextBounds = nextControl->getAbsoluteBounds();
-                switch(direction)
-                {
-                case UP:
-                    vNext.set(nextBounds.x + nextBounds.width * 0.5f,
-                              nextBounds.bottom());
-                    if (vNext.y > vStart.y) continue;
-                    break;
-                case DOWN:
-                    vNext.set(nextBounds.x + nextBounds.width * 0.5f,
-                              nextBounds.y);
-                    if (vNext.y < vStart.y) continue;
-                    break;
-                case LEFT:
-                    vNext.set(nextBounds.right(),
-                              nextBounds.y + nextBounds.height * 0.5f);
-                    if (vNext.x > vStart.x) continue;
-                    break;
-                case RIGHT:
-                    vNext.set(nextBounds.x,
-                              nextBounds.y + nextBounds.height * 0.5f);
-                    if (vNext.x < vStart.x) continue;
-                    break;
-                }
-
-                float nextDistance = vStart.distance(vNext);
-                if (abs(nextDistance) < distance)
-                {
-                    distance = nextDistance;
-                    next = nextControl;
-                }
-            }
-        }
-
-        if (!next)
-        {
-            // Check for controls in the given direction in our parent container.
-            if (direction != NEXT && !outsideControl && _parent && _parent->moveFocus(direction, start))
-            {
-                setState(NORMAL);
-                _focusChangeRepeat = false;
-                _focusPressed = 0;
-                return true;
-            }
-            
-            // No control is in the given direction.  Move to the next control in the focus order.
-            int focusDelta;
-            switch(direction)
-            {
-            case UP:
-            case LEFT:
-                focusDelta = -1;
-                break;
-            case DOWN:
-            case RIGHT:
-            case NEXT:
-                focusDelta = 1;
-                break;
-            }
-
-            // Find the index to search for.
-            if (outsideControl)
-            {
-                focusIndex = outsideControl->_parent->getFocusIndex() + focusDelta;
-            }
-            else
-            {
-                focusIndex = start->getFocusIndex() + focusDelta;
-            }
-
-            if (focusIndex > _focusIndexMax)
-            {
-                if (direction == NEXT && !outsideControl && _parent && _parent->moveFocus(direction, start))
-                {
-                    setState(NORMAL);
-                    _focusChangeRepeat = false;
-                    _focusPressed = 0;
-                    return true;
-                }
-
-                focusIndex = 0;
-            }
-            else if (focusIndex < 0)
-            {
-                focusIndex = _focusIndexMax;
-            }
-        }
-    }
-
-    if (!next)
-    {
-        std::vector<Control*>::const_iterator itt;
-        for (itt = _controls.begin(); itt < _controls.end(); itt++)
-        {
-            Control* nextControl = *itt;
-            if (nextControl->getFocusIndex() == focusIndex &&
-                nextControl->isEnabled() && nextControl->isVisible())
-            {
-                next = nextControl;
-                break;
-            }
-        }
-    }
-
-    // If we haven't found next by now, then there are no focusable controls in this container.
-    if (next)
-    {
-        next->setState(Control::FOCUS);
-        _dirty = true;
-
-        if (next->isContainer())
-        {
-            if ((direction == NEXT && ((Container*)next)->moveFocus(direction)) ||
-                ((Container*)next)->moveFocus(direction, start))
-            {
-                _focusChangeRepeat = false;
-                _focusPressed = 0;
-                return true;
-            }
-        }
-
-        // If the next control is not fully visible, scroll the container so that it is.
-        const Rectangle& bounds = next->getBounds();
-        if (bounds.x < _scrollPosition.x)
-        {
-            // Control is to the left of the scrolled viewport.
-            _scrollPosition.x = -bounds.x;
-        }
-        else if (bounds.x + bounds.width > _scrollPosition.x + _viewportBounds.width)
-        {
-            // Control is off to the right.
-            _scrollPosition.x = -(bounds.x + bounds.width - _viewportBounds.width);
-        }
-
-        if (bounds.y < _viewportBounds.y - _scrollPosition.y)
-        {
-            // Control is above the viewport.
-            _scrollPosition.y = -bounds.y;
-        }
-        else if (bounds.y + bounds.height > _viewportBounds.height - _scrollPosition.y)
-        {
-            // Control is below the viewport.
-            _scrollPosition.y = -(bounds.y + bounds.height - _viewportBounds.height);
-        }
-
-        if (outsideControl && outsideControl->_parent)
-        {
-            _focusPressed = outsideControl->_parent->_focusPressed;
-            _focusChangeCount = outsideControl->_parent->_focusChangeCount;
-            _focusChangeRepeatDelay = outsideControl->_parent->_focusChangeRepeatDelay;
-            outsideControl->_parent->guaranteeFocus(next);
-        }
-
-        _focusChangeStartTime = Game::getAbsoluteTime();
-        _focusChangeRepeat = true;
-        addRef();
-        Game::getInstance()->schedule(_focusChangeRepeatDelay, this);
-
-        return true;
-    }
-
-    return false;
-}
-
-void Container::timeEvent(long timeDiff, void* cookie)
-{
-    double time = Game::getAbsoluteTime();
-    if (_focusChangeRepeat && hasFocus() && _focusPressed &&
-        abs(time - timeDiff - _focusChangeRepeatDelay - _focusChangeStartTime) < 50)
-    {
-        ++_focusChangeCount;
-        if (_focusChangeCount == 5)
-        {
-            _focusChangeRepeatDelay *= 0.5;
-        }
-        moveFocus(_direction);
-    }
-    else
-    {
-        _focusChangeCount = 0;
-        _focusChangeRepeatDelay = FOCUS_CHANGE_REPEAT_DELAY;
-    }
-
-    release();
-}
-
-void Container::startScrolling(float x, float y, bool resetTime)
-{
-    _scrollingVelocity.set(-x, y);
-    _scrolling = true;
-    _scrollBarOpacity = 1.0f;
-    _dirty = true;
-
-    if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
-    {
-        _scrollBarOpacityClip->stop();
-        _scrollBarOpacityClip = NULL;
-    }
-
-    if (resetTime)
-    {
-        _lastFrameTime = Game::getGameTime();
-    }
-}
-
-void Container::stopScrolling()
-{
-    _scrollingVelocity.set(0, 0);
-    _scrolling = false;
-    _dirty = true;
-}
-
-bool Container::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
-{
-    addRef();
-
-    bool eventConsumed = false;
-
-    // Pass the event to any control that is active or in focus.
-    std::vector<Control*>::const_iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        Control* control = *it;
-        GP_ASSERT(control);
-        if (control->hasFocus() || control->getState() == Control::ACTIVE)
-        {
-            eventConsumed |= control->gamepadEvent(evt, gamepad, analogIndex);
-            break;
-        }
-    }
-
-    // First check if a selection button is down.
-    if (!_selectButtonDown)
-    {
-        if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
-            gamepad->isButtonDown(Gamepad::BUTTON_X))
-        {
-            _selectButtonDown = true;
-            _focusChangeRepeat = false;
-            eventConsumed |= _consumeInputEvents;
-        }
-    }
-    else
-    {
-        if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
-            !gamepad->isButtonDown(Gamepad::BUTTON_X))
-        {
-            _selectButtonDown = false;
-        }
-    }
-
-    Vector2 joystick;
-    gamepad->getJoystickValues(analogIndex, &joystick);
-
-    // Don't allow focus changes or scrolling while a selection button is down.
-    if (!_selectButtonDown && !eventConsumed)
-    {
-        switch (evt)
-        {
-            case Gamepad::BUTTON_EVENT:
-            {
-                // Shift focus forward or backward when the DPad is used.
-                if (!(_focusPressed & DOWN) &&
-                    gamepad->isButtonDown(Gamepad::BUTTON_DOWN))
-                {
-                    _focusPressed |= DOWN;
-                    eventConsumed = true;
-                    if (moveFocus(DOWN))
-                        break;
-                    else
-                        startScrolling(0, -GAMEPAD_SCROLL_SPEED);
-                }
-                    
-                if (!(_focusPressed & RIGHT) &&
-                    gamepad->isButtonDown(Gamepad::BUTTON_RIGHT))
-                {
-                    _focusPressed |= RIGHT;
-                    eventConsumed = true;
-                    if (moveFocus(RIGHT))
-                        break;
-                    else
-                        startScrolling(GAMEPAD_SCROLL_SPEED, 0);
-                }
-
-                if (!(_focusPressed & UP) &&
-                    gamepad->isButtonDown(Gamepad::BUTTON_UP))
-                {
-                    _focusPressed |= UP;
-                    eventConsumed = true;
-                    if (moveFocus(UP))
-                        break;
-                    else
-                        startScrolling(0, GAMEPAD_SCROLL_SPEED);
-                }
-
-                if (!(_focusPressed & LEFT) &&
-                    gamepad->isButtonDown(Gamepad::BUTTON_LEFT))
-                {
-                    _focusPressed |= LEFT;
-                    eventConsumed = true;
-                    if (moveFocus(LEFT))
-                        break;
-                    else
-                        startScrolling(-GAMEPAD_SCROLL_SPEED, 0);
-                }
-                break;
-            }
-            case Gamepad::JOYSTICK_EVENT:
-            {
-                switch (analogIndex)
-                {
-                case 0:
-                    // The left analog stick can be used in the same way as the DPad.
-                    eventConsumed = true;
-                    if (!(_focusPressed & RIGHT) &&
-                        joystick.x > JOYSTICK_THRESHOLD)
-                    {
-                        _focusPressed |= RIGHT;
-                        if (moveFocus(RIGHT))
-                            break;
-                        else
-                            startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
-                    }
-
-                    if (!(_focusPressed & DOWN) &&
-                        joystick.y < -JOYSTICK_THRESHOLD)
-                    {
-                        _focusPressed |= DOWN;
-                        if (moveFocus(DOWN))
-                            break;
-                        else
-                            startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
-                    }
-
-                    if (!(_focusPressed & LEFT) &&
-                        joystick.x < -JOYSTICK_THRESHOLD)
-                    {
-                        _focusPressed |= LEFT;
-                        if (moveFocus(LEFT))
-                            break;
-                        else
-                            startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
-                    }
-                        
-                    if (!(_focusPressed & UP) &&
-                        joystick.y > JOYSTICK_THRESHOLD)
-                    {
-                        _focusPressed |= UP;
-                        if (moveFocus(UP))
-                            break;
-                        else
-                            startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
-                    }
-                    break;
-
-                case 1:
-                    // The right analog stick can be used to scroll.
-                    if (_scroll != SCROLL_NONE)
-                    {
-                        if (_scrolling)
-                        {
-                            if (joystick.isZero())
-                            {
-                                stopScrolling();
-                            }
-                            else
-                            {
-                                startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, false);
-                            }
-                        }
-                        else
-                        {
-                            startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y);
-                        }
-                        release();
-                        return _consumeInputEvents;
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    if ((evt == Gamepad::BUTTON_EVENT || evt == Gamepad::JOYSTICK_EVENT) &&
-        analogIndex == 0)
-    {
-        if ((_focusPressed & DOWN) &&
-            !gamepad->isButtonDown(Gamepad::BUTTON_DOWN) &&
-            joystick.y > -JOYSTICK_THRESHOLD)
-        {
-            _focusPressed &= ~DOWN;
-            eventConsumed = true;
-        }
-
-        if ((_focusPressed & RIGHT) &&
-            !gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) &&
-            joystick.x < JOYSTICK_THRESHOLD)
-        {
-            _focusPressed &= ~RIGHT;
-            eventConsumed = true;
-        }
-    
-        if ((_focusPressed & UP) &&
-            !gamepad->isButtonDown(Gamepad::BUTTON_UP) &&
-            joystick.y < JOYSTICK_THRESHOLD)
-        {
-            _focusPressed &= ~UP;
-            eventConsumed = true;
-        }
-
-        if ((_focusPressed & LEFT) &&
-            !gamepad->isButtonDown(Gamepad::BUTTON_LEFT) &&
-            joystick.x > -JOYSTICK_THRESHOLD)
-        {
-            _focusPressed &= ~LEFT;
-            eventConsumed = true;
-        }
-    }
-
-    if (!_focusPressed && _scrolling)
-    {
-        stopScrolling();
-    }
-
-    release();
-    return eventConsumed;
-}
-
-bool Container::isContainer() const
-{
-    return true;
-}
-
-Layout::Type Container::getLayoutType(const char* layoutString)
-{
-    if (!layoutString)
-    {
-        return Layout::LAYOUT_ABSOLUTE;
-    }
-
-    std::string layoutName(layoutString);
-    std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
-    if (layoutName == "LAYOUT_ABSOLUTE")
-    {
-        return Layout::LAYOUT_ABSOLUTE;
-    }
-    else if (layoutName == "LAYOUT_VERTICAL")
-    {
-        return Layout::LAYOUT_VERTICAL;
-    }
-    else if (layoutName == "LAYOUT_FLOW")
-    {
-        return Layout::LAYOUT_FLOW;
-    }
-    else
-    {
-        // Default.
-        return Layout::LAYOUT_ABSOLUTE;
-    }
-}
-
-void Container::updateScroll()
-{
-    if (!_initializedWithScroll)
-    {
-        _initializedWithScroll = true;
-        _layout->update(this, _scrollPosition);
-    }
-
-    // Update time.
-    if (!_lastFrameTime)
-    {
-        _lastFrameTime = Game::getGameTime();
-    }
-    double frameTime = Game::getGameTime();
-    float elapsedTime = (float)(frameTime - _lastFrameTime);
-    _lastFrameTime = frameTime;
-
-    const Theme::Border& containerBorder = getBorder(_state);
-    const Theme::Padding& containerPadding = getPadding();
-
-    // Calculate total width and height.
-    _totalWidth = _totalHeight = 0.0f;
-    std::vector<Control*> controls = getControls();
-    for (size_t i = 0, controlsCount = controls.size(); i < controlsCount; i++)
-    {
-        Control* control = controls.at(i);
-
-        const Rectangle& bounds = control->getBounds();
-        const Theme::Margin& margin = control->getMargin();
-
-        float newWidth = bounds.x + bounds.width + margin.right;
-        if (newWidth > _totalWidth)
-        {
-            _totalWidth = newWidth;
-        }
-
-        float newHeight = bounds.y + bounds.height + margin.bottom;
-        if (newHeight > _totalHeight)
-        {
-            _totalHeight = newHeight;
-        }
-    }
-
-    float vWidth = getImageRegion("verticalScrollBar", _state).width;
-    float hHeight = getImageRegion("horizontalScrollBar", _state).height;
-    float clipWidth = _absoluteBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right - vWidth;
-    float clipHeight = _absoluteBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
-
-    // Apply and dampen inertia.
-    if (!_scrollingVelocity.isZero())
-    {
-        // Calculate the time passed since last update.
-        float elapsedSecs = (float)elapsedTime * 0.001f;
-
-        _scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
-        _scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
-
-        if (!_scrolling)
-        {
-            float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
-            _scrollingVelocity.x *= dampening;
-            _scrollingVelocity.y *= dampening;
-
-            if (fabs(_scrollingVelocity.x) < 100.0f)
-                _scrollingVelocity.x = 0.0f;
-            if (fabs(_scrollingVelocity.y) < 100.0f)
-                _scrollingVelocity.y = 0.0f;
-        }
-    }
-
-    // Stop scrolling when the far edge is reached.
-    if (-_scrollPosition.x > _totalWidth - clipWidth)
-    {
-        _scrollPosition.x = -(_totalWidth - clipWidth);
-        _scrollingVelocity.x = 0;
-    }
-    
-    if (-_scrollPosition.y > _totalHeight - clipHeight)
-    {
-        _scrollPosition.y = -(_totalHeight - clipHeight);
-        _scrollingVelocity.y = 0;
-    }
-
-    if (_scrollPosition.x > 0)
-    {
-        _scrollPosition.x = 0;
-        _scrollingVelocity.x = 0;
-    }
-
-    if (_scrollPosition.y > 0)
-    {
-        _scrollPosition.y = 0;
-        _scrollingVelocity.y = 0;
-    }
-
-    float scrollWidth = 0;
-    if (clipWidth < _totalWidth)
-        scrollWidth = (clipWidth / _totalWidth) * clipWidth;
-
-    float scrollHeight = 0;
-    if (clipHeight < _totalHeight)
-        scrollHeight = (clipHeight / _totalHeight) * clipHeight;
-
-    _scrollBarBounds.set(((-_scrollPosition.x) / _totalWidth) * clipWidth,
-                         ((-_scrollPosition.y) / _totalHeight) * clipHeight,
-                         scrollWidth, scrollHeight);
-
-    // If scroll velocity is 0 and scrollbars are not always visible, trigger fade-out animation.
-    if (!_scrolling && _scrollingVelocity.isZero() && _scrollBarsAutoHide && _scrollBarOpacity == 1.0f)
-    {
-        float to = 0;
-        _scrollBarOpacity = 0.99f;
-        if (!_scrollBarOpacityClip)
-        {
-            Animation* animation = createAnimationFromTo("scrollbar-fade-out", ANIMATE_SCROLLBAR_OPACITY, &_scrollBarOpacity, &to, Curve::QUADRATIC_IN_OUT, 500L);
-            _scrollBarOpacityClip = animation->getClip();
-        }
-        _scrollBarOpacityClip->play();
-    }
-
-    // Position controls within scroll area.
-    _layout->update(this, _scrollPosition);
-}
-
-void Container::sortControls()
-{
-    if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
-    {
-        std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
-    }
-}
-
-bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    switch(evt)
-    {
-    case Touch::TOUCH_PRESS:
-        if (_contactIndex == INVALID_CONTACT_INDEX)
-        {
-            _contactIndex = (int) contactIndex;
-            _scrollingLastX = _scrollingFirstX = _scrollingVeryFirstX = x;
-            _scrollingLastY = _scrollingFirstY = _scrollingVeryFirstY = y;
-            _scrollingVelocity.set(0, 0);
-            _scrolling = true;
-            _scrollingStartTimeX = _scrollingStartTimeY = 0;
-
-            if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
-            {
-                _scrollBarOpacityClip->stop();
-                _scrollBarOpacityClip = NULL;
-            }
-            _scrollBarOpacity = 1.0f;
-            _dirty = true;
-            return _consumeInputEvents;
-        }
-        break;
-    case Touch::TOUCH_MOVE:
-        if (_scrolling && _contactIndex == (int) contactIndex)
-        {
-            double gameTime = Game::getAbsoluteTime();
-
-            // Calculate the latest movement delta for the next update to use.
-            int vx = x - _scrollingLastX;
-            int vy = y - _scrollingLastY;
-            if (_scrollingMouseVertically)
-            {
-                float yRatio = _totalHeight / _absoluteBounds.height;
-                vy *= yRatio;
-
-                _scrollingVelocity.set(0, -vy);
-                _scrollPosition.y -= vy;
-            }
-            else if (_scrollingMouseHorizontally)
-            {
-                float xRatio = _totalWidth / _absoluteBounds.width;
-                vx *= xRatio;
-
-                _scrollingVelocity.set(-vx, 0);
-                _scrollPosition.x -= vx;
-            }
-            else
-            {
-                _scrollingVelocity.set(vx, vy);
-                _scrollPosition.x += vx;
-                _scrollPosition.y += vy;
-            }
-
-            _scrollingLastX = x;
-            _scrollingLastY = y;
-
-            // If the user changes direction, reset the start time and position.
-            bool goingRight = (vx > 0);
-            if (goingRight != _scrollingRight)
-            {
-                _scrollingFirstX = x;
-                _scrollingRight = goingRight;
-                _scrollingStartTimeX = gameTime;
-            }
-
-            bool goingDown = (vy > 0);
-            if (goingDown != _scrollingDown)
-            {
-                _scrollingFirstY = y;
-                _scrollingDown = goingDown;
-                _scrollingStartTimeY = gameTime;
-            }
-
-            if (!_scrollingStartTimeX)
-                _scrollingStartTimeX = gameTime;
-
-            if (!_scrollingStartTimeY)
-                _scrollingStartTimeY = gameTime;
-
-            _scrollingLastTime = gameTime;
-            _dirty = true;
-            return _consumeInputEvents;
-        }
-        break;
-
-    case Touch::TOUCH_RELEASE:
-        if (_contactIndex == (int) contactIndex)
-        {
-            _contactIndex = INVALID_CONTACT_INDEX;
-            _scrolling = false;
-            double gameTime = Game::getAbsoluteTime();
-            float timeSinceLastMove = (float)(gameTime - _scrollingLastTime);
-            if (timeSinceLastMove > SCROLL_INERTIA_DELAY)
-            {
-                _scrollingVelocity.set(0, 0);
-                _scrollingMouseVertically = _scrollingMouseHorizontally = false;
-                _dirty = true;
-                return _consumeInputEvents;
-            }
-
-            int dx = _scrollingLastX - _scrollingFirstX;
-            int dy = _scrollingLastY - _scrollingFirstY;
-
-            float timeTakenX = (float)(gameTime - _scrollingStartTimeX);
-            float elapsedSecsX = timeTakenX * 0.001f;
-            float timeTakenY = (float)(gameTime - _scrollingStartTimeY);
-            float elapsedSecsY = timeTakenY * 0.001f;
-
-            float vx = dx;
-            float vy = dy;
-            if (elapsedSecsX > 0)
-                vx = (float)dx / elapsedSecsX;
-            if (elapsedSecsY > 0)
-                vy = (float)dy / elapsedSecsY;
-
-            if (_scrollingMouseVertically)
-            {
-                float yRatio = _totalHeight / _absoluteBounds.height;
-                vy *= yRatio;
-                _scrollingVelocity.set(0, -vy);
-            }
-            else if (_scrollingMouseHorizontally)
-            {
-                float xRatio = _totalWidth / _absoluteBounds.width;
-                vx *= xRatio;
-                _scrollingVelocity.set(-vx, 0);
-            }
-            else
-            {
-                _scrollingVelocity.set(vx, vy);
-            }
-
-            _scrollingMouseVertically = _scrollingMouseHorizontally = false;
-            _dirty = true;
-            return _consumeInputEvents;
-        }
-        break;
-    }
-
-    return false;
-}
-
-bool Container::mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
-{
-    switch(evt)
-    {
-        case Mouse::MOUSE_PRESS_LEFT_BUTTON:
-        {
-            if (_scrollBarVertical)
-            {
-                float vWidth = _scrollBarVertical->getRegion().width;
-                Rectangle vBounds(_viewportBounds.x + _viewportBounds.width,
-                                 _scrollBarBounds.y,
-                                 vWidth, _scrollBarBounds.height);
-
-                if (x + _viewportBounds.x >= vBounds.x &&
-                    x + _viewportBounds.x <= vBounds.x + vBounds.width)
-                {
-                    // Then we're within the horizontal bounds of the vertical scrollbar.
-                    // We want to either jump up or down, or drag the scrollbar itself.
-                    if (y < vBounds.y)
-                    {
-                        _scrollPosition.y += _totalHeight / 5.0f;
-                    }
-                    else if (y > vBounds.y + vBounds.height)
-                    {
-                        _scrollPosition.y -= _totalHeight / 5.0f;
-                    }
-                    else
-                    {
-                        _scrollingMouseVertically = true;
-                    }
-                }
-            }
-            
-            if (_scrollBarHorizontal)
-            {
-                float hHeight = _scrollBarHorizontal->getRegion().height;
-                Rectangle hBounds(_scrollBarBounds.x,
-                                  _viewportBounds.y + _viewportBounds.height,
-                                  _scrollBarBounds.width, hHeight);
-            
-                if (y + _viewportBounds.y >= hBounds.y &&
-                         y + _viewportBounds.y <= hBounds.y + hBounds.height)
-                {
-                    // We're within the vertical bounds of the horizontal scrollbar.
-                    if (x < hBounds.x)
-                        _scrollPosition.x += _totalWidth / 5.0f;
-                    else if (x > hBounds.x + hBounds.width)
-                        _scrollPosition.x -= _totalWidth / 5.0f;
-                    else
-                        _scrollingMouseHorizontally = true;
-                }
-            }
-
-            return touchEventScroll(Touch::TOUCH_PRESS, x, y, 0);
-        }
-
-        case Mouse::MOUSE_MOVE:
-            return touchEventScroll(Touch::TOUCH_MOVE, x, y, 0);
-
-        case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
-            return touchEventScroll(Touch::TOUCH_RELEASE, x, y, 0);
-
-        case Mouse::MOUSE_WHEEL:
-            if ((_state == HOVER && (!_scrollWheelRequiresFocus || _previousState == FOCUS)) ||
-                _state == FOCUS && _scrollWheelRequiresFocus)
-            {
-                if (_scrollingVelocity.isZero())
-                {
-                    _lastFrameTime = Game::getGameTime();
-                }
-                _scrolling = _scrollingMouseVertically = _scrollingMouseHorizontally = false;
-
-                _scrollingVelocity.y += _scrollWheelSpeed * wheelDelta;
-
-                if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
-                {
-                    _scrollBarOpacityClip->stop();
-                    _scrollBarOpacityClip = NULL;
-                }
-                _scrollBarOpacity = 1.0f;
-                _dirty = true;
-                return _consumeInputEvents;
-            }
-            break;
-    }
-
-    return false;
-}
-
-bool Container::inContact()
-{
-	for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
-	{
-		if (_contactIndices[i])
-			return true;
-	}
-	return false;
-}
-
-bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
-{
-    if (!isEnabled() || !isVisible())
-    {
-        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();
-    float xPos = border.left + padding.left;
-    float yPos = border.top + padding.top;
-
-    Vector2* offset = NULL;
-    if (_scroll != SCROLL_NONE)
-    {
-        offset = &_scrollPosition;
-    }
-
-    std::vector<Control*>::const_iterator it;
-    for (it = _controls.begin(); it < _controls.end(); it++)
-    {
-        Control* control = *it;
-        GP_ASSERT(control);
-        if (!control->isEnabled() || !control->isVisible())
-        {
-            continue;
-        }
-
-        const Rectangle& bounds = control->getBounds();
-        float boundsX = bounds.x;
-        float boundsY = bounds.y;
-        if (offset)
-        {
-            boundsX += offset->x;
-            boundsY += offset->y;
-        }
-
-        Control::State currentState = control->getState();
-        if ((currentState != Control::NORMAL) ||
-            ((evt == Touch::TOUCH_PRESS ||
-              evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
-              evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
-              evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON ||
-              evt == Mouse::MOUSE_MOVE ||
-              evt == Mouse::MOUSE_WHEEL) &&
-                x >= xPos + boundsX &&
-                x <= xPos + boundsX + bounds.width &&
-                y >= yPos + boundsY &&
-                y <= yPos + boundsY + bounds.height))
-        {
-            // Pass on the event's clip relative to the control.
-            if (mouse)
-                eventConsumed |= control->mouseEvent((Mouse::MouseEvent)evt, x - xPos - boundsX, y - yPos - boundsY, data);
-            else
-                eventConsumed |= control->touchEvent((Touch::TouchEvent)evt, x - xPos - boundsX, y - yPos - boundsY, (unsigned int)data);
-        }
-    }
-
-    if (!isEnabled() || !isVisible())
-    {
-        _contactIndex = INVALID_CONTACT_INDEX;
-        clearContacts();
-        _scrolling = false;
-        _scrollingMouseVertically = _scrollingMouseHorizontally = false;
-
-        release();
-        return (_consumeInputEvents | eventConsumed);
-    }
-
-    bool withinClipBounds = (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                             y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height);
-    switch (evt)
-    {
-    case Touch::TOUCH_PRESS:
-        if (withinClipBounds)
-        {
-            setState(Control::ACTIVE);
-        }
-        else if (!inContact())
-        {
-            setState(Control::NORMAL);
-            _contactIndex = INVALID_CONTACT_INDEX;
-            release();
-            return false;
-        }
-        if (!mouse)
-        	_contactIndices[data] = true;
-        break;
-    case Mouse::MOUSE_MOVE:
-        if (_state != ACTIVE)
-        {
-            if (_state != HOVER && withinClipBounds)
-            {
-                _previousState = _state;
-                setState(HOVER);
-                notifyListeners(Control::Listener::ENTER);
-            }
-            else if (_state == HOVER && !withinClipBounds)
-            {
-                setState(_previousState);
-                notifyListeners(Control::Listener::LEAVE);
-            }
-            else if (_state != HOVER)
-            {
-                release();
-                return false;
-            }
-        }
-        break;
-    case Mouse::MOUSE_WHEEL:
-        if (!withinClipBounds && !_scrollWheelRequiresFocus)
-        {
-            release();
-            return false;
-        }
-        break;
-    case Touch::TOUCH_RELEASE:
-    	if (!mouse)
-    		_contactIndices[data] = false;
-
-    	if (!inContact())
-        {
-			if (_state == ACTIVE && withinClipBounds)
-			{
-				setState(FOCUS);
-			}
-			else
-			{
-				setState(NORMAL);
-			}
-        }
-        break;
-    }
-
-    if (!eventConsumed && _scroll != SCROLL_NONE &&
-        (evt != Touch::TOUCH_PRESS || withinClipBounds))
-    {
-        if ((mouse && mouseEventScroll((Mouse::MouseEvent)evt, x - xPos, y - yPos, data)) ||
-            (!mouse && touchEventScroll((Touch::TouchEvent)evt, x - xPos, y - yPos, (unsigned int)data)))
-        {
-            eventConsumed = true;
-        }
-    }
-
-    release();
-    return (_consumeInputEvents | eventConsumed);
-}
-
-Container::Scroll Container::getScroll(const char* scroll)
-{
-    if (!scroll)
-        return Container::SCROLL_NONE;
-
-    if (strcmp(scroll, "SCROLL_NONE") == 0)
-    {
-        return Container::SCROLL_NONE;
-    }
-    else if (strcmp(scroll, "SCROLL_HORIZONTAL") == 0)
-    {
-        return Container::SCROLL_HORIZONTAL;
-    }
-    else if (strcmp(scroll, "SCROLL_VERTICAL") == 0)
-    {
-        return Container::SCROLL_VERTICAL;
-    }
-    else if (strcmp(scroll, "SCROLL_BOTH") == 0)
-    {
-        return Container::SCROLL_BOTH;
-    }
-    else
-    {
-        GP_ERROR("Failed to get corresponding scroll state for unsupported value '%s'.", scroll);
-    }
-
-    return Container::SCROLL_NONE;
-}
-
-float Container::getScrollingFriction() const
-{
-    return _scrollingFriction;
-}
-
-void Container::setScrollingFriction(float friction)
-{
-    _scrollingFriction = friction;
-}
-
-float Container::getScrollWheelSpeed() const
-{
-    return _scrollWheelSpeed;
-}
-
-void Container::setScrollWheelSpeed(float speed)
-{
-    _scrollWheelSpeed = speed;
-}
-
-static bool sortControlsByZOrder(Control* c1, Control* c2)
-{
-    if (c1->getZIndex() < c2->getZIndex())
-        return true;
-
-    return false;
-}
-
-unsigned int Container::getAnimationPropertyComponentCount(int propertyId) const
-{
-    switch(propertyId)
-    {
-    case ANIMATE_SCROLLBAR_OPACITY:
-        return 1;
-    default:
-        return Control::getAnimationPropertyComponentCount(propertyId);
-    }
-}
-
-void Container::getAnimationPropertyValue(int propertyId, AnimationValue* value)
-{
-    GP_ASSERT(value);
-
-    switch(propertyId)
-    {
-    case ANIMATE_SCROLLBAR_OPACITY:
-        value->setFloat(0, _scrollBarOpacity);
-        break;
-    default:
-        Control::getAnimationPropertyValue(propertyId, value);
-        break;
-    }
-}
-
-void Container::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
-{
-    GP_ASSERT(value);
-
-    switch(propertyId)
-    {
-    case ANIMATE_SCROLLBAR_OPACITY:
-        _scrollBarOpacity = Curve::lerp(blendWeight, _opacity, value->getFloat(0));
-        _dirty = true;
-        break;
-    default:
-        Control::setAnimationPropertyValue(propertyId, value, blendWeight);
-        break;
-    }
-}
-
-}
+#include "Base.h"
+#include "Container.h"
+#include "Layout.h"
+#include "AbsoluteLayout.h"
+#include "FlowLayout.h"
+#include "VerticalLayout.h"
+#include "ControlFactory.h"
+#include "Form.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+// If the user stops scrolling for this amount of time (in millis) before touch/click release, don't apply inertia.
+static const long SCROLL_INERTIA_DELAY = 100L;
+// Factor to multiply friction by before applying to velocity.
+static const float SCROLL_FRICTION_FACTOR = 5.0f;
+// Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
+static const float SCROLL_THRESHOLD = 10.0f;
+// If the DPad or joystick is held down, this is the initial delay in milliseconds between focus change events.
+static const float FOCUS_CHANGE_REPEAT_DELAY = 300.0f;
+
+/**
+ * Sort function for use with _controls.sort(), based on Z-Order.
+ * 
+ * @param c1 The first control
+ * @param c2 The second control
+ * return true if the first controls z index is less than the second.
+ */
+static bool sortControlsByZOrder(Control* c1, Control* c2);
+
+void Container::clearContacts()
+{
+	for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
+		_contactIndices[i] = false;
+}
+
+Container::Container()
+    : _layout(NULL), _activeControl(NULL), _scrollBarTopCap(NULL), _scrollBarVertical(NULL), _scrollBarBottomCap(NULL),
+      _scrollBarLeftCap(NULL), _scrollBarHorizontal(NULL), _scrollBarRightCap(NULL),
+      _scroll(SCROLL_NONE), _scrollBarBounds(Rectangle::empty()), _scrollPosition(Vector2::zero()),
+      _scrollBarsAutoHide(false), _scrollBarOpacity(1.0f), _scrolling(false),
+      _scrollingVeryFirstX(0), _scrollingVeryFirstY(0), _scrollingFirstX(0), _scrollingFirstY(0), _scrollingLastX(0), _scrollingLastY(0),
+      _scrollingStartTimeX(0), _scrollingStartTimeY(0), _scrollingLastTime(0),
+      _scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f), _scrollWheelSpeed(400.0f),
+      _scrollingRight(false), _scrollingDown(false),
+      _scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
+      _scrollBarOpacityClip(NULL), _zIndexDefault(0),
+      _selectButtonDown(false), _lastFrameTime(0), _totalWidth(0), _totalHeight(0),
+      _initializedWithScroll(false), _scrollWheelRequiresFocus(false), _allowRelayout(true)
+{
+	clearContacts();
+}
+
+Container::~Container()
+{
+    std::vector<Control*>::iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        SAFE_RELEASE((*it));
+    }
+    SAFE_RELEASE(_layout);
+}
+
+Container* Container::create(const char* id, Theme::Style* style, Layout::Type layoutType)
+{
+    GP_ASSERT(style);
+
+    Container* container = new Container();
+    container->_layout = createLayout(layoutType);
+    if (id)
+        container->_id = id;
+    container->_style = style;
+    return container;
+}
+
+Control* Container::create(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Container* container = new Container();
+    container->initialize(style, properties);
+    return container;
+}
+
+void Container::initialize(Theme::Style* style, Properties* properties)
+{
+    Control::initialize(style, properties);
+
+    // Parse layout
+    Properties* layoutNS = properties->getNamespace("layout", true, false);
+    if (layoutNS)
+    {
+        _layout = createLayout(getLayoutType(layoutNS->getString("type")));
+        switch (_layout->getType())
+        {
+        case Layout::LAYOUT_FLOW:
+            static_cast<FlowLayout*>(_layout)->setSpacing(layoutNS->getInt("horizontalSpacing"), layoutNS->getInt("verticalSpacing"));
+            break;
+        case Layout::LAYOUT_VERTICAL:
+            static_cast<VerticalLayout*>(_layout)->setSpacing(layoutNS->getInt("spacing"));
+            break;
+        }
+    }
+    else
+    {
+        _layout = createLayout(getLayoutType(properties->getString("layout")));
+    }
+
+    setScroll(getScroll(properties->getString("scroll")));
+    _scrollBarsAutoHide = properties->getBool("scrollBarsAutoHide");
+    if (_scrollBarsAutoHide)
+    {
+        _scrollBarOpacity = 0.0f;
+    }
+    
+    _scrollWheelRequiresFocus = properties->getBool("scrollWheelRequiresFocus");
+    if (properties->exists("scrollingFriction"))
+        _scrollingFriction = properties->getFloat("scrollingFriction");
+    if (properties->exists("scrollWheelSpeed"))
+        _scrollWheelSpeed = properties->getFloat("scrollWheelSpeed");
+
+    addControls(style->getTheme(), properties);
+    _layout->update(this, _scrollPosition);
+
+    const char* activeControl = properties->getString("activeControl");
+    if (activeControl)
+    {
+        for (size_t i = 0, count = _controls.size(); i < count; ++i)
+        {
+            if (_controls[i]->_id == activeControl)
+            {
+                _activeControl = _controls[i];
+                break;
+            }
+        }
+    }
+}
+
+void Container::addControls(Theme* theme, Properties* properties)
+{
+    GP_ASSERT(theme);
+    GP_ASSERT(properties);
+
+    // Add all the controls to this container.
+    Properties* controlSpace = properties->getNextNamespace();
+    while (controlSpace != NULL)
+    {
+        Control* control = NULL;
+
+        const char* controlStyleName = controlSpace->getString("style");
+        Theme::Style* controlStyle = NULL;
+        if (controlStyleName)
+        {
+            controlStyle = theme->getStyle(controlStyleName);
+        }
+        else
+        {
+            controlStyle = theme->getEmptyStyle();
+        }
+
+        std::string controlName(controlSpace->getNamespace());
+        std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);
+
+        control = ControlFactory::getInstance()->createControl(controlName.c_str(), controlStyle, controlSpace);
+
+        // Add the new control to the form.
+        if (control)
+        {
+            addControl(control);
+            control->release();
+        }
+
+        // Get the next control.
+        controlSpace = properties->getNextNamespace();
+    }
+
+    // Sort controls by Z-Order.
+    sortControls();
+}
+
+Layout* Container::getLayout()
+{
+    return _layout;
+}
+
+unsigned int Container::addControl(Control* control)
+{
+    GP_ASSERT(control);
+
+    // Remove the control from its current parent
+    if (control->_parent && control->_parent != this)
+    {
+        control->_parent->removeControl(control);
+    }
+
+    if (control->getZIndex() == -1)
+    {
+        control->setZIndex(_zIndexDefault++);
+    }
+
+    if (control->getFocusIndex() == -1)
+    {
+        // Find the current largest focus index
+        int maxFocusIndex = 0;
+        for (size_t i = 0, count = _controls.size(); i < count; ++i)
+        {
+            if (_controls[i]->_focusIndex > maxFocusIndex)
+                maxFocusIndex = _controls[i]->_focusIndex;
+        }
+        control->setFocusIndex(maxFocusIndex + 1);
+    }
+
+    if (control->_parent != this)
+    {
+        _controls.push_back(control);
+        control->addRef();
+        control->_parent = this;
+        sortControls();
+        return (unsigned int)(_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 (unsigned int)i;
+            }
+        }
+
+        // Should never reach this.
+        GP_ASSERT(false);
+        return 0;
+    }
+}
+
+void Container::insertControl(Control* control, unsigned int index)
+{
+    GP_ASSERT(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;
+    Control* control = *it;
+    _controls.erase(it);
+    control->_parent = NULL;
+
+    if (_activeControl == control)
+        _activeControl = NULL;
+
+    Form::verifyRemovedControlState(control);
+
+    SAFE_RELEASE(control);
+}
+
+void Container::removeControl(const char* id)
+{
+    GP_ASSERT(id);
+
+    for (size_t i = 0, size = _controls.size(); i < size; ++i)
+    {
+        Control* c = _controls[i];
+        if (strcmp(id, c->getId()) == 0)
+        {
+            removeControl((unsigned int)i);
+            return;
+        }
+    }
+}
+
+void Container::removeControl(Control* control)
+{
+    GP_ASSERT(control);
+
+    for (size_t i = 0, size = _controls.size(); i < size; ++i)
+    {
+        Control* c = _controls[i];
+        if (c == control)
+        {
+            removeControl((unsigned int)i);
+            return;
+        }
+    }
+}
+
+Control* Container::getControl(unsigned int index) const
+{
+    GP_ASSERT(index < _controls.size());
+    return _controls[index];
+}
+
+Control* Container::getControl(const char* id) const
+{
+    GP_ASSERT(id);
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* c = *it;
+        GP_ASSERT(c);
+        if (strcmp(id, c->getId()) == 0)
+        {
+            return c;
+        }
+        else if (c->isContainer())
+        {
+            Control* cc = ((Container*)c)->getControl(id);
+            if (cc)
+            {
+                return cc;
+            }
+        }
+    }
+    return NULL;
+}
+
+unsigned int Container::getControlCount() const
+{
+    return (unsigned int)_controls.size();
+}
+
+const std::vector<Control*>& Container::getControls() const
+{
+    return _controls;
+}
+
+bool Container::isForm() const
+{
+    return false;
+}
+
+void Container::setScroll(Scroll scroll)
+{
+    if (scroll != _scroll)
+    {
+        _scroll = scroll;
+        _dirty = true;
+
+        // Scrollable containers can be focused (to allow scrolling)
+        if (_scroll != SCROLL_NONE)
+            _canFocus = true;
+    }
+}
+
+Container::Scroll Container::getScroll() const
+{
+    return _scroll;
+}
+
+void Container::setScrollBarsAutoHide(bool autoHide)
+{
+    if (autoHide != _scrollBarsAutoHide)
+    {
+        _scrollBarsAutoHide = autoHide;
+        _dirty = true;
+    }
+}
+
+bool Container::isScrollBarsAutoHide() const
+{
+    return _scrollBarsAutoHide;
+}
+
+bool Container::isScrolling() const
+{
+    if (_parent && _parent->isScrolling())
+        return true;
+
+    return (_scrolling &&
+            (abs(_scrollingLastX - _scrollingVeryFirstX) > SCROLL_THRESHOLD ||
+             abs(_scrollingLastY - _scrollingVeryFirstY) > SCROLL_THRESHOLD));
+}
+
+const Vector2& Container::getScrollPosition() const
+{
+    return _scrollPosition;
+}
+
+void Container::setScrollPosition(const Vector2& scrollPosition)
+{
+    _scrollPosition = scrollPosition;
+}
+
+Animation* Container::getAnimation(const char* id) const
+{
+    std::vector<Control*>::const_iterator itr = _controls.begin();
+    std::vector<Control*>::const_iterator end = _controls.end();
+    Control* control = NULL;
+    for (; itr != end; itr++)
+    {
+        control = *itr;
+        GP_ASSERT(control);
+        Animation* animation = control->getAnimation(id);
+        if (animation)
+            return animation;
+
+        if (control->isContainer())
+        {
+            animation = ((Container*)control)->getAnimation(id);
+            if (animation)
+                return animation;
+        }
+    }
+    return NULL;
+}
+
+const char* Container::getType() const
+{
+    return "container";
+}
+
+bool Container::getScrollWheelRequiresFocus() const
+{
+    return _scrollWheelRequiresFocus;
+}
+
+void Container::setScrollWheelRequiresFocus(bool required)
+{
+    _scrollWheelRequiresFocus = required;
+}
+
+bool Container::setFocus()
+{
+    // If this container (or one of its children) already has focus, do nothing
+    if (Form::_focusControl && (Form::_focusControl == this || Form::_focusControl->isChild(this)))
+        return true;
+
+    // First try to set focus to our active control
+    if (_activeControl)
+    {
+        if (_activeControl->setFocus())
+            return true;
+    }
+
+    // Try to set focus to one of our children
+    for (size_t i = 0, count = _controls.size(); i < count; ++i)
+    {
+        if (_controls[i]->setFocus())
+            return true;
+    }
+
+    // Lastly, try to set focus to ourself if none of our children will accept it
+    return Control::setFocus();
+}
+
+Control* Container::getActiveControl() const
+{
+    return _activeControl;
+}
+
+void Container::setActiveControl(Control* control)
+{
+    if (std::find(_controls.begin(), _controls.end(), control) != _controls.end())
+    {
+        _activeControl = control;
+
+        // If a control within this container currently has focus, switch focus to the new active control
+        if (Form::_focusControl && Form::_focusControl != control && Form::_focusControl->isChild(this))
+            Form::setFocusControl(control);
+    }
+}
+
+void Container::update(const Control* container, const Vector2& offset)
+{
+    // Update this container's viewport.
+    Control::update(container, offset);
+
+    Control::State state = getState();
+
+    // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
+    if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
+    {
+        _scrollBarLeftCap = getImage("scrollBarLeftCap", state);
+        _scrollBarHorizontal = getImage("horizontalScrollBar", state);
+        _scrollBarRightCap = getImage("scrollBarRightCap", state);
+
+        GP_ASSERT(_scrollBarLeftCap && _scrollBarHorizontal && _scrollBarRightCap);
+
+        _viewportBounds.height -= _scrollBarHorizontal->getRegion().height;
+        _viewportClipBounds.height -= _scrollBarHorizontal->getRegion().height;
+    }
+
+    if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
+    {
+        _scrollBarTopCap = getImage("scrollBarTopCap", state);
+        _scrollBarVertical = getImage("verticalScrollBar", state);
+        _scrollBarBottomCap = getImage("scrollBarBottomCap", state);
+
+        GP_ASSERT(_scrollBarTopCap && _scrollBarVertical && _scrollBarBottomCap);
+
+        _viewportBounds.width -= _scrollBarVertical->getRegion().width;
+        _viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
+    }
+
+    GP_ASSERT(_layout);
+    if (_scroll != SCROLL_NONE)
+    {
+        updateScroll();
+    }
+    else
+    {
+        _layout->update(this, Vector2::zero());
+    }
+
+    // Handle automatically sizing based on our children
+    if (_autoWidth == Control::AUTO_SIZE_FIT || _autoHeight == Control::AUTO_SIZE_FIT)
+    {
+        Vector2 oldSize(_bounds.width, _bounds.height);
+        bool sizeChanged = false;
+        bool relayout = false;
+
+        if (_autoWidth == Control::AUTO_SIZE_FIT)
+        {
+            // Size ourself to tightly fit the width of our children
+            float width = 0;
+            for (std::vector<Control*>::const_iterator it = _controls.begin(); it < _controls.end(); ++it)
+            {
+                Control* ctrl = *it;
+                if (ctrl->isXPercentage() || ctrl->isWidthPercentage())
+                {
+                    // We (this control's parent) are resizing and our child's layout
+                    // depends on our size, so we need to dirty it
+                    ctrl->_dirty = true;
+                    relayout = _allowRelayout;
+                }
+                else
+                {
+                    float w = ctrl->getX() + ctrl->getWidth();
+                    if (width < w)
+                        width = w;
+                }
+            }
+            width += getBorder(state).left + getBorder(state).right + getPadding().left + getPadding().right;
+            if (width != oldSize.x)
+            {
+                setWidth(width);
+                sizeChanged = true;
+            }
+        }
+
+        if (_autoHeight == Control::AUTO_SIZE_FIT)
+        {
+            // Size ourself to tightly fit the height of our children
+            float height = 0;
+            for (std::vector<Control*>::const_iterator it = _controls.begin(); it < _controls.end(); ++it)
+            {
+                Control* ctrl = *it;
+                if (ctrl->isYPercentage() || ctrl->isHeightPercentage())
+                {
+                    // We (this control's parent) are resizing and our child's layout
+                    // depends on our size, so we need to dirty it
+                    ctrl->_dirty = true;
+                    relayout = _allowRelayout;
+                }
+                else
+                {
+                    float h = ctrl->getY() + ctrl->getHeight();
+                    if (height < h)
+                        height = h;
+                }
+            }
+            height += getBorder(state).top + getBorder(state).bottom + getPadding().top + getPadding().bottom;
+            if (height != oldSize.y)
+            {
+                setHeight(height);
+                sizeChanged = true;
+            }
+        }
+
+        if (sizeChanged && relayout)
+        {
+            // Our size changed and as a result we need to force another layout.
+            // Prevent infinitely recursive layouts by disabling relayout for the next call.
+            _allowRelayout = false;
+            update(container, offset);
+            _allowRelayout = true;
+        }
+    }
+}
+
+void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
+{
+    if (needsClear)
+    {
+        GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
+        float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
+        GL_ASSERT( glScissor(_clearBounds.x, clearY, _clearBounds.width, _clearBounds.height) );
+        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
+        GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
+        needsClear = false;
+        cleared = true;
+    }
+    else if (!cleared)
+    {
+        needsClear = true;
+    }
+
+    if (!_visible)
+    {
+        _dirty = false;
+        return;
+    }
+
+    spriteBatch->start();
+    Control::drawBorder(spriteBatch, clip);
+    spriteBatch->finish();
+
+    std::vector<Control*>::const_iterator it;
+    Rectangle boundsUnion = Rectangle::empty();
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* control = *it;
+        GP_ASSERT(control);
+        if (!needsClear || control->isDirty() || control->_clearBounds.intersects(boundsUnion))
+        {
+            control->draw(spriteBatch, _viewportClipBounds, needsClear, cleared, targetHeight);
+            Rectangle::combine(control->_clearBounds, boundsUnion, &boundsUnion);
+        }
+    }
+
+    if (_scroll != SCROLL_NONE && (_scrollBarOpacity > 0.0f))
+    {
+        // Draw scroll bars.
+        Rectangle clipRegion(_viewportClipBounds);
+
+        spriteBatch->start();
+
+        if (_scrollBarBounds.height > 0 && ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL))
+        {
+            const Rectangle& topRegion = _scrollBarTopCap->getRegion();
+            const Theme::UVs& topUVs = _scrollBarTopCap->getUVs();
+            Vector4 topColor = _scrollBarTopCap->getColor();
+            topColor.w *= _scrollBarOpacity * _opacity;
+
+            const Rectangle& verticalRegion = _scrollBarVertical->getRegion();
+            const Theme::UVs& verticalUVs = _scrollBarVertical->getUVs();
+            Vector4 verticalColor = _scrollBarVertical->getColor();
+            verticalColor.w *= _scrollBarOpacity * _opacity;
+
+            const Rectangle& bottomRegion = _scrollBarBottomCap->getRegion();
+            const Theme::UVs& bottomUVs = _scrollBarBottomCap->getUVs();
+            Vector4 bottomColor = _scrollBarBottomCap->getColor();
+            bottomColor.w *= _scrollBarOpacity * _opacity;
+
+            clipRegion.width += verticalRegion.width;
+
+            Rectangle bounds(_viewportBounds.x + _viewportBounds.width, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
+            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
+
+            bounds.y += topRegion.height;
+            bounds.height = _scrollBarBounds.height - topRegion.height - bottomRegion.height;
+            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, verticalUVs.u1, verticalUVs.v1, verticalUVs.u2, verticalUVs.v2, verticalColor, clipRegion);
+
+            bounds.y += bounds.height;
+            bounds.height = bottomRegion.height;
+            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, bottomUVs.u1, bottomUVs.v1, bottomUVs.u2, bottomUVs.v2, bottomColor, clipRegion);
+        }
+
+        if (_scrollBarBounds.width > 0 && ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL))
+        {
+            const Rectangle& leftRegion = _scrollBarLeftCap->getRegion();
+            const Theme::UVs& leftUVs = _scrollBarLeftCap->getUVs();
+            Vector4 leftColor = _scrollBarLeftCap->getColor();
+            leftColor.w *= _scrollBarOpacity * _opacity;
+
+            const Rectangle& horizontalRegion = _scrollBarHorizontal->getRegion();
+            const Theme::UVs& horizontalUVs = _scrollBarHorizontal->getUVs();
+            Vector4 horizontalColor = _scrollBarHorizontal->getColor();
+            horizontalColor.w *= _scrollBarOpacity * _opacity;
+
+            const Rectangle& rightRegion = _scrollBarRightCap->getRegion();
+            const Theme::UVs& rightUVs = _scrollBarRightCap->getUVs();
+            Vector4 rightColor = _scrollBarRightCap->getColor();
+            rightColor.w *= _scrollBarOpacity * _opacity;
+
+            clipRegion.height += horizontalRegion.height;
+        
+            Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.y + _viewportBounds.height, leftRegion.width, leftRegion.height);
+            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
+
+            bounds.x += leftRegion.width;
+            bounds.width = _scrollBarBounds.width - leftRegion.width - rightRegion.width;
+            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, horizontalUVs.u1, horizontalUVs.v1, horizontalUVs.u2, horizontalUVs.v2, horizontalColor, clipRegion);
+
+            bounds.x += bounds.width;
+            bounds.width = rightRegion.width;
+            spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, rightUVs.u1, rightUVs.v1, rightUVs.u2, rightUVs.v2, rightColor, clipRegion);
+        }
+
+        spriteBatch->finish();
+
+        if (_scrollingVelocity.isZero())
+        {
+            _dirty = false;
+        }
+    }
+    else
+    {
+        _dirty = false;
+    }
+}
+
+bool Container::isDirty()
+{
+    if (_dirty)
+    {
+        return true;
+    }
+    else
+    {
+        std::vector<Control*>::const_iterator it;
+        for (it = _controls.begin(); it < _controls.end(); it++)
+        {
+            GP_ASSERT(*it);
+            if ((*it)->isDirty())
+            {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+static bool canReceiveFocus(Control* control)
+{
+    if (control->getFocusIndex() < 0 || !(control->isEnabled() && control->isVisible()))
+        return false;
+
+    if (control->canFocus())
+        return true;
+
+    if (control->isContainer())
+    {
+        Container* container = static_cast<Container*>(control);
+        for (unsigned int i = 0, count = (unsigned int)container->getControlCount(); i < count; ++i)
+        {
+            if (canReceiveFocus(container->getControl(i)))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+bool Container::moveFocus(Direction direction)
+{
+	switch (direction)
+	{
+	case NEXT:
+	case PREVIOUS:
+		return moveFocusNextPrevious(direction);
+
+	case UP:
+	case DOWN:
+	case LEFT:
+	case RIGHT:
+		return moveFocusDirectional(direction);
+
+	default:
+		return false;
+	}
+}
+
+bool Container::moveFocusNextPrevious(Direction direction)
+{
+    // Get the current control that has focus (either directly or indirectly) within this container
+    Control* current = NULL;
+    if (Form::_focusControl && Form::_focusControl->isChild(this))
+    {
+        if (Form::_focusControl->_parent == this)
+        {
+            // Currently focused control is a direct child of us
+            current = Form::_focusControl;
+        }
+        else
+        {
+            // Currently focused control is a child of one of our child containers
+            for (size_t i = 0, count = _controls.size(); i < count; ++i)
+            {
+                if (Form::_focusControl->isChild(_controls[i]))
+                {
+                    current = _controls[i];
+                    break;
+                }
+            }
+        }
+    }
+
+    Control* nextCtrl = NULL;
+    int nextIndex = direction == NEXT ? INT_MAX : INT_MIN;
+    bool moveFirst = false;
+
+    if (current)
+    {
+        // There is a control inside us that currently has focus, so find the next control that
+        // should receive focus.
+        int focusableControlCount = 0; // track the number of valid focusable controls in this container
+
+        for (size_t i = 0, count = _controls.size(); i < count; ++i)
+        {
+            Control* ctrl = _controls[i];
+            if (!canReceiveFocus(ctrl))
+                continue;
+
+            if ((direction == NEXT && ctrl->_focusIndex > current->_focusIndex && ctrl->_focusIndex < nextIndex) ||
+                (direction == PREVIOUS && ctrl->_focusIndex < current->_focusIndex && ctrl->_focusIndex > nextIndex))
+            {
+                nextCtrl = ctrl;
+                nextIndex = ctrl->_focusIndex;
+            }
+
+            ++focusableControlCount;
+        }
+
+        if (nextCtrl)
+        {
+            if (nextCtrl->isContainer() && static_cast<Container*>(nextCtrl)->moveFocus(direction))
+                return true;
+            if (nextCtrl->setFocus())
+                return true;
+        }
+
+        // Search up into our parent container for a focus move
+        if (_parent && _parent->moveFocus(direction))
+            return true;
+
+        // We didn't find a control to move to, so we must be the first or last focusable control in our parent.
+        // Wrap focus to the other side of the container.
+        if (focusableControlCount > 1)
+        {
+            moveFirst = true;
+        }
+    }
+    else
+    {
+        moveFirst = true;
+    }
+
+    if (moveFirst)
+    {
+        nextIndex = direction == NEXT ? INT_MAX : INT_MIN;
+        nextCtrl = NULL;
+        for (size_t i = 0, count = _controls.size(); i < count; ++i)
+        {
+            Control* ctrl = _controls[i];
+            if (!canReceiveFocus(ctrl))
+                continue;
+            if ((direction == NEXT && ctrl->_focusIndex < nextIndex) ||
+                (direction == PREVIOUS && ctrl->_focusIndex > nextIndex))
+            {
+                nextCtrl = ctrl;
+                nextIndex = ctrl->_focusIndex;
+            }
+        }
+
+        if (nextCtrl)
+        {
+            if (nextCtrl->isContainer() && static_cast<Container*>(nextCtrl)->moveFocus(direction))
+                return true;
+            if (nextCtrl->setFocus())
+                return true;
+        }
+    }
+
+    return false;
+}
+
+bool Container::moveFocusDirectional(Direction direction)
+{
+	Control* startControl = Form::_focusControl;
+	if (startControl == NULL)
+		return false;
+
+	const Rectangle& startBounds = startControl->_absoluteBounds;
+
+	Control* next = NULL;
+	Vector2 vStart, vNext;
+	float distance = FLT_MAX;
+
+	switch (direction)
+	{
+	case UP:
+		vStart.set(startBounds.x + startBounds.width * 0.5f, startBounds.y);
+		break;
+	case DOWN:
+		vStart.set(startBounds.x + startBounds.width * 0.5f, startBounds.bottom());
+		break;
+	case LEFT:
+		vStart.set(startBounds.x, startBounds.y + startBounds.height * 0.5f);
+		break;
+	case RIGHT:
+		vStart.set(startBounds.right(), startBounds.y + startBounds.height * 0.5f);
+		break;
+	}
+
+	for (size_t i = 0, count = _controls.size(); i < count; ++i)
+	{
+		Control* ctrl = _controls[i];
+		if (!canReceiveFocus(ctrl))
+			continue;
+
+		const Rectangle& nextBounds = ctrl->getAbsoluteBounds();
+		switch (direction)
+		{
+		case UP:
+			vNext.set(nextBounds.x + nextBounds.width * 0.5f, nextBounds.bottom());
+			if (vNext.y > vStart.y)
+				continue;
+			break;
+		case DOWN:
+			vNext.set(nextBounds.x + nextBounds.width * 0.5f, nextBounds.y);
+			if (vNext.y < vStart.y)
+				continue;
+			break;
+		case LEFT:
+			vNext.set(nextBounds.right(), nextBounds.y + nextBounds.height * 0.5f);
+			if (vNext.x > vStart.x)
+				continue;
+			break;
+		case RIGHT:
+			vNext.set(nextBounds.x, nextBounds.y + nextBounds.height * 0.5f);
+			if (vNext.x < vStart.x)
+				continue;
+			break;
+		}
+
+		float nextDistance = vStart.distance(vNext);
+		if (std::fabs(nextDistance) < distance)
+		{
+			distance = nextDistance;
+			next = ctrl;
+		}
+	}
+
+	if (next)
+	{
+		// If this control is a container, try to move focus to the first control within it
+		if (next->isContainer())
+		{
+			if (static_cast<Container*>(next)->moveFocusDirectional(direction))
+				return true;
+		}
+
+		if (next->setFocus())
+			return true;
+	}
+	else
+	{
+		// If no control was found, try searching in our parent container
+		if (_parent && _parent->moveFocusDirectional(direction))
+			return true;
+	}
+
+    return false;
+}
+
+void Container::startScrolling(float x, float y, bool resetTime)
+{
+    _scrollingVelocity.set(-x, y);
+    _scrolling = true;
+    _scrollBarOpacity = 1.0f;
+    _dirty = true;
+
+    if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
+    {
+        _scrollBarOpacityClip->stop();
+        _scrollBarOpacityClip = NULL;
+    }
+
+    if (resetTime)
+    {
+        _lastFrameTime = Game::getAbsoluteTime();
+    }
+}
+
+void Container::stopScrolling()
+{
+    _scrollingVelocity.set(0, 0);
+    _scrolling = false;
+    _dirty = true;
+}
+
+bool Container::isContainer() const
+{
+    return true;
+}
+
+Layout::Type Container::getLayoutType(const char* layoutString)
+{
+    if (!layoutString)
+    {
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+
+    std::string layoutName(layoutString);
+    std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
+    if (layoutName == "LAYOUT_ABSOLUTE")
+    {
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+    else if (layoutName == "LAYOUT_VERTICAL")
+    {
+        return Layout::LAYOUT_VERTICAL;
+    }
+    else if (layoutName == "LAYOUT_FLOW")
+    {
+        return Layout::LAYOUT_FLOW;
+    }
+    else
+    {
+        // Default.
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+}
+
+Layout* Container::createLayout(Layout::Type type)
+{
+    switch (type)
+    {
+    case Layout::LAYOUT_ABSOLUTE:
+        return AbsoluteLayout::create();
+    case Layout::LAYOUT_FLOW:
+        return FlowLayout::create();
+    case Layout::LAYOUT_VERTICAL:
+        return VerticalLayout::create();
+    default:
+        return AbsoluteLayout::create();
+    }
+}
+
+void Container::updateScroll()
+{
+    if (!_initializedWithScroll)
+    {
+        _initializedWithScroll = true;
+        _layout->update(this, _scrollPosition);
+    }
+
+    Control::State state = getState();
+
+    // Update time.
+    if (!_lastFrameTime)
+    {
+        _lastFrameTime = Game::getAbsoluteTime();
+    }
+    double frameTime = Game::getAbsoluteTime();
+    float elapsedTime = (float)(frameTime - _lastFrameTime);
+    _lastFrameTime = frameTime;
+
+    const Theme::Border& containerBorder = getBorder(state);
+    const Theme::Padding& containerPadding = getPadding();
+
+    // Calculate total width and height.
+    _totalWidth = _totalHeight = 0.0f;
+    std::vector<Control*> controls = getControls();
+    for (size_t i = 0, controlsCount = controls.size(); i < controlsCount; i++)
+    {
+        Control* control = controls.at(i);
+
+        const Rectangle& bounds = control->getBounds();
+        const Theme::Margin& margin = control->getMargin();
+
+        float newWidth = bounds.x + bounds.width + margin.right;
+        if (newWidth > _totalWidth)
+        {
+            _totalWidth = newWidth;
+        }
+
+        float newHeight = bounds.y + bounds.height + margin.bottom;
+        if (newHeight > _totalHeight)
+        {
+            _totalHeight = newHeight;
+        }
+    }
+
+    float vWidth = getImageRegion("verticalScrollBar", state).width;
+    float hHeight = getImageRegion("horizontalScrollBar", state).height;
+    float clipWidth = _absoluteBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right - vWidth;
+    float clipHeight = _absoluteBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
+
+    // Apply and dampen inertia.
+    if (!_scrollingVelocity.isZero())
+    {
+        // Calculate the time passed since last update.
+        float elapsedSecs = (float)elapsedTime * 0.001f;
+
+        _scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
+        _scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
+
+        if (!_scrolling)
+        {
+            float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
+            _scrollingVelocity.x *= dampening;
+            _scrollingVelocity.y *= dampening;
+
+            if (fabs(_scrollingVelocity.x) < 100.0f)
+                _scrollingVelocity.x = 0.0f;
+            if (fabs(_scrollingVelocity.y) < 100.0f)
+                _scrollingVelocity.y = 0.0f;
+        }
+    }
+
+    // Stop scrolling when the far edge is reached.
+    if (-_scrollPosition.x > _totalWidth - clipWidth)
+    {
+        _scrollPosition.x = -(_totalWidth - clipWidth);
+        _scrollingVelocity.x = 0;
+    }
+    
+    if (-_scrollPosition.y > _totalHeight - clipHeight)
+    {
+        _scrollPosition.y = -(_totalHeight - clipHeight);
+        _scrollingVelocity.y = 0;
+    }
+
+    if (_scrollPosition.x > 0)
+    {
+        _scrollPosition.x = 0;
+        _scrollingVelocity.x = 0;
+    }
+
+    if (_scrollPosition.y > 0)
+    {
+        _scrollPosition.y = 0;
+        _scrollingVelocity.y = 0;
+    }
+
+    float scrollWidth = 0;
+    if (clipWidth < _totalWidth)
+        scrollWidth = (clipWidth / _totalWidth) * clipWidth;
+
+    float scrollHeight = 0;
+    if (clipHeight < _totalHeight)
+        scrollHeight = (clipHeight / _totalHeight) * clipHeight;
+
+    _scrollBarBounds.set(((-_scrollPosition.x) / _totalWidth) * clipWidth,
+                         ((-_scrollPosition.y) / _totalHeight) * clipHeight,
+                         scrollWidth, scrollHeight);
+
+    // If scroll velocity is 0 and scrollbars are not always visible, trigger fade-out animation.
+    if (!_scrolling && _scrollingVelocity.isZero() && _scrollBarsAutoHide && _scrollBarOpacity == 1.0f)
+    {
+        float to = 0;
+        _scrollBarOpacity = 0.99f;
+        if (!_scrollBarOpacityClip)
+        {
+            Animation* animation = createAnimationFromTo("scrollbar-fade-out", ANIMATE_SCROLLBAR_OPACITY, &_scrollBarOpacity, &to, Curve::QUADRATIC_IN_OUT, 500L);
+            _scrollBarOpacityClip = animation->getClip();
+        }
+        _scrollBarOpacityClip->play();
+    }
+
+    // Position controls within scroll area.
+    _layout->update(this, _scrollPosition);
+}
+
+void Container::sortControls()
+{
+    if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
+    {
+        std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
+    }
+}
+
+bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    switch (evt)
+    {
+    case Touch::TOUCH_PRESS:
+        if (_contactIndex == INVALID_CONTACT_INDEX)
+        {
+            _contactIndex = (int) contactIndex;
+            _scrollingLastX = _scrollingFirstX = _scrollingVeryFirstX = x;
+            _scrollingLastY = _scrollingFirstY = _scrollingVeryFirstY = y;
+            _scrollingVelocity.set(0, 0);
+            _scrolling = true;
+            _scrollingStartTimeX = _scrollingStartTimeY = 0;
+
+            if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
+            {
+                _scrollBarOpacityClip->stop();
+                _scrollBarOpacityClip = NULL;
+            }
+            _scrollBarOpacity = 1.0f;
+            _dirty = true;
+            return false;
+        }
+        break;
+
+    case Touch::TOUCH_MOVE:
+        if (_scrolling && _contactIndex == (int) contactIndex)
+        {
+            double gameTime = Game::getAbsoluteTime();
+
+            // Calculate the latest movement delta for the next update to use.
+            int vx = x - _scrollingLastX;
+            int vy = y - _scrollingLastY;
+            if (_scrollingMouseVertically)
+            {
+                float yRatio = _totalHeight / _absoluteBounds.height;
+                vy *= yRatio;
+
+                _scrollingVelocity.set(0, -vy);
+                _scrollPosition.y -= vy;
+            }
+            else if (_scrollingMouseHorizontally)
+            {
+                float xRatio = _totalWidth / _absoluteBounds.width;
+                vx *= xRatio;
+
+                _scrollingVelocity.set(-vx, 0);
+                _scrollPosition.x -= vx;
+            }
+            else
+            {
+                _scrollingVelocity.set(vx, vy);
+                _scrollPosition.x += vx;
+                _scrollPosition.y += vy;
+            }
+
+            _scrollingLastX = x;
+            _scrollingLastY = y;
+
+            // If the user changes direction, reset the start time and position.
+            bool goingRight = (vx > 0);
+            if (goingRight != _scrollingRight)
+            {
+                _scrollingFirstX = x;
+                _scrollingRight = goingRight;
+                _scrollingStartTimeX = gameTime;
+            }
+
+            bool goingDown = (vy > 0);
+            if (goingDown != _scrollingDown)
+            {
+                _scrollingFirstY = y;
+                _scrollingDown = goingDown;
+                _scrollingStartTimeY = gameTime;
+            }
+
+            if (!_scrollingStartTimeX)
+                _scrollingStartTimeX = gameTime;
+
+            if (!_scrollingStartTimeY)
+                _scrollingStartTimeY = gameTime;
+
+            _scrollingLastTime = gameTime;
+            _dirty = true;
+            return _consumeInputEvents;
+        }
+        break;
+
+    case Touch::TOUCH_RELEASE:
+        if (_contactIndex == (int) contactIndex)
+        {
+            _contactIndex = INVALID_CONTACT_INDEX;
+            _scrolling = false;
+            double gameTime = Game::getAbsoluteTime();
+            float timeSinceLastMove = (float)(gameTime - _scrollingLastTime);
+            if (timeSinceLastMove > SCROLL_INERTIA_DELAY)
+            {
+                _scrollingVelocity.set(0, 0);
+                _scrollingMouseVertically = _scrollingMouseHorizontally = false;
+                _dirty = true;
+                return _consumeInputEvents;
+            }
+
+            int dx = _scrollingLastX - _scrollingFirstX;
+            int dy = _scrollingLastY - _scrollingFirstY;
+
+            float timeTakenX = (float)(gameTime - _scrollingStartTimeX);
+            float elapsedSecsX = timeTakenX * 0.001f;
+            float timeTakenY = (float)(gameTime - _scrollingStartTimeY);
+            float elapsedSecsY = timeTakenY * 0.001f;
+
+            float vx = dx;
+            float vy = dy;
+            if (elapsedSecsX > 0)
+                vx = (float)dx / elapsedSecsX;
+            if (elapsedSecsY > 0)
+                vy = (float)dy / elapsedSecsY;
+
+            if (_scrollingMouseVertically)
+            {
+                float yRatio = _totalHeight / _absoluteBounds.height;
+                vy *= yRatio;
+                _scrollingVelocity.set(0, -vy);
+            }
+            else if (_scrollingMouseHorizontally)
+            {
+                float xRatio = _totalWidth / _absoluteBounds.width;
+                vx *= xRatio;
+                _scrollingVelocity.set(-vx, 0);
+            }
+            else
+            {
+                _scrollingVelocity.set(vx, vy);
+            }
+
+            _scrollingMouseVertically = _scrollingMouseHorizontally = false;
+            _dirty = true;
+            return _consumeInputEvents;
+        }
+        break;
+    }
+
+    return false;
+}
+
+bool Container::mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+{
+    switch (evt)
+    {
+        case Mouse::MOUSE_PRESS_LEFT_BUTTON:
+        {
+            if (_scrollBarVertical)
+            {
+                float vWidth = _scrollBarVertical->getRegion().width;
+                Rectangle vBounds(_viewportBounds.x + _viewportBounds.width,
+                                 _scrollBarBounds.y,
+                                 vWidth, _scrollBarBounds.height);
+
+                if (x >= vBounds.x &&
+                    x <= vBounds.x + vBounds.width)
+                {
+                    // Then we're within the horizontal bounds of the vertical scrollbar.
+                    // We want to either jump up or down, or drag the scrollbar itself.
+                    if (y < vBounds.y)
+                    {
+                        _scrollPosition.y += _totalHeight / 5.0f;
+                    }
+                    else if (y > vBounds.y + vBounds.height)
+                    {
+                        _scrollPosition.y -= _totalHeight / 5.0f;
+                    }
+                    else
+                    {
+                        _scrollingMouseVertically = true;
+                    }
+                }
+            }
+
+            if (_scrollBarHorizontal)
+            {
+                float hHeight = _scrollBarHorizontal->getRegion().height;
+                Rectangle hBounds(_scrollBarBounds.x,
+                                  _viewportBounds.y + _viewportBounds.height,
+                                  _scrollBarBounds.width, hHeight);
+
+                if (y >= hBounds.y &&
+                    y <= hBounds.y + hBounds.height)
+                {
+                    // We're within the vertical bounds of the horizontal scrollbar.
+                    if (x < hBounds.x)
+                        _scrollPosition.x += _totalWidth / 5.0f;
+                    else if (x > hBounds.x + hBounds.width)
+                        _scrollPosition.x -= _totalWidth / 5.0f;
+                    else
+                        _scrollingMouseHorizontally = true;
+                }
+            }
+
+            return touchEventScroll(Touch::TOUCH_PRESS, x, y, 0);
+        }
+
+        case Mouse::MOUSE_MOVE:
+            return touchEventScroll(Touch::TOUCH_MOVE, x, y, 0);
+
+        case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
+            return touchEventScroll(Touch::TOUCH_RELEASE, x, y, 0);
+
+        case Mouse::MOUSE_WHEEL:
+        {
+            if (_scrollingVelocity.isZero())
+            {
+                _lastFrameTime = Game::getAbsoluteTime();
+            }
+            _scrolling = _scrollingMouseVertically = _scrollingMouseHorizontally = false;
+
+            _scrollingVelocity.y += _scrollWheelSpeed * wheelDelta;
+
+            if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
+            {
+                _scrollBarOpacityClip->stop();
+                _scrollBarOpacityClip = NULL;
+            }
+            _scrollBarOpacity = 1.0f;
+            _dirty = true;
+            return _consumeInputEvents;
+        }
+    }
+
+    return false;
+}
+
+bool Container::inContact()
+{
+	for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
+	{
+		if (_contactIndices[i])
+			return true;
+	}
+	return false;
+}
+
+Container::Scroll Container::getScroll(const char* scroll)
+{
+    if (!scroll)
+        return Container::SCROLL_NONE;
+
+    if (strcmp(scroll, "SCROLL_NONE") == 0)
+    {
+        return Container::SCROLL_NONE;
+    }
+    else if (strcmp(scroll, "SCROLL_HORIZONTAL") == 0)
+    {
+        return Container::SCROLL_HORIZONTAL;
+    }
+    else if (strcmp(scroll, "SCROLL_VERTICAL") == 0)
+    {
+        return Container::SCROLL_VERTICAL;
+    }
+    else if (strcmp(scroll, "SCROLL_BOTH") == 0)
+    {
+        return Container::SCROLL_BOTH;
+    }
+    else
+    {
+        GP_ERROR("Failed to get corresponding scroll state for unsupported value '%s'.", scroll);
+    }
+
+    return Container::SCROLL_NONE;
+}
+
+float Container::getScrollingFriction() const
+{
+    return _scrollingFriction;
+}
+
+void Container::setScrollingFriction(float friction)
+{
+    _scrollingFriction = friction;
+}
+
+float Container::getScrollWheelSpeed() const
+{
+    return _scrollWheelSpeed;
+}
+
+void Container::setScrollWheelSpeed(float speed)
+{
+    _scrollWheelSpeed = speed;
+}
+
+static bool sortControlsByZOrder(Control* c1, Control* c2)
+{
+    if (c1->getZIndex() < c2->getZIndex())
+        return true;
+
+    return false;
+}
+
+unsigned int Container::getAnimationPropertyComponentCount(int propertyId) const
+{
+    switch(propertyId)
+    {
+    case ANIMATE_SCROLLBAR_OPACITY:
+        return 1;
+    default:
+        return Control::getAnimationPropertyComponentCount(propertyId);
+    }
+}
+
+void Container::getAnimationPropertyValue(int propertyId, AnimationValue* value)
+{
+    GP_ASSERT(value);
+
+    switch(propertyId)
+    {
+    case ANIMATE_SCROLLBAR_OPACITY:
+        value->setFloat(0, _scrollBarOpacity);
+        break;
+    default:
+        Control::getAnimationPropertyValue(propertyId, value);
+        break;
+    }
+}
+
+void Container::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
+{
+    GP_ASSERT(value);
+
+    switch(propertyId)
+    {
+    case ANIMATE_SCROLLBAR_OPACITY:
+        _scrollBarOpacity = Curve::lerp(blendWeight, _opacity, value->getFloat(0));
+        _dirty = true;
+        break;
+    default:
+        Control::setAnimationPropertyValue(propertyId, value, blendWeight);
+        break;
+    }
+}
+
+}

+ 609 - 640
gameplay/src/Container.h

@@ -1,640 +1,609 @@
-#ifndef CONTAINER_H_
-#define CONTAINER_H_
-
-#include "Control.h"
-#include "Layout.h"
-#include "TimeListener.h"
-
-namespace gameplay
-{
-
-/**
- * A container is a UI control that can contain other controls.
- *
- * The following properties are available for containers:
-
- @verbatim
-    container <containerID>
-    {
-         // Container properties.
-         layout   = <Layout::Type>        // A value from the Layout::Type enum.  E.g.: LAYOUT_VERTICAL
-         style    = <styleID>           // A style from the form's theme.
-         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
-         position    = <x, y>    // Position of the container on-screen, measured in pixels.
-         autoWidth   = <bool>
-         autoHeight  = <bool>
-         size        = <width, height>   // Size of the container, measured in pixels.
-         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
-         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
-         scroll      = <Container::Scroll constant> // Whether scrolling is allowed and in which directions.
-         scrollBarsAutoHide = <bool>        // Whether scrollbars fade out when not in use.
-         scrollingFriction = <float>        // Friction applied to inertial scrolling.
-         scrollWheelRequiresFocus = <bool>  // Whether focus or hover state handles scroll-wheel events.
-         scrollWheelSpeed = <float>         // Speed to scroll at on a scroll-wheel event.
-         consumeEvents = <bool>             // Whether the container propagates input events to the Game's input event handler. Default is true.
-
-         // All the nested controls within this container.
-         container 
-         { 
-             ...
-         }
-
-         label { }
-         textBox { }
-         button { }
-         checkBox { }
-         radioButton { }
-         slider { }
-    }
- @endverbatim
- */
-class Container : public Control, TimeListener
-{
-	friend class ControlFactory;
-
-public:
-
-    /**
-     * Constant used to auto-hide scrollbars.
-     */
-    static const int ANIMATE_SCROLLBAR_OPACITY = 8;
-
-    /**
-     * The definition for container scrolling.
-     */
-    enum Scroll
-    {
-        SCROLL_NONE        = 0,
-        SCROLL_HORIZONTAL  = 0x01,
-        SCROLL_VERTICAL    = 0x02,
-        SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL
-    };
-
-    /**
-     * Create a new container.
-     *
-     * @param id The container's ID.
-     * @param style The container's style.
-     * @param layoutType The container's layout type.
-     *
-     * @return The new container.
-     * @script{create}
-     */
-    static Container* create(const char* id, Theme::Style* style, Layout::Type layoutType = Layout::LAYOUT_ABSOLUTE);
-
-    /**
-     * Get this container's layout.
-     *
-     * @return This container's layout object.
-     */
-    Layout* getLayout();
-
-    /**
-     * Add a control to this layout.
-     * The control will be assigned the next available index.
-     *
-     * @param control The Control to add.
-     *
-     * @return The index assigned to the added Control.
-     */
-    unsigned int addControl(Control* control);
-
-    /**
-     * Insert a control at a specific index.
-     *
-     * @param control The control to add.
-     * @param index The index at which to insert the control.
-     */
-    void insertControl(Control* control, unsigned int index);
-
-    /**
-     * Remove a control at a specific index.
-     *
-     * @param index The index from which to remove the control.
-     */
-    void removeControl(unsigned int index);
-
-    /**
-     * Remove a control with the given ID.
-     *
-     * @param id The ID of the control to remove.
-     */
-    void removeControl(const char* id);
-
-    /**
-     * Remove a specific control.
-     *
-     * @param control The control to remove.
-     */
-    void removeControl(Control* control);
-
-    /**
-     * Get the Control at a specific index.
-     *
-     * @param index The index at which to retrieve the Control.
-     *
-     * @return The Control at the given index.
-     */
-    Control* getControl(unsigned int index) const;
-
-    /**
-     * Get a Control with a specific ID that belongs to this Layout.
-     *
-     * @param id The ID of the Control to search for.
-     */
-    Control* getControl(const char* id) const;
-
-    /**
-     * Get the vector of controls within this container.
-     *
-     * @return The vector of the controls within this container.
-     * @script{ignore}
-     */
-    const std::vector<Control*>& getControls() const;
-
-    /**
-     * Sets the allowed scroll directions for this container.
-     *
-     * @param scroll The allowed scroll directions for this container.
-     */
-    void setScroll(Scroll scroll);
-
-    /**
-     * Gets the allowed scroll directions for this container.
-     *
-     * @return The allowed scroll directions for this container.
-     */
-    Scroll getScroll() const;
-
-    /**
-     * Set whether scrollbars auto hidden when they become static.
-     *
-     * @param autoHide true to auto hide the scrollbars when they become static.
-     */
-    void setScrollBarsAutoHide(bool autoHide);
-
-    /**
-     * Whether scrollbars are always visible, or only visible while scrolling.
-     *
-     * @return Whether scrollbars are always visible.
-     */
-    bool isScrollBarsAutoHide() const;
-
-    /**
-     * Whether this container is currently being scrolled.
-     *
-     * @return Whether this container is currently being scrolled.
-     */
-    bool isScrolling() const;
-
-    /**
-     * Get the friction applied to scrolling velocity for this container.
-     */
-    float getScrollingFriction() const;
-
-    /**
-     * Get the friction applied to scrolling velocity for this container.
-     * A higher value will bring the viewport to a stop sooner.
-     */
-    void setScrollingFriction(float friction);
-
-    /**
-     * Get the speed added to scrolling velocity on a scroll-wheel event.
-     */
-    float getScrollWheelSpeed() const;
-
-    /**
-     * Set the speed added to scrolling velocity on a scroll-wheel event.
-     */
-    void setScrollWheelSpeed(float speed);
-
-    /**
-     * Get an offset of how far this layout has been scrolled in each direction.
-     */
-    const Vector2& getScrollPosition() const;
-
-    /**
-     * Set an offset of how far this layout has been scrolled in each direction.
-     */
-    void setScrollPosition(const Vector2& scrollPosition);
-
-    /**
-     * @see AnimationTarget::getAnimation
-     */
-    Animation* getAnimation(const char* id = NULL) const;
-
-    /**
-     * @see Control::isContainer
-     */
-    bool isContainer() const;
-
-    /**
-     * @see Control::getType
-     */
-    const char* getType() const;
-
-    /**
-     * Get whether this container requires focus in order to handle scroll-wheel events.
-     */
-    bool getScrollWheelRequiresFocus() const;
-
-    /**
-     * Set whether this container requires focus in order to handle scroll-wheel events.
-     * If this property is set to true, scroll-wheel events will only be handled when the container has focus.
-     * If this property is set tofalse, scroll-wheel events will only be handled
-     * when the container is in the HOVER state.
-     *
-     * @param required Whether focus is required in order to handle scroll-wheel events.
-     */
-    void setScrollWheelRequiresFocus(bool required);
-
-    /**
-     * @see AnimationTarget::getAnimationPropertyComponentCount
-     */
-    virtual unsigned int getAnimationPropertyComponentCount(int propertyId) const;
-
-    /**
-     * @see AnimationTarget::getAnimationProperty
-     */
-    virtual void getAnimationPropertyValue(int propertyId, AnimationValue* value);
-
-    /**
-     * @see AnimationTarget::setAnimationProperty
-     */
-    virtual void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
-
-    /**
-     * @see TimeListener::timeEvent
-     *
-     * @script{ignore}
-     */
-    void timeEvent(long timeDiff, void* cookie);
-
-protected:
-
-    /**
-     * Constructor.
-     */
-    Container();
-
-    /**
-     * Destructor.
-     */
-    virtual ~Container();
-
-    /**
-     * Create an empty container.  A container's layout type must be specified at creation time.
-     *
-     * @param type The container's layout type.
-     *
-     * @return The new container.
-     */
-    static Container* create(Layout::Type type);
-
-    /**
-     * Create a container with a given style and properties, including a list of controls.
-     *
-     * @param style The style to apply to this container.
-     * @param properties The properties to set on this container, including nested controls.
-     * @param theme The theme to search for control styles within.
-     *
-     * @return The new container.
-     */
-    static Control* create(Theme::Style* style, Properties* properties, Theme* theme);
-
-    /**
-     * Updates each control within this container,
-     * and positions them according to the container's layout.
-     *
-     * @param container This container's parent container.
-     * @param offset The offset.
-     */
-    virtual void update(const Control* container, const Vector2& offset);
-
-    /**
-     * Touch callback on touch events.  Controls return true if they consume the touch event.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by a control within this container.
-     *
-     * @see Touch::TouchEvent
-     */
-    virtual bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-    
-    /**
-     * Keyboard callback on key events.  Passes key events on to the currently focused control.
-     *
-     * @param evt The key event that occurred.
-     * @param key If evt is KEY_PRESS or KEY_RELEASE then key is the key code from Keyboard::Key.
-     *            If evt is KEY_CHAR then key is the unicode value of the character.
-     *
-     * @return Whether the key event was consumed by this control.
-     * 
-     * @see Keyboard::KeyEvent
-     * @see Keyboard::Key
-     */
-    virtual bool keyEvent(Keyboard::KeyEvent evt, int key);
-
-    /**
-     * Mouse callback on mouse events.
-     *
-     * @param evt The mouse event that occurred.
-     * @param x The x position of the mouse in pixels. Left edge is zero.
-     * @param y The y position of the mouse in pixels. Top edge is zero.
-     * @param wheelDelta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
-     *
-     * @return True if the mouse event is consumed or false if it is not consumed.
-     *
-     * @see Mouse::mouseEvent
-     */
-    virtual bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
-
-    /**
-     * Gamepad callback on gamepad events.
-     *
-     * @see Control::gamepadEvent
-     */
-    virtual bool gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
-
-    /**
-     * Gets a Layout::Type enum from a matching string.
-     *
-     * @param layoutString The layout string to parse
-     */
-    static Layout::Type getLayoutType(const char* layoutString);
-    
-    /**
-     * Returns whether this container or any of its controls have been modified and require an update.
-     * 
-     * @return true if this container or any of its controls have been modified and require an update.
-     */
-    virtual bool isDirty();
-
-    /**
-     * Adds controls nested within a properties object to this container,
-     * searching for styles within the given theme.
-     *
-     * @param theme The them to add controls from
-     * @param properties The properties to use.
-     */
-    void addControls(Theme* theme, Properties* properties);
-
-    /**
-     * Draws a sprite batch for the specified clipping rect.
-     *
-     * @param spriteBatch The sprite batch to use.
-     * @param clip The clipping rectangle.
-     * @param needsClear Whether it needs to be cleared.
-     * @param cleared Whether it was previously cleared
-     * @param targetHeight The targets height
-     */
-    virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight);
-
-    /**
-     * Update scroll position and velocity.
-     */
-    void updateScroll();
-
-    /**
-     * Sorts controls by Z-Order (for absolute layouts only).
-     * This method is used by controls to notify their parent container when
-     * their Z-Index changes.
-     */
-    void sortControls();
-
-    /**
-     * Applies touch events to scroll state.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by scrolling within this container.
-     *
-     * @see Touch::TouchEvent
-     */
-    bool touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-
-    /**
-     * Mouse scroll event callback.
-     *
-     * @param evt The mouse scroll event that occurred.
-     * @param x The x position of the scroll in pixels. Left edge is zero.
-     * @param y The y position of the scroll in pixels. Top edge is zero.
-     * @param wheelDelta The value change of the mouse's scroll wheel.
-     *
-     * @return Whether the scroll event was consumed by scrolling within this container.
-     *
-     * @see Mouse::MouseEvent
-     */
-    bool mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
-
-    /**
-     * Mouse pointer event callback.
-     *
-     * @param mouse Whether to treat the event as a mouse event or a touch event.
-     * @param evt The pointer event (either a Mouse::MouseEvent or a Touch::TouchEvent).
-     * @param x The x position of the pointer event in pixels. Left edge is zero.
-     * @param y The y position of the pointer event in pixels. Top edge is zero.
-     * @param data The event's data (depends on whether it is a mouse event or a touch event).
-     *
-     * @return Whether the pointer event was consumed by this container.
-     * 
-     * @see Mouse::MouseEvent
-     * @see Touch::TouchEvent
-     */
-    bool pointerEvent(bool mouse, char evt, int x, int y, int data);
-
-    /**
-     * Get a Scroll enum from a matching string.
-     *
-     * @param scroll A string representing a Scroll enum.
-     *
-     * @return The Scroll enum value that matches the given string.
-     */
-    static Scroll getScroll(const char* scroll);
-
-    /**
-     * The container's layout.
-     */
-    Layout* _layout;
-    /**
-     * List of controls within the container.
-     */
-    std::vector<Control*> _controls;
-    /**
-     * Scrollbar top cap image.
-     */
-    Theme::ThemeImage* _scrollBarTopCap;
-    /**
-     * Scrollbar vertical track image.
-     */
-    Theme::ThemeImage* _scrollBarVertical;
-    /**
-     * Scrollbar bottom cap image.
-     */
-    Theme::ThemeImage* _scrollBarBottomCap;
-    /**
-     * Scrollbar left cap image.
-     */
-    Theme::ThemeImage* _scrollBarLeftCap;
-    /**
-     * Scrollbar horizontal track image.
-     */
-    Theme::ThemeImage* _scrollBarHorizontal;
-    /**
-     * Scrollbar horizontal image.
-     */
-    Theme::ThemeImage* _scrollBarRightCap;
-    /** 
-     * Flag representing whether scrolling is enabled, and in which directions.
-     */
-    Scroll _scroll;
-    /** 
-     * Scroll bar bounds.
-     */
-    Rectangle _scrollBarBounds;
-    /** 
-     * How far this layout has been scrolled in each direction.
-     */
-    Vector2 _scrollPosition;
-    /** 
-     * Whether the scrollbars should auto-hide. Default is false.
-     */
-    bool _scrollBarsAutoHide;
-    /** 
-     * Used to animate scrollbars fading out.
-     */
-    float _scrollBarOpacity;
-    /** 
-     * Whether the user is currently touching / holding the mouse down within this layout's container.
-     */
-    bool _scrolling;
-    /** 
-     * First scrolling touch x position.
-     */
-    int _scrollingVeryFirstX;
-    /**
-     * First scrolling touch y position.
-     */
-    int _scrollingVeryFirstY;
-    /**
-     * First scrolling touch x position since last change in direction.
-     */ 
-    int _scrollingFirstX;
-    /** 
-     * First scrolling touch y position since last change in direction.
-     */ 
-    int _scrollingFirstY;
-    /** 
-     * The last y position when scrolling.
-     */ 
-    int _scrollingLastX;
-    /** 
-     * The last x position when scrolling.
-     */ 
-    int _scrollingLastY;
-    /** 
-     * Time we started scrolling horizontally.
-     */ 
-    double _scrollingStartTimeX;
-    /** 
-     * Time we started scrolling vertically.
-     */ 
-    double _scrollingStartTimeY;
-    /** 
-     * The last time we were scrolling.
-     */
-    double _scrollingLastTime;
-    /** 
-     * Speed to continue scrolling at after touch release or a scroll-wheel event.
-     */ 
-    Vector2 _scrollingVelocity;
-    /** 
-     * Friction dampens velocity.
-     */ 
-    float _scrollingFriction;
-    /**
-     * Amount to add to scrolling velocity on a scroll-wheel event;
-     */
-    float _scrollWheelSpeed;
-    /** 
-     * Are we scrolling to the right?
-     */ 
-    bool _scrollingRight;
-    /** 
-     * Are we scrolling down?
-     */ 
-    bool _scrollingDown;
-    /**
-     * Locked to scrolling vertically by grabbing the scrollbar with the mouse.
-     */
-    bool _scrollingMouseVertically;
-    /**
-     * Locked to scrolling horizontally by grabbing the scrollbar with the mouse.
-     */
-    bool _scrollingMouseHorizontally;
-
-private:
-
-    /**
-     * Constructor.
-     */
-    Container(const Container& copy);
-
-    enum Direction
-    {
-        UP = 0x01,
-        DOWN = 0x02,
-        LEFT = 0x04,
-        RIGHT = 0x08,
-        NEXT = 0x10
-    };
-
-    static const int MAX_CONTACT_INDICES = 10;
-
-    // Returns true on success; false if there are no controls to focus on,
-    // in which case scrolling can be initiated.
-    bool moveFocus(Direction direction, Control* outsideControl = NULL);
-
-    void guaranteeFocus(Control* inFocus);
-
-    // Starts scrolling at the given horizontal and vertical speeds.
-    void startScrolling(float x, float y, bool resetTime = true);
-
-    void stopScrolling();
-
-    void clearContacts();
-    bool inContact();
-
-    AnimationClip* _scrollBarOpacityClip;
-    int _zIndexDefault;
-    int _focusIndexDefault;
-    int _focusIndexMax;
-    unsigned int _focusPressed;
-    bool _selectButtonDown;
-    double _lastFrameTime;
-
-    // Timing information for repeating focus changes.
-    bool _focusChangeRepeat;
-    double _focusChangeStartTime;
-    double _focusChangeRepeatDelay;
-    unsigned int _focusChangeCount;
-    Direction _direction;
-
-    float _totalWidth;
-    float _totalHeight;
-    bool _contactIndices[MAX_CONTACT_INDICES];
-    bool _initializedWithScroll;
-    bool _scrollWheelRequiresFocus;
-    bool _allowRelayout;
-};
-
-}
-
-#endif
+#ifndef CONTAINER_H_
+#define CONTAINER_H_
+
+#include "Control.h"
+#include "Layout.h"
+#include "TimeListener.h"
+
+namespace gameplay
+{
+
+/**
+ * A container is a UI control that can contain other controls.
+ *
+ * The following properties are available for containers:
+
+ @verbatim
+    container <containerID>
+    {
+         // Container properties.
+         layout   = <Layout::Type>        // A value from the Layout::Type enum.  E.g.: LAYOUT_VERTICAL
+         style    = <styleID>           // A style from the form's theme.
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>    // Position of the container on-screen, measured in pixels.
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>   // Size of the container, measured in pixels.
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         scroll      = <Container::Scroll constant> // Whether scrolling is allowed and in which directions.
+         scrollBarsAutoHide = <bool>        // Whether scrollbars fade out when not in use.
+         scrollingFriction = <float>        // Friction applied to inertial scrolling.
+         scrollWheelRequiresFocus = <bool>  // Whether focus or hover state handles scroll-wheel events.
+         scrollWheelSpeed = <float>         // Speed to scroll at on a scroll-wheel event.
+         consumeEvents = <bool>             // Whether the container propagates input events to the Game's input event handler. Default is true.
+
+         // All the nested controls within this container.
+         container 
+         { 
+             ...
+         }
+
+         label { }
+         textBox { }
+         button { }
+         checkBox { }
+         radioButton { }
+         slider { }
+    }
+ @endverbatim
+ */
+class Container : public Control
+{
+    friend class Form;
+    friend class Control;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Constant used to auto-hide scrollbars.
+     */
+    static const int ANIMATE_SCROLLBAR_OPACITY = 8;
+
+    /**
+     * The definition for container scrolling.
+     */
+    enum Scroll
+    {
+        SCROLL_NONE        = 0,
+        SCROLL_HORIZONTAL  = 0x01,
+        SCROLL_VERTICAL    = 0x02,
+        SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL
+    };
+
+    /**
+     * Create a new container.
+     *
+     * @param id The container's ID.
+     * @param style The container's style.
+     * @param layoutType The container's layout type.
+     *
+     * @return The new container.
+     * @script{create}
+     */
+    static Container* create(const char* id, Theme::Style* style, Layout::Type layoutType = Layout::LAYOUT_ABSOLUTE);
+
+    /**
+     * Get this container's layout.
+     *
+     * @return This container's layout object.
+     */
+    Layout* getLayout();
+
+    /**
+     * Add a control to this layout.
+     * The control will be assigned the next available index.
+     *
+     * @param control The Control to add.
+     *
+     * @return The index assigned to the added Control.
+     */
+    unsigned int addControl(Control* control);
+
+    /**
+     * Insert a control at a specific index.
+     *
+     * @param control The control to add.
+     * @param index The index at which to insert the control.
+     */
+    void insertControl(Control* control, unsigned int index);
+
+    /**
+     * Remove a control at a specific index.
+     *
+     * @param index The index from which to remove the control.
+     */
+    void removeControl(unsigned int index);
+
+    /**
+     * Remove a control with the given ID.
+     *
+     * @param id The ID of the control to remove.
+     */
+    void removeControl(const char* id);
+
+    /**
+     * Remove a specific control.
+     *
+     * @param control The control to remove.
+     */
+    void removeControl(Control* control);
+
+    /**
+     * Get the Control at a specific index.
+     *
+     * @param index The index at which to retrieve the Control.
+     *
+     * @return The Control at the given index.
+     */
+    Control* getControl(unsigned int index) const;
+
+    /**
+     * Get a Control with a specific ID that belongs to this Layout.
+     *
+     * @param id The ID of the Control to search for.
+     */
+    Control* getControl(const char* id) const;
+
+    /**
+     * Returns the number of child controls for this container.
+     *
+     * @return The number of child controls.
+     */
+    unsigned int getControlCount() const;
+
+    /**
+     * Get the vector of controls within this container.
+     *
+     * @return The vector of the controls within this container.
+     * @script{ignore}
+     */
+    const std::vector<Control*>& getControls() const;
+
+    /**
+     * Determines if this container is a top level form.
+     *
+     * @return True if the container is a top level form, false otherwise.
+     */
+    virtual bool isForm() const;
+
+    /**
+     * Sets the allowed scroll directions for this container.
+     *
+     * @param scroll The allowed scroll directions for this container.
+     */
+    void setScroll(Scroll scroll);
+
+    /**
+     * Gets the allowed scroll directions for this container.
+     *
+     * @return The allowed scroll directions for this container.
+     */
+    Scroll getScroll() const;
+
+    /**
+     * Set whether scrollbars auto hidden when they become static.
+     *
+     * @param autoHide true to auto hide the scrollbars when they become static.
+     */
+    void setScrollBarsAutoHide(bool autoHide);
+
+    /**
+     * Whether scrollbars are always visible, or only visible while scrolling.
+     *
+     * @return Whether scrollbars are always visible.
+     */
+    bool isScrollBarsAutoHide() const;
+
+    /**
+     * Whether this container is currently being scrolled.
+     *
+     * @return Whether this container is currently being scrolled.
+     */
+    bool isScrolling() const;
+
+    /**
+     * Get the friction applied to scrolling velocity for this container.
+     */
+    float getScrollingFriction() const;
+
+    /**
+     * Get the friction applied to scrolling velocity for this container.
+     * A higher value will bring the viewport to a stop sooner.
+     */
+    void setScrollingFriction(float friction);
+
+    /**
+     * Get the speed added to scrolling velocity on a scroll-wheel event.
+     */
+    float getScrollWheelSpeed() const;
+
+    /**
+     * Set the speed added to scrolling velocity on a scroll-wheel event.
+     */
+    void setScrollWheelSpeed(float speed);
+
+    /**
+     * Get an offset of how far this layout has been scrolled in each direction.
+     */
+    const Vector2& getScrollPosition() const;
+
+    /**
+     * Set an offset of how far this layout has been scrolled in each direction.
+     */
+    void setScrollPosition(const Vector2& scrollPosition);
+
+    /**
+     * @see AnimationTarget::getAnimation
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
+    /**
+     * @see Control::isContainer
+     */
+    bool isContainer() const;
+
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
+    /**
+     * Get whether this container requires focus in order to handle scroll-wheel events.
+     */
+    bool getScrollWheelRequiresFocus() const;
+
+    /**
+     * Set whether this container requires focus in order to handle scroll-wheel events.
+     * If this property is set to true, scroll-wheel events will only be handled when the container has focus.
+     * If this property is set tofalse, scroll-wheel events will only be handled
+     * when the container is in the HOVER state.
+     *
+     * @param required Whether focus is required in order to handle scroll-wheel events.
+     */
+    void setScrollWheelRequiresFocus(bool required);
+
+    /**
+     * @see Control::setFocus
+     */
+    bool setFocus();
+
+    /**
+     * Returns the currently active control for this container.
+     *
+     * @return This container's active control.
+     */
+    Control* getActiveControl() const;
+    
+    /**
+     * Sets the active control for this container.
+     *
+     * A container's active control is the control that will receive focus
+     * when the container receives focus.
+     *
+     * @param control The container's new active control (must be a child of this container).
+     */
+    void setActiveControl(Control* control);
+
+    /**
+     * @see AnimationTarget::getAnimationPropertyComponentCount
+     */
+    virtual unsigned int getAnimationPropertyComponentCount(int propertyId) const;
+
+    /**
+     * @see AnimationTarget::getAnimationProperty
+     */
+    virtual void getAnimationPropertyValue(int propertyId, AnimationValue* value);
+
+    /**
+     * @see AnimationTarget::setAnimationProperty
+     */
+    virtual void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    Container();
+
+    /**
+     * Destructor.
+     */
+    virtual ~Container();
+
+    /**
+     * Create a container with a given style and properties, including a list of controls.
+     *
+     * @param style The style to apply to this container.
+     * @param properties The properties to set on this container, including nested controls.
+     *
+     * @return The new container.
+     */
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    /**
+     * Initialize properties common to all Containers from a Properties object.
+     *
+     * @param style The style to apply to this control.
+     * @param properties The properties to set on this control.
+     */
+    void initialize(Theme::Style* style, Properties* properties);
+
+    /**
+     * Updates each control within this container,
+     * and positions them according to the container's layout.
+     *
+     * @param container This container's parent container.
+     * @param offset The offset.
+     */
+    virtual void update(const Control* container, const Vector2& offset);
+
+    /**
+     * Gets a Layout::Type enum from a matching string.
+     *
+     * @param layoutString The layout string to parse
+     * @return The parsed layout type.
+     */
+    static Layout::Type getLayoutType(const char* layoutString);
+
+    /**
+     * Creates a layout for the specified layout type.
+     *
+     * @param type The type of layout to create.
+     * @return The new Layout.
+     */
+    static Layout* createLayout(Layout::Type type);
+
+    /**
+     * Returns whether this container or any of its controls have been modified and require an update.
+     * 
+     * @return true if this container or any of its controls have been modified and require an update.
+     */
+    virtual bool isDirty();
+
+    /**
+     * Adds controls nested within a properties object to this container,
+     * searching for styles within the given theme.
+     *
+     * @param theme The them to add controls from
+     * @param properties The properties to use.
+     */
+    void addControls(Theme* theme, Properties* properties);
+
+    /**
+     * Draws a sprite batch for the specified clipping rect.
+     *
+     * @param spriteBatch The sprite batch to use.
+     * @param clip The clipping rectangle.
+     * @param needsClear Whether it needs to be cleared.
+     * @param cleared Whether it was previously cleared
+     * @param targetHeight The targets height
+     */
+    virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight);
+
+    /**
+     * Update scroll position and velocity.
+     */
+    void updateScroll();
+
+    /**
+     * Sorts controls by Z-Order (for absolute layouts only).
+     * This method is used by controls to notify their parent container when
+     * their Z-Index changes.
+     */
+    void sortControls();
+
+    /**
+     * Applies touch events to scroll state.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by scrolling within this container.
+     *
+     * @see Touch::TouchEvent
+     */
+    bool touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
+
+    /**
+     * Mouse scroll event callback.
+     *
+     * @param evt The mouse scroll event that occurred.
+     * @param x The x position of the scroll in pixels. Left edge is zero.
+     * @param y The y position of the scroll in pixels. Top edge is zero.
+     * @param wheelDelta The value change of the mouse's scroll wheel.
+     *
+     * @return Whether the scroll event was consumed by scrolling within this container.
+     *
+     * @see Mouse::MouseEvent
+     */
+    bool mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
+
+    /**
+     * Get a Scroll enum from a matching string.
+     *
+     * @param scroll A string representing a Scroll enum.
+     *
+     * @return The Scroll enum value that matches the given string.
+     */
+    static Scroll getScroll(const char* scroll);
+
+    /**
+     * The container's layout.
+     */
+    Layout* _layout;
+    /**
+     * List of controls within the container.
+     */
+    std::vector<Control*> _controls;
+    /**
+     * The active control for the container.
+     */
+    Control* _activeControl;
+    /**
+     * Scrollbar top cap image.
+     */
+    Theme::ThemeImage* _scrollBarTopCap;
+    /**
+     * Scrollbar vertical track image.
+     */
+    Theme::ThemeImage* _scrollBarVertical;
+    /**
+     * Scrollbar bottom cap image.
+     */
+    Theme::ThemeImage* _scrollBarBottomCap;
+    /**
+     * Scrollbar left cap image.
+     */
+    Theme::ThemeImage* _scrollBarLeftCap;
+    /**
+     * Scrollbar horizontal track image.
+     */
+    Theme::ThemeImage* _scrollBarHorizontal;
+    /**
+     * Scrollbar horizontal image.
+     */
+    Theme::ThemeImage* _scrollBarRightCap;
+    /** 
+     * Flag representing whether scrolling is enabled, and in which directions.
+     */
+    Scroll _scroll;
+    /** 
+     * Scroll bar bounds.
+     */
+    Rectangle _scrollBarBounds;
+    /** 
+     * How far this layout has been scrolled in each direction.
+     */
+    Vector2 _scrollPosition;
+    /** 
+     * Whether the scrollbars should auto-hide. Default is false.
+     */
+    bool _scrollBarsAutoHide;
+    /** 
+     * Used to animate scrollbars fading out.
+     */
+    float _scrollBarOpacity;
+    /** 
+     * Whether the user is currently touching / holding the mouse down within this layout's container.
+     */
+    bool _scrolling;
+    /** 
+     * First scrolling touch x position.
+     */
+    int _scrollingVeryFirstX;
+    /**
+     * First scrolling touch y position.
+     */
+    int _scrollingVeryFirstY;
+    /**
+     * First scrolling touch x position since last change in direction.
+     */ 
+    int _scrollingFirstX;
+    /** 
+     * First scrolling touch y position since last change in direction.
+     */ 
+    int _scrollingFirstY;
+    /** 
+     * The last y position when scrolling.
+     */ 
+    int _scrollingLastX;
+    /** 
+     * The last x position when scrolling.
+     */ 
+    int _scrollingLastY;
+    /** 
+     * Time we started scrolling horizontally.
+     */ 
+    double _scrollingStartTimeX;
+    /** 
+     * Time we started scrolling vertically.
+     */ 
+    double _scrollingStartTimeY;
+    /** 
+     * The last time we were scrolling.
+     */
+    double _scrollingLastTime;
+    /** 
+     * Speed to continue scrolling at after touch release or a scroll-wheel event.
+     */ 
+    Vector2 _scrollingVelocity;
+    /** 
+     * Friction dampens velocity.
+     */ 
+    float _scrollingFriction;
+    /**
+     * Amount to add to scrolling velocity on a scroll-wheel event;
+     */
+    float _scrollWheelSpeed;
+    /** 
+     * Are we scrolling to the right?
+     */ 
+    bool _scrollingRight;
+    /** 
+     * Are we scrolling down?
+     */ 
+    bool _scrollingDown;
+    /**
+     * Locked to scrolling vertically by grabbing the scrollbar with the mouse.
+     */
+    bool _scrollingMouseVertically;
+    /**
+     * Locked to scrolling horizontally by grabbing the scrollbar with the mouse.
+     */
+    bool _scrollingMouseHorizontally;
+
+private:
+
+    /**
+     * Constructor.
+     */
+    Container(const Container& copy);
+
+    enum Direction
+    {
+        UP = 0x01,
+        DOWN = 0x02,
+        LEFT = 0x04,
+        RIGHT = 0x08,
+        NEXT = 0x10,
+        PREVIOUS = 0x20
+    };
+
+    static const int MAX_CONTACT_INDICES = 10;
+
+    // Returns true on success; false if there are no controls to focus on,
+    // in which case scrolling can be initiated.
+    bool moveFocus(Direction direction);
+
+	bool moveFocusNextPrevious(Direction direction);
+	bool moveFocusDirectional(Direction direction);
+
+    // Starts scrolling at the given horizontal and vertical speeds.
+    void startScrolling(float x, float y, bool resetTime = true);
+
+    void stopScrolling();
+
+    void clearContacts();
+    bool inContact();
+
+    AnimationClip* _scrollBarOpacityClip;
+    int _zIndexDefault;
+    bool _selectButtonDown;
+    double _lastFrameTime;
+
+    float _totalWidth;
+    float _totalHeight;
+    bool _contactIndices[MAX_CONTACT_INDICES];
+    bool _initializedWithScroll;
+    bool _scrollWheelRequiresFocus;
+    bool _allowRelayout;
+};
+
+}
+
+#endif

+ 164 - 168
gameplay/src/Control.cpp

@@ -1,6 +1,7 @@
 #include "Base.h"
 #include "Game.h"
 #include "Control.h"
+#include "Form.h"
 
 #define BOUNDS_X_PERCENTAGE_BIT 1
 #define BOUNDS_Y_PERCENTAGE_BIT 2
@@ -44,15 +45,17 @@ static bool parseCoordPair(const char* s, float* v1, float* v2, bool* v1Percenta
 }
 
 Control::Control()
-    : _id(""), _state(Control::NORMAL), _boundsBits(0), _dirty(true), _consumeInputEvents(false),
-    _alignment(ALIGN_TOP_LEFT), _isAlignmentSet(false), _autoWidth(AUTO_SIZE_NONE), _autoHeight(AUTO_SIZE_NONE), _listeners(NULL), _visible(true),
-    _zIndex(-1), _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(-1), _parent(NULL), _styleOverridden(false), _skin(NULL), _previousState(NORMAL)
+    : _id(""), _enabled(true), _boundsBits(0), _dirty(true), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT), _isAlignmentSet(false),
+    _autoWidth(AUTO_SIZE_NONE), _autoHeight(AUTO_SIZE_NONE), _listeners(NULL), _visible(true), _zIndex(-1),
+    _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(-1), _canFocus(false), _parent(NULL), _styleOverridden(false), _skin(NULL)
 {
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
 }
 
 Control::~Control()
 {
+    Form::verifyRemovedControlState(this);
+
     if (_listeners)
     {
         for (std::map<Control::Listener::EventType, std::list<Control::Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); ++itr)
@@ -94,7 +97,7 @@ void Control::initialize(Theme::Style* style, Properties* properties)
     _autoWidth = parseAutoSize(properties->getString("autoWidth"));
     _autoHeight = parseAutoSize(properties->getString("autoHeight"));
 
-    _consumeInputEvents = properties->getBool("consumeInputEvents", false);
+    _consumeInputEvents = properties->getBool("consumeInputEvents", true);
 
     _visible = properties->getBool("visible", true);
 
@@ -107,6 +110,9 @@ void Control::initialize(Theme::Style* style, Properties* properties)
         _zIndex = -1;
     }
 
+    if (properties->exists("canFocus"))
+        _canFocus = properties->getBool("canFocus", false);
+
     if (properties->exists("focusIndex"))
     {
         _focusIndex = properties->getInt("focusIndex");
@@ -408,15 +414,13 @@ void Control::setAutoHeight(AutoSize mode)
 
 void Control::setVisible(bool visible)
 {
-    if (visible && !_visible)
-    {
-        _visible = true;
-        _dirty = true;
-    }
-    else if (!visible && _visible)
+    if (_visible != visible)
     {
-        _visible = false;
+        _visible = visible;
         _dirty = true;
+
+        if (!_visible)
+            Form::controlDisabled(this);
     }
 }
 
@@ -425,9 +429,41 @@ bool Control::isVisible() const
     return _visible;
 }
 
+bool Control::isVisibleInHierarchy() const
+{
+    if (!_visible)
+        return false;
+
+    if (_parent)
+        return _parent->isVisibleInHierarchy();
+
+    return true;
+}
+
+bool Control::canFocus() const
+{
+    return _canFocus;
+}
+
+void Control::setCanFocus(bool acceptsFocus)
+{
+    _canFocus = acceptsFocus;
+}
+
 bool Control::hasFocus() const
 {
-    return (_state == FOCUS || (_state == HOVER && _previousState == FOCUS));
+    return (Form::_focusControl == this);
+}
+
+bool Control::setFocus()
+{
+    if (Form::_focusControl != this && canFocus())
+    {
+        Form::setFocusControl(this);
+        return true;
+    }
+
+    return false;
 }
 
 void Control::setOpacity(float opacity, unsigned char states)
@@ -453,21 +489,30 @@ float Control::getOpacity(State state) const
 
 void Control::setEnabled(bool enabled)
 {
-	if (enabled && _state == Control::DISABLED)
-	{
-		_state = Control::NORMAL;
+    if (_enabled != enabled)
+    {
+        _enabled = enabled;
         _dirty = true;
-	}
-	else if (!enabled && _state != Control::DISABLED)
-	{
-		_state = Control::DISABLED;
-		_dirty = true;
-	}
+
+        if (!_enabled)
+            Form::controlDisabled(this);
+    }
 }
 
 bool Control::isEnabled() const
 {
-    return _state != DISABLED;
+    return _enabled;
+}
+
+bool Control::isEnabledInHierarchy() const
+{
+    if (!_enabled)
+        return false;
+
+    if (_parent)
+        return _parent->isEnabledInHierarchy();
+
+    return true;
 }
 
 void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
@@ -790,22 +835,29 @@ Theme::Style* Control::getStyle() const
     return _style;
 }
 
-void Control::setState(State state)
+Control::State Control::getState() const
 {
-    if (getOverlay(_state) != getOverlay(state))
-        _dirty = true;
+    if (!_enabled)
+        return DISABLED;
 
-    _state = state;
-}
+    if (Form::_activeControl == this)
+    {
+        if (Form::_activeControlState == ACTIVE)
+            return ACTIVE;
+        if (Form::_focusControl == this)
+            return FOCUS;
+        return Form::_activeControlState;
+    }
+    
+    if (Form::_focusControl == this)
+        return FOCUS;
 
-Control::State Control::getState() const
-{
-    return _state;
+    return NORMAL;
 }
 
 Theme::Style::OverlayType Control::getOverlayType() const
 {
-    switch (_state)
+    switch (getState())
     {
     case Control::NORMAL:
         return Theme::Style::OVERLAY_NORMAL;
@@ -843,6 +895,11 @@ void Control::setZIndex(int zIndex)
     {
         _zIndex = zIndex;
         _dirty = true;
+
+        if (_parent)
+        {
+			_parent->sortControls();
+        }
     }
 }
 
@@ -931,133 +988,24 @@ void Control::addSpecificListener(Control::Listener* listener, Control::Listener
 
 bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
 {
-    switch (evt)
-    {
-    case Touch::TOUCH_PRESS:
-        // Controls that don't have an ACTIVE state go to the FOCUS state when pressed.
-        // (Other controls, such as buttons and sliders, become ACTIVE when pressed and go to the FOCUS state on release.)
-        // Labels are never any state other than NORMAL.
-        if (_contactIndex == INVALID_CONTACT_INDEX && x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-        {
-            _contactIndex = (int) contactIndex;
-
-            notifyListeners(Control::Listener::PRESS);
-
-            return _consumeInputEvents;
-        }
-        else
-        {
-            // If this control was in focus, it's not any more.
-            _state = NORMAL;
-        }
-        break;
-            
-    case Touch::TOUCH_MOVE:
-        break;
-
-    case Touch::TOUCH_RELEASE:
-        if (_contactIndex == (int)contactIndex)
-        {
-            _contactIndex = INVALID_CONTACT_INDEX;
-
-            // Always trigger Control::Listener::RELEASE
-            notifyListeners(Control::Listener::RELEASE);
-
-            // Only trigger Control::Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
-            if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-            {
-                // Leave this control in the FOCUS state.
-                notifyListeners(Control::Listener::CLICK);
-            }
-
-            return _consumeInputEvents;
-        }
-        break;
-    }
-
-    return false;
+    return _consumeInputEvents;
 }
 
 bool Control::keyEvent(Keyboard::KeyEvent evt, int key)
 {
-    return false;
+    return _consumeInputEvents;
 }
 
 bool Control::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 {
-    // By default, mouse events are either interpreted as touch events or ignored.
-    switch (evt)
-    {
-    case Mouse::MOUSE_PRESS_LEFT_BUTTON:
-        return touchEvent(Touch::TOUCH_PRESS, x, y, 0);
-
-    case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
-        return touchEvent(Touch::TOUCH_RELEASE, x, y, 0);
-
-    case Mouse::MOUSE_MOVE:
-        if (_state != ACTIVE)
-        {
-            if (_state != HOVER &&
-                x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-            {
-                _previousState = _state;
-                setState(HOVER);
-                notifyListeners(Control::Listener::ENTER);
-                return _consumeInputEvents;
-            }
-            else if (_state == HOVER && !(x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                        y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height))
-            {
-                setState(_previousState);
-                notifyListeners(Control::Listener::LEAVE);
-                return _consumeInputEvents;
-            }
-        }
-        return touchEvent(Touch::TOUCH_MOVE, x, y, 0);
-
-    default:
-        break;
-    }
-
+    // Return false instead of _consumeInputEvents to allow handling to be 
+    // routed to touchEvent before consuming.
     return false;
 }
 
 bool Control::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
 {
-    // Default behavior for gamepad events.
-    switch (evt)
-    {
-    case Gamepad::BUTTON_EVENT:
-        if (_state == Control::FOCUS)
-        {
-            if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
-                gamepad->isButtonDown(Gamepad::BUTTON_X))
-            {
-                notifyListeners(Control::Listener::PRESS);
-                return _consumeInputEvents;
-            }
-        }
-        else if (_state == Control::ACTIVE)
-        {
-            if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
-                !gamepad->isButtonDown(Gamepad::BUTTON_X))
-            {
-                notifyListeners(Control::Listener::RELEASE);
-                notifyListeners(Control::Listener::CLICK);
-                return _consumeInputEvents;
-            }
-        }
-        break;
-    case Gamepad::JOYSTICK_EVENT:
-        break;
-    case Gamepad::TRIGGER_EVENT:
-        break;
-    }
-
-    return false;
+    return _consumeInputEvents;
 }
 
 void Control::notifyListeners(Control::Listener::EventType eventType)
@@ -1067,6 +1015,8 @@ void Control::notifyListeners(Control::Listener::EventType eventType)
     // need to keep it alive until the method returns.
     addRef();
 
+    controlEvent(eventType);
+
     if (_listeners)
     {
         std::map<Control::Listener::EventType, std::list<Control::Listener*>*>::const_iterator itr = _listeners->find(eventType);
@@ -1086,6 +1036,10 @@ void Control::notifyListeners(Control::Listener::EventType eventType)
     release();
 }
 
+void Control::controlEvent(Control::Listener::EventType evt)
+{
+}
+
 void Control::update(const Control* container, const Vector2& offset)
 {
     Game* game = Game::getInstance();
@@ -1173,7 +1127,7 @@ void Control::update(const Control* container, const Vector2& offset)
 
     // Calculate the absolute viewport bounds (content area, which does not include border and padding)
     // Absolute bounds minus border and padding.
-    const Theme::Border& border = getBorder(_state);
+    const Theme::Border& border = getBorder(getState());
     const Theme::Padding& padding = getPadding();
     x += border.left + padding.left;
     y += border.top + padding.top;
@@ -1226,10 +1180,10 @@ void Control::update(const Control* container, const Vector2& offset)
     }
 
     // Cache themed attributes for performance.
-    _skin = getSkin(_state);
+    _skin = getSkin(getState());
 
     // Current opacity should be multiplied by that of the parent container.
-    _opacity = getOpacity(_state);
+    _opacity = getOpacity(getState());
     if (container)
         _opacity *= container->_opacity;
 }
@@ -1251,7 +1205,7 @@ void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
     const Theme::UVs& bottomRight = _skin->getUVs(Theme::Skin::BOTTOM_RIGHT);
 
     // Calculate screen-space positions.
-    const Theme::Border& border = getBorder(_state);
+    const Theme::Border& border = getBorder(getState());
     const Theme::Padding& padding = getPadding();
     Vector4 skinColor = _skin->getColor();
     skinColor.w *= _opacity;
@@ -1386,6 +1340,42 @@ const char* Control::getType() const
     return "control";
 }
 
+Control* Control::getParent() const
+{
+    return _parent;
+}
+
+bool Control::isChild(Control* control) const
+{
+    if (!control)
+        return false;
+
+    Control* parent = _parent;
+    while (parent)
+    {
+        if (parent == control)
+            return true;
+        parent = parent->_parent;
+    }
+
+    return false;
+}
+
+Form* Control::getTopLevelForm() const
+{
+    if (_parent)
+        return _parent->getTopLevelForm();
+
+    if (isContainer())
+    {
+        Container* container = static_cast<Container*>(const_cast<Control*>(this));
+        if (container->isForm())
+            return static_cast<Form*>(container);
+    }
+
+    return NULL;
+}
+
 // Implementation of AnimationHandler
 unsigned int Control::getAnimationPropertyComponentCount(int propertyId) const
 {
@@ -1511,33 +1501,39 @@ Theme::Style::Overlay* Control::getOverlay(State state) const
 {
     GP_ASSERT(_style);
 
-    switch(state)
+    Theme::Style::Overlay* overlay = NULL;
+
+    switch (state)
     {
     case Control::NORMAL:
         return _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
+
     case Control::FOCUS:
-        return _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
+        overlay = _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
+        break;
+
     case Control::ACTIVE:
-    {
-        Theme::Style::Overlay* activeOverlay = _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
-        if (activeOverlay)
-            return activeOverlay;
-        else
-            return getOverlay(_previousState);
-    }
+        overlay = _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
+        if (!overlay && hasFocus())
+            overlay = _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
+        break;
+
     case Control::DISABLED:
-        return _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
+        overlay = _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
+        break;
+
     case Control::HOVER:
-    {
-        Theme::Style::Overlay* hoverOverlay = _style->getOverlay(Theme::Style::OVERLAY_HOVER);
-        if (hoverOverlay)
-            return hoverOverlay;
-        else
-            return getOverlay(_previousState);
-    }
-    default:
-        return NULL;
+        overlay = _style->getOverlay(Theme::Style::OVERLAY_HOVER);
+        if (!overlay && hasFocus())
+            overlay = _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
+        break;
     }
+
+    // Fall back to normal overlay if more specific state overlay not found
+    if (!overlay)
+        overlay = _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
+
+    return overlay;
 }
 
 void Control::overrideStyle()

+ 104 - 17
gameplay/src/Control.h

@@ -17,6 +17,7 @@ namespace gameplay
 {
 
 class Container;
+class Form;
 
 /**
  * Base class for UI controls.
@@ -43,7 +44,7 @@ public:
         NORMAL = 0x01,
 
         /**
-         * State of a control currently in focus.
+         * State of a control when it is currently in focus.
          */
         FOCUS = 0x02,
 
@@ -173,8 +174,18 @@ public:
              * Event triggered when a mouse cursor leaves a control.
              */
             LEAVE           = 0x100,
+
+            /**
+             * Event triggered when a control gains focus.
+             */
+            FOCUS_GAINED    = 0x200,
+
+            /**
+             * Event triggered when a control loses focus.
+             */
+            FOCUS_LOST      = 0x400
         };
-    
+
         /*
          * Destructor.
          */
@@ -193,7 +204,7 @@ public:
      * @script{ignore}
      * A constant used for setting themed attributes on all control states simultaneously.
      */
-    static const unsigned char STATE_ALL = NORMAL | FOCUS | ACTIVE | DISABLED | HOVER;
+    static const unsigned char STATE_ALL = NORMAL | ACTIVE | FOCUS | DISABLED | HOVER;
 
     /**
      * Position animation property. Data = x, y
@@ -760,6 +771,14 @@ public:
      */
     bool isVisible() const;
 
+    /**
+     * Determines if this control is visible in its hierarchy.
+     *
+     * A control is visible in its hierarchy if it is visible and all of its parents
+     * are also visible.
+     */
+    bool isVisibleInHierarchy() const;
+
     /**
      * Set the opacity of this control.
      *
@@ -792,11 +811,12 @@ public:
     bool isEnabled() const;
 
     /**
-     * Change this control's state.
+     * Determines if this control is enabled in its hierarchy.
      *
-     * @param state The state to switch this control to.
+     * A control is enabled in its hierarchy if it is enabled and all of its parents
+     * are also enabled.
      */
-    void setState(State state);
+    bool isEnabledInHierarchy() const;
 
     /**
      * Get this control's current state.
@@ -848,6 +868,39 @@ public:
      */
     void setZIndex(int zIndex);
 
+    /**
+     * Determines if this control accepts focus.
+     *
+     * @return True if this control accepts focus, false if it does not.
+     */
+    bool canFocus() const;
+
+    /**
+     * Sets whether or not the control accepts input focus.
+     *
+     * @param acceptsFocus True if the control should accept input focus, false otherwise.
+     */
+    void setCanFocus(bool acceptsFocus);
+
+    /**
+     * Determines if this control is currently in focus.
+     *
+     * @return True if the control is currently in focus.
+     */
+    bool hasFocus() const;
+
+    /**
+     * Sets input focus to this control.
+     *
+     * If this control accepts focus (the hasFocus method returns true), input focus
+     * is set to this control. If this control is a container, the first focusable
+     * control within it gains focus.
+     *
+     * @return True if this control or one of its children successfully gained focus,
+     *      false otherwise.
+     */
+    virtual bool setFocus();
+
     /**
      * Get this control's focus index.
      *
@@ -858,6 +911,12 @@ public:
     /**
      * Set this control's focus index.
      *
+     * Focus indexes control the order in which input focus changes between controls
+     * when using the focus change controls such as the TAB key.
+     *
+     * Valid focus indexes should be zero or greater, with a negative number indicating
+     * an unset focus index.
+     *
      * @param focusIndex The new focus index.
      */
     void setFocusIndex(int focusIndex);
@@ -876,6 +935,29 @@ public:
      */
     virtual const char* getType() const;
 
+    /**
+     * Returns this control's parent, or NULL if this control does not have a parent.
+     *
+     * @return This control's parent.
+     */
+    Control* getParent() const;
+
+    /**
+     * Determines if this control is a child (at any level of hierarchy) of the 
+     * specified control.
+     *
+     * @param control The control to check.
+     * @return True if this control is a direct or indirect child of the specified control.
+     */
+    bool isChild(Control* control) const;
+
+    /**
+     * Returns this control's top level form, or NULL if this control does not belong to a form.
+     *
+     * @return this control's form.
+     */
+    Form* getTopLevelForm() const;
+
     /**
      * Adds a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -1074,6 +1156,14 @@ protected:
      */
     void notifyListeners(Control::Listener::EventType eventType);
 
+    /**
+     * Called when a control event is fired for this control, before external
+     * listeners are notified of the event.
+     *
+     * @param evt The event type.
+     */
+    virtual void controlEvent(Control::Listener::EventType evt);
+
     /**
      * Gets the Alignment by string.
      *
@@ -1082,23 +1172,15 @@ protected:
      */
     static Alignment getAlignment(const char* alignment);
 
-    /**
-     * Gets whether this control is in focus.
-     * Note that a control's state can be HOVER while the control is in focus.
-     * When the cursor leaves the control, it will return to the FOCUS state.
-     * This method will still return true in this case.
-     */
-    bool hasFocus() const;
-
     /** 
      * The Control's ID.
      */ 
     std::string _id;
 
     /**
-     * Determines overlay used during draw().
+     * Whether the control is enabled.
      */
-    State _state;
+    bool _enabled;
 
     /**
      * Bits indicating whether bounds values are absolute values or percentages.
@@ -1211,6 +1293,11 @@ protected:
      */
     int _focusIndex;
 
+    /**
+     * Whether or not the control accepts input focus.
+     */
+    bool _canFocus;
+
     /**
      * The control's parent container.
      */
@@ -1243,7 +1330,7 @@ private:
     
     bool _styleOverridden;
     Theme::Skin* _skin;
-    State _previousState;
+
 };
 
 }

+ 8 - 3
gameplay/src/ControlFactory.cpp

@@ -30,6 +30,11 @@ ControlFactory::~ControlFactory()
 {
 }
 
+void ControlFactory::finalize()
+{
+    SAFE_DELETE(__controlFactory);
+}
+
 ControlFactory* ControlFactory::getInstance() 
 {
 	if (__controlFactory == NULL)
@@ -55,12 +60,12 @@ void ControlFactory::unregisterCustomControl(const char* controlName)
 	}
 }
 
-Control *ControlFactory::createControl(const char* controlName, Theme::Style* style, Properties* properties, Theme* theme)
+Control *ControlFactory::createControl(const char* controlName, Theme::Style* style, Properties* properties)
 {
 	if (_registeredControls.find(controlName) == _registeredControls.end())
-		return NULL;	
+		return NULL;
 
-	return (*_registeredControls[controlName])(style, properties, theme);
+	return (*_registeredControls[controlName])(style, properties);
 }
 
 void ControlFactory::registerStandardControls() 

+ 18 - 8
gameplay/src/ControlFactory.h

@@ -1,7 +1,7 @@
 #ifndef	CONTROLFACTORY_H_
 #define	CONTROLFACTORY_H_
 
-#include "Theme.h"
+#include "ThemeStyle.h"
 
 namespace gameplay 
 {	
@@ -15,13 +15,15 @@ class Control;
  * @script{ignore}
  */
 class ControlFactory 
-{	
-public :
+{
+    friend class Game;
+
+public:
 
 	/**
 	 * The activator interface for controls that are created.
 	 */
-	typedef Control* (*ControlActivator)(Theme::Style*, Properties*, Theme*);
+	typedef Control* (*ControlActivator)(Theme::Style*, Properties*);
 
 	/**
 	 * Gets the single instance of the control factory used to create controls and register/unregister custom controls.
@@ -34,7 +36,7 @@ public :
 	 * Registers a custom control and specify the activator.
 	 *
 	 * @param controlName The name of the custom control to register.
-	 * @param activator The activator for applying the style, properties and theme to the control.
+	 * @param activator The activator for applying the style and properties to the control.
 	 *
 	 * @return true if the control was successfully registered.
 	 */
@@ -46,13 +48,16 @@ public :
 	 * @param controlName The name of the custom control to unregister.
 	 */
 	void unregisterCustomControl(const char* controlName);
-		
+
 	/**
 	 * Creates a controls from the set of core and custom controls registered.
 	 *
-	 * @param controlName The name of the control to create
+	 * @param controlName The name of the control to create.
+     * @param style The style to apply to the control.
+     * @param properties The Properties object containing the definition of the controlo.
+     * @return The newly created control.
 	 */
-	Control* createControl(const char* controlName, Theme::Style *style, Properties *properties, Theme *theme = NULL);
+	Control* createControl(const char* controlName, Theme::Style *style, Properties *properties);
 
 private:
 
@@ -71,6 +76,11 @@ private:
 	 */
 	~ControlFactory();
 
+    /**
+    * Called when the game is shutting down to clean up resources.
+    */
+    static void finalize();
+
 	/**
 	 * Assignment operator
 	 */

+ 28 - 28
gameplay/src/Curve.h

@@ -29,14 +29,14 @@ public:
     enum InterpolationType
     {
         /**
-         * Bezier Interpolation. 
+         * Bezier Interpolation.
          *
          * Requires that two control points are set for each segment.
          */
         BEZIER,
 
         /**
-         * B-Spline Interpolation. 
+         * B-Spline Interpolation.
          *
          * Uses the points as control points, and the curve is guaranteed to only pass through the
          * first and last point.
@@ -44,14 +44,14 @@ public:
         BSPLINE,
 
         /**
-         * Flat Interpolation. 
-         * 
+         * Flat Interpolation.
+         *
          * A form of Hermite interpolation that generates flat tangents for you. The tangents have a value equal to 0.
          */
         FLAT,
 
         /**
-         * Hermite Interpolation. 
+         * Hermite Interpolation.
          *
          * Requires that two tangents for each segment.
          */
@@ -62,8 +62,8 @@ public:
          */
         LINEAR,
 
-        /** 
-         * Smooth Interpolation. 
+        /**
+         * Smooth Interpolation.
          *
          * A form of Hermite interpolation that generates tangents for each segment based on the points prior to and after the segment.
          */
@@ -71,14 +71,14 @@ public:
 
         /**
          * Discrete Interpolation.
-         */ 
+         */
         STEP,
 
         /**
          * Quadratic-In Interpolation.
          */
-        QUADRATIC_IN, 
-        
+        QUADRATIC_IN,
+
         /**
          * Quadratic-Out Interpolation.
          */
@@ -98,17 +98,17 @@ public:
          * Cubic-In Interpolation.
          */
         CUBIC_IN,
-        
+
         /**
          * Cubic-Out Interpolation.
          */
         CUBIC_OUT,
-        
+
         /**
          * Cubic-In-Out Interpolation.
          */
         CUBIC_IN_OUT,
-        
+
         /**
          * Cubic-Out-In Interpolation.
          */
@@ -138,37 +138,37 @@ public:
          * Quintic-In Interpolation.
          */
         QUINTIC_IN,
-        
+
         /**
          * Quintic-Out Interpolation.
          */
         QUINTIC_OUT,
-        
+
         /**
          * Quintic-In-Out Interpolation.
          */
         QUINTIC_IN_OUT,
-        
+
         /**
          * Quintic-Out-In Interpolation.
          */
         QUINTIC_OUT_IN,
-        
+
         /**
          * Sine-In Interpolation.
          */
         SINE_IN,
-        
+
         /**
          * Sine-Out Interpolation.
          */
         SINE_OUT,
-        
+
         /**
          * Sine-In-Out Interpolation.
          */
         SINE_IN_OUT,
-        
+
         /**
          * Sine-Out-In Interpolation.
          */
@@ -277,7 +277,7 @@ public:
 
     /**
      * Creates a new curve.
-     * 
+     *
      * @param pointCount The number of points in the curve.
      * @param componentCount The number of float component values per key value.
      * @script{create}
@@ -343,7 +343,7 @@ public:
      * @param outValue The tangent leaving the point.
      */
     void setTangent(unsigned int index, InterpolationType type, float* inValue, float* outValue);
-    
+
     /**
      * Evaluates the curve at the given position value.
      *
@@ -373,7 +373,7 @@ public:
      * interpolating a repeat of the curve.
      *
      * @param time The position within the subregion of the curve to evaluate the curve at.
-     *      A time of zero representes the start of the subregion, with a time of one
+     *      A time of zero represents the start of the subregion, with a time of one
      *      representing the end of the subregion.
      * @param startTime Start time for the subregion (between 0.0 - 1.0).
      * @param endTime End time for the subregion (between 0.0 - 1.0).
@@ -478,19 +478,19 @@ private:
      */
     void interpolateHermiteSmooth(float s, unsigned int index, Point* from, Point* to, float* dst) const;
 
-    /** 
+    /**
      * Linear interpolation function.
-     */ 
+     */
     void interpolateLinear(float s, Point* from, Point* to, float* dst) const;
 
     /**
      * Quaternion interpolation function.
      */
     void interpolateQuaternion(float s, float* from, float* to, float* dst) const;
-    
+
     /**
      * Determines the current keyframe to interpolate from based on the specified time.
-     */ 
+     */
     int determineIndex(float time, unsigned int min, unsigned int max) const;
 
     /**
@@ -498,7 +498,7 @@ private:
      * index. The next four components of data starting at the given index will be interpolated as a Quaternion.
      * This function will assert an error if the given index is greater than the component size subtracted by the four components required
      * to store a quaternion.
-     * 
+     *
      * @param index The index of the Quaternion rotation data.
      */
     void setQuaternionOffset(unsigned int index);

+ 836 - 896
gameplay/src/FileSystem.cpp

@@ -1,896 +1,836 @@
-#include "Base.h"
-#include "FileSystem.h"
-#include "Properties.h"
-#include "Stream.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef WIN32
-    #include <windows.h>
-    #include <tchar.h>
-    #include <stdio.h>
-    #include <direct.h>
-    #define gp_stat _stat
-    #define gp_stat_struct struct stat
-#else
-    #define __EXT_POSIX2
-    #include <libgen.h>
-    #include <dirent.h>
-    #define gp_stat stat
-    #define gp_stat_struct struct stat
-#endif
-
-#ifdef __ANDROID__
-#include <android/asset_manager.h>
-extern AAssetManager* __assetManager;
-#endif
-
-namespace gameplay
-{
-
-#ifdef __ANDROID__
-#include <unistd.h>
-
-static void makepath(std::string path, int mode)
-{
-    std::vector<std::string> dirs;
-    while (path.length() > 0)
-    {
-        int index = path.find('/');
-        std::string dir = (index == -1 ) ? path : path.substr(0, index);
-        if (dir.length() > 0)
-            dirs.push_back(dir);
-        
-        if (index + 1 >= path.length() || index == -1)
-            break;
-            
-        path = path.substr(index + 1);
-    }
-    
-    struct stat s;
-    std::string dirPath;
-    for (unsigned int i = 0; i < dirs.size(); i++)
-    {
-        dirPath += "/";
-        dirPath += dirs[i];
-        if (stat(dirPath.c_str(), &s) != 0)
-        {
-            // Directory does not exist.
-            if (mkdir(dirPath.c_str(), 0777) != 0)
-            {
-                GP_ERROR("Failed to create directory: '%s'", dirPath.c_str());
-                return;
-            }
-        }
-    }
-    
-    return;
-}
-
-/**
- * Returns true if the file exists in the android read-only asset directory.
- */
-static bool androidFileExists(const char* filePath)
-{
-    AAsset* asset = AAssetManager_open(__assetManager, filePath, AASSET_MODE_RANDOM);
-    if (asset)
-    {
-        int lenght = AAsset_getLength(asset);
-        AAsset_close(asset);
-        return length > 0;
-    }
-    return false;
-}
-
-#endif
-
-/** @script{ignore} */
-static std::string __resourcePath("./");
-static std::map<std::string, std::string> __aliases;
-
-/**
- * Gets the fully resolved path.
- * If the path is relative then it will be prefixed with the resource path.
- * Aliases will be converted to a relative path.
- * 
- * @param path The path to resolve.
- * @param fullPath The full resolved path. (out param)
- */
-static void getFullPath(const char* path, std::string& fullPath)
-{
-    if (FileSystem::isAbsolutePath(path))
-    {
-        fullPath.assign(path);
-    }
-    else
-    {
-        fullPath.assign(__resourcePath);
-        fullPath += FileSystem::resolvePath(path);
-    }
-}
-
-/**
- * 
- * @script{ignore}
- */
-class FileStream : public Stream
-{
-public:
-    friend class FileSystem;
-    
-    ~FileStream();
-    virtual bool canRead();
-    virtual bool canWrite();
-    virtual bool canSeek();
-    virtual void close();
-    virtual size_t read(void* ptr, size_t size, size_t count);
-    virtual char* readLine(char* str, int num);
-    virtual size_t write(const void* ptr, size_t size, size_t count);
-    virtual bool eof();
-    virtual size_t length();
-    virtual long int position();
-    virtual bool seek(long int offset, int origin);
-    virtual bool rewind();
-
-    static FileStream* create(const char* filePath, const char* mode);
-
-private:
-    FileStream(FILE* file);
-
-private:
-    FILE* _file;
-    bool _canRead;
-    bool _canWrite;
-};
-
-#ifdef __ANDROID__
-
-/**
- * 
- * @script{ignore}
- */
-class FileStreamAndroid : public Stream
-{
-public:
-    friend class FileSystem;
-    
-    ~FileStreamAndroid();
-    virtual bool canRead();
-    virtual bool canWrite();
-    virtual bool canSeek();
-    virtual void close();
-    virtual size_t read(void* ptr, size_t size, size_t count);
-    virtual char* readLine(char* str, int num);
-    virtual size_t write(const void* ptr, size_t size, size_t count);
-    virtual bool eof();
-    virtual size_t length();
-    virtual long int position();
-    virtual bool seek(long int offset, int origin);
-    virtual bool rewind();
-
-    static FileStreamAndroid* create(const char* filePath, const char* mode);
-
-private:
-    FileStreamAndroid(AAsset* asset);
-
-private:
-    AAsset* _asset;
-};
-
-#endif
-
-/////////////////////////////
-
-FileSystem::FileSystem()
-{
-}
-
-FileSystem::~FileSystem()
-{
-}
-
-void FileSystem::setResourcePath(const char* path)
-{
-    __resourcePath = path == NULL ? "" : path;
-}
-
-const char* FileSystem::getResourcePath()
-{
-    return __resourcePath.c_str();
-}
-
-void FileSystem::loadResourceAliases(const char* aliasFilePath)
-{
-    Properties* properties = Properties::create(aliasFilePath);
-    if (properties)
-    {
-        Properties* aliases;
-        while ((aliases = properties->getNextNamespace()) != NULL)
-        {
-            loadResourceAliases(aliases);
-        }
-    }
-    SAFE_DELETE(properties);
-}
-
-void FileSystem::loadResourceAliases(Properties* properties)
-{
-    assert(properties);
-
-    const char* name;
-    while ((name = properties->getNextProperty()) != NULL)
-    {
-        __aliases[name] = properties->getString();
-    }
-}
-
-const char* FileSystem::resolvePath(const char* path)
-{
-    GP_ASSERT(path);
-
-    size_t len = strlen(path);
-    if (len > 1 && path[0] == '@')
-    {
-        std::string alias(path + 1);
-        std::map<std::string, std::string>::const_iterator itr = __aliases.find(alias);
-        if (itr == __aliases.end())
-            return path; // no matching alias found
-        return itr->second.c_str();
-    }
-
-    return path;
-}
-
-bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
-{
-#ifdef WIN32
-    std::string path(FileSystem::getResourcePath());
-    if (dirPath && strlen(dirPath) > 0)
-    {
-        path.append(dirPath);
-    }
-    path.append("/*");
-    // Convert char to wchar
-    std::basic_string<TCHAR> wPath;
-    wPath.assign(path.begin(), path.end());
-
-    WIN32_FIND_DATA FindFileData;
-    HANDLE hFind = FindFirstFile(wPath.c_str(), &FindFileData);
-    if (hFind == INVALID_HANDLE_VALUE) 
-    {
-        return false;
-    }
-    do
-    {
-        // Add to the list if this is not a directory
-        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
-        {
-            // Convert wchar to char
-            std::basic_string<TCHAR> wfilename(FindFileData.cFileName);
-            std::string filename;
-            filename.assign(wfilename.begin(), wfilename.end());
-            files.push_back(filename);
-        }
-    } while (FindNextFile(hFind, &FindFileData) != 0);
-
-    FindClose(hFind);
-    return true;
-#else
-    std::string path(FileSystem::getResourcePath());
-    if (dirPath && strlen(dirPath) > 0)
-    {
-        path.append(dirPath);
-    }
-    path.append("/.");
-    bool result = false;
-
-    struct dirent* dp;
-    DIR* dir = opendir(path.c_str());
-    if (dir != NULL)
-    {
-        while ((dp = readdir(dir)) != NULL)
-        {
-            std::string filepath(path);
-            filepath.append("/");
-            filepath.append(dp->d_name);
-
-            struct stat buf;
-            if (!stat(filepath.c_str(), &buf))
-            {
-                // Add to the list if this is not a directory
-                if (!S_ISDIR(buf.st_mode))
-                {
-                    files.push_back(dp->d_name);
-                }
-            }
-        }
-        closedir(dir);
-        result = true;
-    }
-
-#ifdef __ANDROID__
-    // List the files that are in the android APK at this path
-    AAssetDir* assetDir = AAssetManager_openDir(__assetManager, dirPath);
-    if (assetDir != NULL)
-    {
-        AAssetDir_rewind(assetDir);
-        const char* file = NULL;
-        while ((file = AAssetDir_getNextFileName(assetDir)) != NULL)
-        {
-            std::string filename(file);
-            // Check if this file was already added to the list because it was copied to the SD card.
-            if (find(files.begin(), files.end(), filename) == files.end())
-            {
-                files.push_back(filename);
-            }
-        }
-        AAssetDir_close(assetDir);
-        result = true;
-    }
-#endif
-
-    return result;
-#endif
-}
-
-bool FileSystem::fileExists(const char* filePath)
-{
-    GP_ASSERT(filePath);
-
-#ifdef __ANDROID__
-    if (androidFileExists(resolvePath(filePath)))
-    {
-        return true;
-    }
-#endif
-
-    std::string fullPath;
-    getFullPath(filePath, fullPath);
-
-    gp_stat_struct s;
-
-#ifdef WIN32
-    if (!isAbsolutePath(filePath) && stat(fullPath.c_str(), &s) != 0)
-    {
-        fullPath = __resourcePath;
-        fullPath += "../../gameplay/";
-        fullPath += filePath;
-        
-        int result = stat(fullPath.c_str(), &s);
-        if (result != 0)
-        {
-            fullPath = __resourcePath;
-            fullPath += "../gameplay/";
-            fullPath += filePath;
-            return stat(fullPath.c_str(), &s) == 0;
-        }
-    }
-    return true;
-#else
-    return stat(fullPath.c_str(), &s) == 0;
-#endif
-}
-
-Stream* FileSystem::open(const char* path, size_t mode)
-{
-    char modeStr[] = "rb";
-    if ((mode & WRITE) != 0)
-        modeStr[0] = 'w';
-#ifdef __ANDROID__
-    if ((mode & WRITE) != 0)
-    {
-        // Open a file on the SD card
-        std::string fullPath(__resourcePath);
-        fullPath += resolvePath(path);
-
-        size_t index = fullPath.rfind('/');
-        if (index != std::string::npos)
-        {
-            std::string directoryPath = fullPath.substr(0, index);
-            struct stat s;
-            if (stat(directoryPath.c_str(), &s) != 0)
-                makepath(directoryPath, 0777);
-        }
-        return FileStream::create(fullPath.c_str(), modeStr);
-    }
-    else
-    {
-        // Open a file in the read-only asset directory
-        return FileStreamAndroid::create(resolvePath(path), modeStr);
-    }
-#else
-    std::string fullPath;
-    getFullPath(path, fullPath);
-    
-#ifdef WIN32
-    gp_stat_struct s;
-    if (!isAbsolutePath(path) && stat(fullPath.c_str(), &s) != 0 && (mode & WRITE) == 0)
-    {
-        fullPath = __resourcePath;
-        fullPath += "../../gameplay/";
-        fullPath += path;
-        
-        int result = stat(fullPath.c_str(), &s);
-        if (result != 0)
-        {
-            fullPath = __resourcePath;
-            fullPath += "../gameplay/";
-            fullPath += path;
-            if (stat(fullPath.c_str(), &s) != 0)
-            {
-                return NULL;
-            }
-        }
-    }
-#endif
-    FileStream* stream = FileStream::create(fullPath.c_str(), modeStr);
-    return stream;
-#endif
-}
-
-FILE* FileSystem::openFile(const char* filePath, const char* mode)
-{
-    GP_ASSERT(filePath);
-    GP_ASSERT(mode);
-
-    std::string fullPath;
-    getFullPath(filePath, fullPath);
-
-    createFileFromAsset(filePath);
-    
-    FILE* fp = fopen(fullPath.c_str(), mode);
-    
-#ifdef WIN32
-    if (fp == NULL && !isAbsolutePath(filePath))
-    {
-        fullPath = __resourcePath;
-        fullPath += "../../gameplay/";
-        fullPath += filePath;
-        
-        fp = fopen(fullPath.c_str(), mode);
-        if (!fp)
-        {
-            fullPath = __resourcePath;
-            fullPath += "../gameplay/";
-            fullPath += filePath;
-            fp = fopen(fullPath.c_str(), mode);
-        }
-    }
-#endif
-
-    return fp;
-}
-
-char* FileSystem::readAll(const char* filePath, int* fileSize)
-{
-    GP_ASSERT(filePath);
-
-    // Open file for reading.
-    std::auto_ptr<Stream> stream(open(filePath));
-    if (stream.get() == NULL)
-    {
-        GP_ERROR("Failed to load file: %s", filePath);
-        return NULL;
-    }
-    size_t size = stream->length();
-
-    // Read entire file contents.
-    char* buffer = new char[size + 1];
-    size_t read = stream->read(buffer, 1, size);
-    if (read != size)
-    {
-        GP_ERROR("Failed to read complete contents of file '%s' (amount read vs. file size: %u < %u).", filePath, read, size);
-        SAFE_DELETE_ARRAY(buffer);
-        return NULL;
-    }
-
-    // Force the character buffer to be NULL-terminated.
-    buffer[size] = '\0';
-
-    if (fileSize)
-    {
-        *fileSize = (int)size; 
-    }
-    return buffer;
-}
-
-bool FileSystem::isAbsolutePath(const char* filePath)
-{
-    if (filePath == 0 || filePath[0] == '\0')
-        return false;
-#ifdef WIN32
-    if (filePath[1] != '\0')
-    {
-        char first = filePath[0];
-        return (filePath[1] == ':' && ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')));
-    }
-    return false;
-#else
-    return filePath[0] == '/';
-#endif
-}
-
-void FileSystem::createFileFromAsset(const char* path)
-{
-#ifdef __ANDROID__
-    static std::set<std::string> upToDateAssets;
-
-    GP_ASSERT(path);
-    std::string fullPath(__resourcePath);
-    std::string resolvedPath = FileSystem::resolvePath(path);
-    fullPath += resolvedPath;
-
-    std::string directoryPath = fullPath.substr(0, fullPath.rfind('/'));
-    struct stat s;
-    if (stat(directoryPath.c_str(), &s) != 0)
-        makepath(directoryPath, 0777);
-
-    // To ensure that the files on the file system corresponding to the assets in the APK bundle
-    // are always up to date (and in sync), we copy them from the APK to the file system once
-    // for each time the process (game) runs.
-    if (upToDateAssets.find(fullPath) == upToDateAssets.end())
-    {
-        AAsset* asset = AAssetManager_open(__assetManager, resolvedPath.c_str(), AASSET_MODE_RANDOM);
-        if (asset)
-        {
-            const void* data = AAsset_getBuffer(asset);
-            int length = AAsset_getLength(asset);
-            FILE* file = fopen(fullPath.c_str(), "wb");
-            if (file != NULL)
-            {
-                int ret = fwrite(data, sizeof(unsigned char), length, file);
-                if (fclose(file) != 0)
-                {
-                    GP_ERROR("Failed to close file on file system created from APK asset '%s'.", path);
-                    return;
-                }
-                if (ret != length)
-                {
-                    GP_ERROR("Failed to write all data from APK asset '%s' to file on file system.", path);
-                    return;
-                }
-            }
-            else
-            {
-                GP_ERROR("Failed to create file on file system from APK asset '%s'.", path);
-                return;
-            }
-
-            upToDateAssets.insert(fullPath);
-        }
-    }
-#endif
-}
-
-std::string FileSystem::getDirectoryName(const char* path)
-{
-    if (path == NULL || strlen(path) == 0)
-    {
-        return "";
-    }
-#ifdef WIN32
-    char drive[_MAX_DRIVE];
-    char dir[_MAX_DIR];
-    _splitpath(path, drive, dir, NULL, NULL);
-    std::string dirname;
-    size_t driveLength = strlen(drive);
-    if (driveLength > 0)
-    {
-        dirname.reserve(driveLength + strlen(dir));
-        dirname.append(drive);
-        dirname.append(dir);
-    }
-    else
-    {
-        dirname.assign(dir);
-    }
-    std::replace(dirname.begin(), dirname.end(), '\\', '/');
-    return dirname;
-#else
-    // dirname() modifies the input string so create a temp string
-    std::string dirname;
-    char* tempPath = new char[strlen(path) + 1];
-    strcpy(tempPath, path);
-    char* dir = ::dirname(tempPath);
-    if (dir && strlen(dir) > 0)
-    {
-        dirname.assign(dir);
-        // dirname() strips off the trailing '/' so add it back to be consistent with Windows
-        dirname.append("/");
-    }
-    SAFE_DELETE_ARRAY(tempPath);
-    return dirname;
-#endif
-}
-
-std::string FileSystem::getExtension(const char* path)
-{
-    const char* str = strrchr(path, '.');
-    if (str == NULL)
-        return "";
-
-    std::string ext;
-    size_t len = strlen(str);
-    for (size_t i = 0; i < len; ++i)
-        ext += std::toupper(str[i]);
-
-    return ext;
-}
-
-//////////////////
-
-FileStream::FileStream(FILE* file)
-    : _file(file), _canRead(false), _canWrite(false)
-{
-    
-}
-
-FileStream::~FileStream()
-{
-    if (_file)
-    {
-        close();
-    }
-}
-
-FileStream* FileStream::create(const char* filePath, const char* mode)
-{
-    FILE* file = fopen(filePath, mode);
-    if (file)
-    {
-        FileStream* stream = new FileStream(file);
-        const char* s = mode;
-        while (s != NULL && *s != '\0')
-        {
-            if (*s == 'r')
-                stream->_canRead = true;
-            else if (*s == 'w')
-                stream->_canWrite = true;
-            ++s;
-        }
-
-        return stream;
-    }
-    return NULL;
-}
-
-bool FileStream::canRead()
-{
-    return _file && _canRead;
-}
-
-bool FileStream::canWrite()
-{
-    return _file && _canWrite;
-}
-
-bool FileStream::canSeek()
-{
-    return _file != NULL;
-}
-
-void FileStream::close()
-{
-    if (_file)
-        fclose(_file);
-    _file = NULL;
-}
-
-size_t FileStream::read(void* ptr, size_t size, size_t count)
-{
-    if (!_file)
-        return 0;
-    return fread(ptr, size, count, _file);
-}
-
-char* FileStream::readLine(char* str, int num)
-{
-    if (!_file)
-        return 0;
-    return fgets(str, num, _file);
-}
-
-size_t FileStream::write(const void* ptr, size_t size, size_t count)
-{
-    if (!_file)
-        return 0;
-    return fwrite(ptr, size, count, _file);
-}
-
-bool FileStream::eof()
-{
-    if (!_file || feof(_file))
-        return true;
-    return ((size_t)position()) >= length();
-}
-
-size_t FileStream::length()
-{
-    size_t len = 0;
-    if (canSeek())
-    {
-        long int pos = position();
-        if (seek(0, SEEK_END))
-        {
-            len = position();
-        }
-        seek(pos, SEEK_SET);
-    }
-    return len;
-}
-
-long int FileStream::position()
-{
-    if (!_file)
-        return -1;
-    return ftell(_file);
-}
-
-bool FileStream::seek(long int offset, int origin)
-{
-    if (!_file)
-        return false;
-    return fseek(_file, offset, origin) == 0;
-}
-
-bool FileStream::rewind()
-{
-    if (canSeek())
-    {
-        ::rewind(_file);
-        return true;
-    }
-    return false;
-}
-
-////////////////////////////////
-
-#ifdef __ANDROID__
-
-FileStreamAndroid::FileStreamAndroid(AAsset* asset)
-    : _asset(asset)
-{
-}
-
-FileStreamAndroid::~FileStreamAndroid()
-{
-    if (_asset)
-        close();
-}
-
-FileStreamAndroid* FileStreamAndroid::create(const char* filePath, const char* mode)
-{
-    AAsset* asset = AAssetManager_open(__assetManager, filePath, AASSET_MODE_RANDOM);
-    if (asset)
-    {
-        FileStreamAndroid* stream = new FileStreamAndroid(asset);
-        return stream;
-    }
-    return NULL;
-}
-
-bool FileStreamAndroid::canRead()
-{
-    return true;
-}
-
-bool FileStreamAndroid::canWrite()
-{
-    return false;
-}
-
-bool FileStreamAndroid::canSeek()
-{
-    return true;
-}
-
-void FileStreamAndroid::close()
-{
-    if (_asset)
-        AAsset_close(_asset);
-    _asset = NULL;
-}
-
-size_t FileStreamAndroid::read(void* ptr, size_t size, size_t count)
-{
-    int result = AAsset_read(_asset, ptr, size * count);
-    return result > 0 ? ((size_t)result) / size : 0;
-}
-
-char* FileStreamAndroid::readLine(char* str, int num)
-{
-    if (num <= 0)
-        return NULL;
-    char c = 0;
-    size_t maxCharsToRead = num - 1;
-    for (size_t i = 0; i < maxCharsToRead; ++i)
-    {
-        size_t result = read(&c, 1, 1);
-        if (result != 1)
-        {
-            str[i] = '\0';
-            break;
-        }
-        if (c == '\n')
-        {
-            str[i] = c;
-            str[i + 1] = '\0';
-            break;
-        }
-        else if(c == '\r')
-        {
-            str[i] = c;
-            // next may be '\n'
-            size_t pos = position();
-
-            char nextChar = 0;
-            if (read(&nextChar, 1, 1) != 1)
-            {
-                // no more characters
-                str[i + 1] = '\0';
-                break;
-            }
-            if (nextChar == '\n')
-            {
-                if (i == maxCharsToRead - 1)
-                {
-                    str[i + 1] = '\0';
-                    break;
-                }
-                else
-                {
-                    str[i + 1] = nextChar;
-                    str[i + 2] = '\0';
-                    break;
-                }
-            }
-            else
-            {
-                seek(pos, SEEK_SET);
-                str[i + 1] = '\0';
-                break;
-            }
-        }
-        str[i] = c;
-    }
-    return str; // what if first read failed?
-}
-
-size_t FileStreamAndroid::write(const void* ptr, size_t size, size_t count)
-{
-    return 0;
-}
-
-bool FileStreamAndroid::eof()
-{
-    return position() >= length();
-}
-
-size_t FileStreamAndroid::length()
-{
-    return (size_t)AAsset_getLength(_asset);
-}
-
-long int FileStreamAndroid::position()
-{
-    return AAsset_getLength(_asset) - AAsset_getRemainingLength(_asset);
-}
-
-bool FileStreamAndroid::seek(long int offset, int origin)
-{
-    return AAsset_seek(_asset, offset, origin) != -1;
-}
-
-bool FileStreamAndroid::rewind()
-{
-    if (canSeek())
-    {
-        return AAsset_seek(_asset, 0, SEEK_SET) != -1;
-    }
-    return false;
-}
-
-#endif
-
-}
+#include "Base.h"
+#include "FileSystem.h"
+#include "Properties.h"
+#include "Stream.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+    #include <windows.h>
+    #include <tchar.h>
+    #include <stdio.h>
+    #include <direct.h>
+    #define gp_stat _stat
+    #define gp_stat_struct struct stat
+#else
+    #define __EXT_POSIX2
+    #include <libgen.h>
+    #include <dirent.h>
+    #define gp_stat stat
+    #define gp_stat_struct struct stat
+#endif
+
+#ifdef __ANDROID__
+#include <android/asset_manager.h>
+extern AAssetManager* __assetManager;
+#endif
+
+namespace gameplay
+{
+
+#ifdef __ANDROID__
+#include <unistd.h>
+
+static void makepath(std::string path, int mode)
+{
+    std::vector<std::string> dirs;
+    while (path.length() > 0)
+    {
+        int index = path.find('/');
+        std::string dir = (index == -1 ) ? path : path.substr(0, index);
+        if (dir.length() > 0)
+            dirs.push_back(dir);
+        
+        if (index + 1 >= path.length() || index == -1)
+            break;
+            
+        path = path.substr(index + 1);
+    }
+    
+    struct stat s;
+    std::string dirPath;
+    for (unsigned int i = 0; i < dirs.size(); i++)
+    {
+        dirPath += "/";
+        dirPath += dirs[i];
+        if (stat(dirPath.c_str(), &s) != 0)
+        {
+            // Directory does not exist.
+            if (mkdir(dirPath.c_str(), 0777) != 0)
+            {
+                GP_ERROR("Failed to create directory: '%s'", dirPath.c_str());
+                return;
+            }
+        }
+    }
+    
+    return;
+}
+
+/**
+ * Returns true if the file exists in the android read-only asset directory.
+ */
+static bool androidFileExists(const char* filePath)
+{
+    AAsset* asset = AAssetManager_open(__assetManager, filePath, AASSET_MODE_RANDOM);
+    if (asset)
+    {
+        int lenght = AAsset_getLength(asset);
+        AAsset_close(asset);
+        return length > 0;
+    }
+    return false;
+}
+
+#endif
+
+/** @script{ignore} */
+static std::string __resourcePath("./");
+static std::map<std::string, std::string> __aliases;
+
+/**
+ * Gets the fully resolved path.
+ * If the path is relative then it will be prefixed with the resource path.
+ * Aliases will be converted to a relative path.
+ * 
+ * @param path The path to resolve.
+ * @param fullPath The full resolved path. (out param)
+ */
+static void getFullPath(const char* path, std::string& fullPath)
+{
+    if (FileSystem::isAbsolutePath(path))
+    {
+        fullPath.assign(path);
+    }
+    else
+    {
+        fullPath.assign(__resourcePath);
+        fullPath += FileSystem::resolvePath(path);
+    }
+}
+
+/**
+ * 
+ * @script{ignore}
+ */
+class FileStream : public Stream
+{
+public:
+    friend class FileSystem;
+    
+    ~FileStream();
+    virtual bool canRead();
+    virtual bool canWrite();
+    virtual bool canSeek();
+    virtual void close();
+    virtual size_t read(void* ptr, size_t size, size_t count);
+    virtual char* readLine(char* str, int num);
+    virtual size_t write(const void* ptr, size_t size, size_t count);
+    virtual bool eof();
+    virtual size_t length();
+    virtual long int position();
+    virtual bool seek(long int offset, int origin);
+    virtual bool rewind();
+
+    static FileStream* create(const char* filePath, const char* mode);
+
+private:
+    FileStream(FILE* file);
+
+private:
+    FILE* _file;
+    bool _canRead;
+    bool _canWrite;
+};
+
+#ifdef __ANDROID__
+
+/**
+ * 
+ * @script{ignore}
+ */
+class FileStreamAndroid : public Stream
+{
+public:
+    friend class FileSystem;
+    
+    ~FileStreamAndroid();
+    virtual bool canRead();
+    virtual bool canWrite();
+    virtual bool canSeek();
+    virtual void close();
+    virtual size_t read(void* ptr, size_t size, size_t count);
+    virtual char* readLine(char* str, int num);
+    virtual size_t write(const void* ptr, size_t size, size_t count);
+    virtual bool eof();
+    virtual size_t length();
+    virtual long int position();
+    virtual bool seek(long int offset, int origin);
+    virtual bool rewind();
+
+    static FileStreamAndroid* create(const char* filePath, const char* mode);
+
+private:
+    FileStreamAndroid(AAsset* asset);
+
+private:
+    AAsset* _asset;
+};
+
+#endif
+
+/////////////////////////////
+
+FileSystem::FileSystem()
+{
+}
+
+FileSystem::~FileSystem()
+{
+}
+
+void FileSystem::setResourcePath(const char* path)
+{
+    __resourcePath = path == NULL ? "" : path;
+}
+
+const char* FileSystem::getResourcePath()
+{
+    return __resourcePath.c_str();
+}
+
+void FileSystem::loadResourceAliases(const char* aliasFilePath)
+{
+    Properties* properties = Properties::create(aliasFilePath);
+    if (properties)
+    {
+        Properties* aliases;
+        while ((aliases = properties->getNextNamespace()) != NULL)
+        {
+            loadResourceAliases(aliases);
+        }
+    }
+    SAFE_DELETE(properties);
+}
+
+void FileSystem::loadResourceAliases(Properties* properties)
+{
+    assert(properties);
+
+    const char* name;
+    while ((name = properties->getNextProperty()) != NULL)
+    {
+        __aliases[name] = properties->getString();
+    }
+}
+
+const char* FileSystem::resolvePath(const char* path)
+{
+    GP_ASSERT(path);
+
+    size_t len = strlen(path);
+    if (len > 1 && path[0] == '@')
+    {
+        std::string alias(path + 1);
+        std::map<std::string, std::string>::const_iterator itr = __aliases.find(alias);
+        if (itr == __aliases.end())
+            return path; // no matching alias found
+        return itr->second.c_str();
+    }
+
+    return path;
+}
+
+bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
+{
+#ifdef WIN32
+    std::string path(FileSystem::getResourcePath());
+    if (dirPath && strlen(dirPath) > 0)
+    {
+        path.append(dirPath);
+    }
+    path.append("/*");
+    // Convert char to wchar
+    std::basic_string<TCHAR> wPath;
+    wPath.assign(path.begin(), path.end());
+
+    WIN32_FIND_DATA FindFileData;
+    HANDLE hFind = FindFirstFile(wPath.c_str(), &FindFileData);
+    if (hFind == INVALID_HANDLE_VALUE) 
+    {
+        return false;
+    }
+    do
+    {
+        // Add to the list if this is not a directory
+        if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+        {
+            // Convert wchar to char
+            std::basic_string<TCHAR> wfilename(FindFileData.cFileName);
+            std::string filename;
+            filename.assign(wfilename.begin(), wfilename.end());
+            files.push_back(filename);
+        }
+    } while (FindNextFile(hFind, &FindFileData) != 0);
+
+    FindClose(hFind);
+    return true;
+#else
+    std::string path(FileSystem::getResourcePath());
+    if (dirPath && strlen(dirPath) > 0)
+    {
+        path.append(dirPath);
+    }
+    path.append("/.");
+    bool result = false;
+
+    struct dirent* dp;
+    DIR* dir = opendir(path.c_str());
+    if (dir != NULL)
+    {
+        while ((dp = readdir(dir)) != NULL)
+        {
+            std::string filepath(path);
+            filepath.append("/");
+            filepath.append(dp->d_name);
+
+            struct stat buf;
+            if (!stat(filepath.c_str(), &buf))
+            {
+                // Add to the list if this is not a directory
+                if (!S_ISDIR(buf.st_mode))
+                {
+                    files.push_back(dp->d_name);
+                }
+            }
+        }
+        closedir(dir);
+        result = true;
+    }
+
+#ifdef __ANDROID__
+    // List the files that are in the android APK at this path
+    AAssetDir* assetDir = AAssetManager_openDir(__assetManager, dirPath);
+    if (assetDir != NULL)
+    {
+        AAssetDir_rewind(assetDir);
+        const char* file = NULL;
+        while ((file = AAssetDir_getNextFileName(assetDir)) != NULL)
+        {
+            std::string filename(file);
+            // Check if this file was already added to the list because it was copied to the SD card.
+            if (find(files.begin(), files.end(), filename) == files.end())
+            {
+                files.push_back(filename);
+            }
+        }
+        AAssetDir_close(assetDir);
+        result = true;
+    }
+#endif
+
+    return result;
+#endif
+}
+
+bool FileSystem::fileExists(const char* filePath)
+{
+    GP_ASSERT(filePath);
+
+#ifdef __ANDROID__
+    if (androidFileExists(resolvePath(filePath)))
+    {
+        return true;
+    }
+#endif
+
+    std::string fullPath;
+    getFullPath(filePath, fullPath);
+
+    gp_stat_struct s;
+    return stat(fullPath.c_str(), &s) == 0;
+
+}
+
+Stream* FileSystem::open(const char* path, size_t mode)
+{
+    char modeStr[] = "rb";
+    if ((mode & WRITE) != 0)
+        modeStr[0] = 'w';
+#ifdef __ANDROID__
+    if ((mode & WRITE) != 0)
+    {
+        // Open a file on the SD card
+        std::string fullPath(__resourcePath);
+        fullPath += resolvePath(path);
+
+        size_t index = fullPath.rfind('/');
+        if (index != std::string::npos)
+        {
+            std::string directoryPath = fullPath.substr(0, index);
+            struct stat s;
+            if (stat(directoryPath.c_str(), &s) != 0)
+                makepath(directoryPath, 0777);
+        }
+        return FileStream::create(fullPath.c_str(), modeStr);
+    }
+    else
+    {
+        // Open a file in the read-only asset directory
+        return FileStreamAndroid::create(resolvePath(path), modeStr);
+    }
+#else
+    std::string fullPath;
+    getFullPath(path, fullPath);
+    FileStream* stream = FileStream::create(fullPath.c_str(), modeStr);
+    return stream;
+#endif
+}
+
+FILE* FileSystem::openFile(const char* filePath, const char* mode)
+{
+    GP_ASSERT(filePath);
+    GP_ASSERT(mode);
+
+    std::string fullPath;
+    getFullPath(filePath, fullPath);
+
+    createFileFromAsset(filePath);
+    
+    FILE* fp = fopen(fullPath.c_str(), mode);
+    return fp;
+}
+
+char* FileSystem::readAll(const char* filePath, int* fileSize)
+{
+    GP_ASSERT(filePath);
+
+    // Open file for reading.
+    std::auto_ptr<Stream> stream(open(filePath));
+    if (stream.get() == NULL)
+    {
+        GP_ERROR("Failed to load file: %s", filePath);
+        return NULL;
+    }
+    size_t size = stream->length();
+
+    // Read entire file contents.
+    char* buffer = new char[size + 1];
+    size_t read = stream->read(buffer, 1, size);
+    if (read != size)
+    {
+        GP_ERROR("Failed to read complete contents of file '%s' (amount read vs. file size: %u < %u).", filePath, read, size);
+        SAFE_DELETE_ARRAY(buffer);
+        return NULL;
+    }
+
+    // Force the character buffer to be NULL-terminated.
+    buffer[size] = '\0';
+
+    if (fileSize)
+    {
+        *fileSize = (int)size; 
+    }
+    return buffer;
+}
+
+bool FileSystem::isAbsolutePath(const char* filePath)
+{
+    if (filePath == 0 || filePath[0] == '\0')
+        return false;
+#ifdef WIN32
+    if (filePath[1] != '\0')
+    {
+        char first = filePath[0];
+        return (filePath[1] == ':' && ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')));
+    }
+    return false;
+#else
+    return filePath[0] == '/';
+#endif
+}
+
+void FileSystem::createFileFromAsset(const char* path)
+{
+#ifdef __ANDROID__
+    static std::set<std::string> upToDateAssets;
+
+    GP_ASSERT(path);
+    std::string fullPath(__resourcePath);
+    std::string resolvedPath = FileSystem::resolvePath(path);
+    fullPath += resolvedPath;
+
+    std::string directoryPath = fullPath.substr(0, fullPath.rfind('/'));
+    struct stat s;
+    if (stat(directoryPath.c_str(), &s) != 0)
+        makepath(directoryPath, 0777);
+
+    // To ensure that the files on the file system corresponding to the assets in the APK bundle
+    // are always up to date (and in sync), we copy them from the APK to the file system once
+    // for each time the process (game) runs.
+    if (upToDateAssets.find(fullPath) == upToDateAssets.end())
+    {
+        AAsset* asset = AAssetManager_open(__assetManager, resolvedPath.c_str(), AASSET_MODE_RANDOM);
+        if (asset)
+        {
+            const void* data = AAsset_getBuffer(asset);
+            int length = AAsset_getLength(asset);
+            FILE* file = fopen(fullPath.c_str(), "wb");
+            if (file != NULL)
+            {
+                int ret = fwrite(data, sizeof(unsigned char), length, file);
+                if (fclose(file) != 0)
+                {
+                    GP_ERROR("Failed to close file on file system created from APK asset '%s'.", path);
+                    return;
+                }
+                if (ret != length)
+                {
+                    GP_ERROR("Failed to write all data from APK asset '%s' to file on file system.", path);
+                    return;
+                }
+            }
+            else
+            {
+                GP_ERROR("Failed to create file on file system from APK asset '%s'.", path);
+                return;
+            }
+
+            upToDateAssets.insert(fullPath);
+        }
+    }
+#endif
+}
+
+std::string FileSystem::getDirectoryName(const char* path)
+{
+    if (path == NULL || strlen(path) == 0)
+    {
+        return "";
+    }
+#ifdef WIN32
+    char drive[_MAX_DRIVE];
+    char dir[_MAX_DIR];
+    _splitpath(path, drive, dir, NULL, NULL);
+    std::string dirname;
+    size_t driveLength = strlen(drive);
+    if (driveLength > 0)
+    {
+        dirname.reserve(driveLength + strlen(dir));
+        dirname.append(drive);
+        dirname.append(dir);
+    }
+    else
+    {
+        dirname.assign(dir);
+    }
+    std::replace(dirname.begin(), dirname.end(), '\\', '/');
+    return dirname;
+#else
+    // dirname() modifies the input string so create a temp string
+    std::string dirname;
+    char* tempPath = new char[strlen(path) + 1];
+    strcpy(tempPath, path);
+    char* dir = ::dirname(tempPath);
+    if (dir && strlen(dir) > 0)
+    {
+        dirname.assign(dir);
+        // dirname() strips off the trailing '/' so add it back to be consistent with Windows
+        dirname.append("/");
+    }
+    SAFE_DELETE_ARRAY(tempPath);
+    return dirname;
+#endif
+}
+
+std::string FileSystem::getExtension(const char* path)
+{
+    const char* str = strrchr(path, '.');
+    if (str == NULL)
+        return "";
+
+    std::string ext;
+    size_t len = strlen(str);
+    for (size_t i = 0; i < len; ++i)
+        ext += std::toupper(str[i]);
+
+    return ext;
+}
+
+//////////////////
+
+FileStream::FileStream(FILE* file)
+    : _file(file), _canRead(false), _canWrite(false)
+{
+    
+}
+
+FileStream::~FileStream()
+{
+    if (_file)
+    {
+        close();
+    }
+}
+
+FileStream* FileStream::create(const char* filePath, const char* mode)
+{
+    FILE* file = fopen(filePath, mode);
+    if (file)
+    {
+        FileStream* stream = new FileStream(file);
+        const char* s = mode;
+        while (s != NULL && *s != '\0')
+        {
+            if (*s == 'r')
+                stream->_canRead = true;
+            else if (*s == 'w')
+                stream->_canWrite = true;
+            ++s;
+        }
+
+        return stream;
+    }
+    return NULL;
+}
+
+bool FileStream::canRead()
+{
+    return _file && _canRead;
+}
+
+bool FileStream::canWrite()
+{
+    return _file && _canWrite;
+}
+
+bool FileStream::canSeek()
+{
+    return _file != NULL;
+}
+
+void FileStream::close()
+{
+    if (_file)
+        fclose(_file);
+    _file = NULL;
+}
+
+size_t FileStream::read(void* ptr, size_t size, size_t count)
+{
+    if (!_file)
+        return 0;
+    return fread(ptr, size, count, _file);
+}
+
+char* FileStream::readLine(char* str, int num)
+{
+    if (!_file)
+        return 0;
+    return fgets(str, num, _file);
+}
+
+size_t FileStream::write(const void* ptr, size_t size, size_t count)
+{
+    if (!_file)
+        return 0;
+    return fwrite(ptr, size, count, _file);
+}
+
+bool FileStream::eof()
+{
+    if (!_file || feof(_file))
+        return true;
+    return ((size_t)position()) >= length();
+}
+
+size_t FileStream::length()
+{
+    size_t len = 0;
+    if (canSeek())
+    {
+        long int pos = position();
+        if (seek(0, SEEK_END))
+        {
+            len = position();
+        }
+        seek(pos, SEEK_SET);
+    }
+    return len;
+}
+
+long int FileStream::position()
+{
+    if (!_file)
+        return -1;
+    return ftell(_file);
+}
+
+bool FileStream::seek(long int offset, int origin)
+{
+    if (!_file)
+        return false;
+    return fseek(_file, offset, origin) == 0;
+}
+
+bool FileStream::rewind()
+{
+    if (canSeek())
+    {
+        ::rewind(_file);
+        return true;
+    }
+    return false;
+}
+
+////////////////////////////////
+
+#ifdef __ANDROID__
+
+FileStreamAndroid::FileStreamAndroid(AAsset* asset)
+    : _asset(asset)
+{
+}
+
+FileStreamAndroid::~FileStreamAndroid()
+{
+    if (_asset)
+        close();
+}
+
+FileStreamAndroid* FileStreamAndroid::create(const char* filePath, const char* mode)
+{
+    AAsset* asset = AAssetManager_open(__assetManager, filePath, AASSET_MODE_RANDOM);
+    if (asset)
+    {
+        FileStreamAndroid* stream = new FileStreamAndroid(asset);
+        return stream;
+    }
+    return NULL;
+}
+
+bool FileStreamAndroid::canRead()
+{
+    return true;
+}
+
+bool FileStreamAndroid::canWrite()
+{
+    return false;
+}
+
+bool FileStreamAndroid::canSeek()
+{
+    return true;
+}
+
+void FileStreamAndroid::close()
+{
+    if (_asset)
+        AAsset_close(_asset);
+    _asset = NULL;
+}
+
+size_t FileStreamAndroid::read(void* ptr, size_t size, size_t count)
+{
+    int result = AAsset_read(_asset, ptr, size * count);
+    return result > 0 ? ((size_t)result) / size : 0;
+}
+
+char* FileStreamAndroid::readLine(char* str, int num)
+{
+    if (num <= 0)
+        return NULL;
+    char c = 0;
+    size_t maxCharsToRead = num - 1;
+    for (size_t i = 0; i < maxCharsToRead; ++i)
+    {
+        size_t result = read(&c, 1, 1);
+        if (result != 1)
+        {
+            str[i] = '\0';
+            break;
+        }
+        if (c == '\n')
+        {
+            str[i] = c;
+            str[i + 1] = '\0';
+            break;
+        }
+        else if(c == '\r')
+        {
+            str[i] = c;
+            // next may be '\n'
+            size_t pos = position();
+
+            char nextChar = 0;
+            if (read(&nextChar, 1, 1) != 1)
+            {
+                // no more characters
+                str[i + 1] = '\0';
+                break;
+            }
+            if (nextChar == '\n')
+            {
+                if (i == maxCharsToRead - 1)
+                {
+                    str[i + 1] = '\0';
+                    break;
+                }
+                else
+                {
+                    str[i + 1] = nextChar;
+                    str[i + 2] = '\0';
+                    break;
+                }
+            }
+            else
+            {
+                seek(pos, SEEK_SET);
+                str[i + 1] = '\0';
+                break;
+            }
+        }
+        str[i] = c;
+    }
+    return str; // what if first read failed?
+}
+
+size_t FileStreamAndroid::write(const void* ptr, size_t size, size_t count)
+{
+    return 0;
+}
+
+bool FileStreamAndroid::eof()
+{
+    return position() >= length();
+}
+
+size_t FileStreamAndroid::length()
+{
+    return (size_t)AAsset_getLength(_asset);
+}
+
+long int FileStreamAndroid::position()
+{
+    return AAsset_getLength(_asset) - AAsset_getRemainingLength(_asset);
+}
+
+bool FileStreamAndroid::seek(long int offset, int origin)
+{
+    return AAsset_seek(_asset, offset, origin) != -1;
+}
+
+bool FileStreamAndroid::rewind()
+{
+    if (canSeek())
+    {
+        return AAsset_seek(_asset, 0, SEEK_SET) != -1;
+    }
+    return false;
+}
+
+#endif
+
+}

+ 11 - 4
gameplay/src/Font.cpp

@@ -55,7 +55,7 @@ Font* Font::create(const char* path, const char* id)
     Bundle* bundle = Bundle::create(path);
     if (bundle == NULL)
     {
-        GP_ERROR("Failed to load font bundle '%s'.", path);
+        GP_WARN("Failed to load font bundle '%s'.", path);
         return NULL;
     }
 
@@ -66,7 +66,7 @@ Font* Font::create(const char* path, const char* id)
         const char* id;
         if ((id = bundle->getObjectId(0)) == NULL)
         {
-            GP_ERROR("Failed to load font without explicit id; the first object in the font bundle has a null id.");
+            GP_WARN("Failed to load font without explicit id; the first object in the font bundle has a null id.");
             return NULL;
         }
 
@@ -105,7 +105,7 @@ Font* Font::create(const char* family, Style style, unsigned int size, Glyph* gl
         __fontEffect = Effect::createFromFile(FONT_VSH, FONT_FSH, defines);
         if (__fontEffect == NULL)
         {
-            GP_ERROR("Failed to create effect for font.");
+            GP_WARN("Failed to create effect for font.");
             SAFE_RELEASE(texture);
             return NULL;
         }
@@ -123,7 +123,7 @@ Font* Font::create(const char* family, Style style, unsigned int size, Glyph* gl
 
     if (batch == NULL)
     {
-        GP_ERROR("Failed to create batch for font.");
+        GP_WARN("Failed to create batch for font.");
         return NULL;
     }
 
@@ -161,6 +161,13 @@ Font::Format Font::getFormat()
     return _format;
 }
 
+bool Font::isCharacterSupported(int character) const
+{
+    // TODO: Update this once we support unicode fonts
+    int glyphIndex = character - 32; // HACK for ASCII
+    return (glyphIndex >= 0 && glyphIndex < (int)_glyphCount);
+}
+
 void Font::start()
 {
     GP_ASSERT(_batch);

+ 10 - 2
gameplay/src/Font.h

@@ -114,7 +114,7 @@ public:
      * @param path The path to a bundle file containing a font resource.
      * @param id An optional ID of the font resource within the bundle (NULL for the first/only resource).
      * 
-     * @return The specified font.
+     * @return The specified Font or NULL if there was an error.
      * @script{create}
      */
     static Font* create(const char* path, const char* id = NULL);
@@ -129,6 +129,14 @@ public:
      */
     Format getFormat();
 
+    /**
+     * Determines if this font supports the specified character code.
+     *
+     * @param character The character code to check.
+     * @return True if this Font supports (can draw) the specified character, false otherwise.
+     */
+    bool isCharacterSupported(int character) const;
+
     /**
      * Starts text drawing for this font.
      */
@@ -343,7 +351,7 @@ private:
      * @param texture A texture map containing rendered glyphs.
      * @param format The format of the font (bitmap or distance fields)
      * 
-     * @return The new Font.
+     * @return The new Font or NULL if there was an error.
      */
     static Font* create(const char* family, Style style, unsigned int size, Glyph* glyphs, int glyphCount, Texture* texture, Font::Format format);
 

+ 682 - 157
gameplay/src/Form.cpp

@@ -14,14 +14,25 @@
 #define FORM_VSH "res/shaders/form.vert"
 #define FORM_FSH "res/shaders/form.frag"
 
+// Scroll speed when using a DPad -- max scroll speed when using a joystick.
+static const float GAMEPAD_SCROLL_SPEED = 500.0f;
+// Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
+static const float JOYSTICK_THRESHOLD = 0.75f;
+// If the DPad or joystick is held down, this is the initial delay in milliseconds between focus changes.
+static const float GAMEPAD_FOCUS_REPEAT_DELAY = 300.0f;
+
 namespace gameplay
 {
 
 static Effect* __formEffect = NULL;
 static std::vector<Form*> __forms;
+Control* Form::_focusControl = NULL;
+Control* Form::_activeControl = NULL;
+Control::State Form::_activeControlState = Control::NORMAL;
+static bool _shiftKeyDown = false;
 
 Form::Form() : _theme(NULL), _frameBuffer(NULL), _spriteBatch(NULL), _node(NULL),
-    _nodeQuad(NULL), _nodeMaterial(NULL) , _u2(0), _v1(0), _isGamepad(false)
+    _nodeQuad(NULL), _nodeMaterial(NULL) , _u2(0), _v1(0)
 {
 }
 
@@ -104,97 +115,37 @@ Form* Form::create(const char* url)
         return NULL;
     }
 
-    // Create new form with given ID, theme and layout.
+    // Parse theme
     std::string themeFile;
     formProperties->getPath("theme", &themeFile);
-
-    // Parse layout
-    Layout* layout = NULL;
-    Properties* layoutNS = formProperties->getNamespace("layout", true, false);
-    if (layoutNS)
-    {
-        Layout::Type layoutType = getLayoutType(layoutNS->getString("type"));
-        switch (layoutType)
-        {
-        case Layout::LAYOUT_ABSOLUTE:
-            layout = AbsoluteLayout::create();
-            break;
-        case Layout::LAYOUT_FLOW:
-            layout = FlowLayout::create();
-            static_cast<FlowLayout*>(layout)->setSpacing(layoutNS->getInt("horizontalSpacing"), layoutNS->getInt("verticalSpacing"));
-            break;
-        case Layout::LAYOUT_VERTICAL:
-            layout = VerticalLayout::create();
-            static_cast<VerticalLayout*>(layout)->setSpacing(layoutNS->getInt("spacing"));
-            break;
-        }
-    }
-    else
-    {
-        switch (getLayoutType(formProperties->getString("layout")))
-        {
-        case Layout::LAYOUT_ABSOLUTE:
-            layout = AbsoluteLayout::create();
-            break;
-        case Layout::LAYOUT_FLOW:
-            layout = FlowLayout::create();
-            break;
-        case Layout::LAYOUT_VERTICAL:
-            layout = VerticalLayout::create();
-            break;
-        }
-    }
-    if (layout == NULL)
-    {
-        GP_ERROR("Unsupported layout type for form: %s", url);
-    }
-
     Theme* theme = Theme::create(themeFile.c_str());
     GP_ASSERT(theme);
 
+    // Parse style
+    const char* styleName = formProperties->getString("style");
+    Theme::Style* style = styleName ? theme->getStyle(styleName) : theme->getEmptyStyle();
+
+    // Create new form
     Form* form = new Form();
-    form->_layout = layout;
     form->_theme = theme;
 
-    Theme::Style* style = NULL;
-    const char* styleName = formProperties->getString("style");
-    if (styleName)
-    {
-        style = theme->getStyle(styleName);
-    }
-    else
-    {
-        style = theme->getEmptyStyle();
-    }
+    // Initialize common container properties
     form->initialize(style, formProperties);
 
-    form->_consumeInputEvents = formProperties->getBool("consumeInputEvents", false);
-
-    form->_scroll = getScroll(formProperties->getString("scroll"));
-    form->_scrollBarsAutoHide = formProperties->getBool("scrollBarsAutoHide");
-    if (form->_scrollBarsAutoHide)
-    {
-        form->_scrollBarOpacity = 0.0f;
-    }
-
-    // Add all the controls to the form.
-    form->addControls(theme, formProperties);
-
-    SAFE_DELETE(properties);
-    
     form->updateFrameBuffer();
 
     __forms.push_back(form);
 
+    SAFE_DELETE(properties);
+
     return form;
 }
 
 Form* Form::getForm(const char* id)
 {
-    std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); ++it)
+    for (size_t i = 0, size = __forms.size(); i < size; ++i)
     {
-        Form* f = *it;
+        Form* f = __forms[i];
         GP_ASSERT(f);
         if (strcmp(id, f->getId()) == 0)
         {
@@ -204,6 +155,21 @@ Form* Form::getForm(const char* id)
     return NULL;
 }
 
+Control* Form::getFocusControl()
+{
+    return _focusControl;
+}
+
+void Form::clearFocus()
+{
+    setFocusControl(NULL);
+}
+
+bool Form::isForm() const
+{
+    return true;
+}
+
 Theme* Form::getTheme() const
 {
     return _theme;
@@ -350,13 +316,15 @@ void Form::setNode(Node* node)
 
 void Form::update(float elapsedTime)
 {
-    if (true)//isDirty())
+    if (isDirty())
     {
         update(NULL, Vector2::zero());
 
+        Control::State state = getState();
+
         // Cache themed attributes for performance.
-        _skin = getSkin(_state);
-        _opacity = getOpacity(_state);
+        _skin = getSkin(state);
+        _opacity = getOpacity(state);
 
         GP_ASSERT(_layout);
         if (_scroll != SCROLL_NONE)
@@ -375,10 +343,10 @@ void Form::update(const Control* container, const Vector2& offset)
     // Store previous absolute bounds
     Rectangle oldAbsoluteClipBounds = _absoluteClipBounds;
 
-    _layout->align(this, NULL);
-
     Container::update(container, offset);
 
+    _layout->align(this, NULL);
+
     if (_absoluteClipBounds.width != oldAbsoluteClipBounds.width || _absoluteClipBounds.height != oldAbsoluteClipBounds.height)
     {
         updateFrameBuffer();
@@ -399,7 +367,7 @@ unsigned int Form::draw()
     // to render the contents of the framebuffer directly to the display.
 
     // Check whether this form has changed since the last call to draw() and if so, render into the framebuffer.
-    if (true)//isDirty())
+    if (isDirty())
     {
         FrameBuffer* previousFrameBuffer = _frameBuffer->bind();
 
@@ -443,162 +411,642 @@ const char* Form::getType() const
     return "form";
 }
 
+Control* Form::getActiveControl()
+{
+    return _activeControl;
+}
+
 void Form::updateInternal(float elapsedTime)
 {
-    size_t size = __forms.size();
-    for (size_t i = 0; i < size; ++i)
+    pollGamepads();
+
+    for (size_t i = 0, size = __forms.size(); i < size; ++i)
     {
         Form* form = __forms[i];
-        GP_ASSERT(form);
 
-        if (form->isEnabled() && form->isVisible())
+        if (form && form->isEnabled() && form->isVisible())
         {
             form->update(elapsedTime);
         }
     }
 }
 
-static bool shouldPropagateTouchEvent(Control::State state, Touch::TouchEvent evt, const Rectangle& bounds, int x, int y)
+bool Form::screenToForm(Control* ctrl, int* x, int* y)
 {
-    return (state != Control::NORMAL ||
-            (evt == Touch::TOUCH_PRESS &&
-             x >= bounds.x &&
-             x <= bounds.x + bounds.width &&
-             y >= bounds.y &&
-             y <= bounds.y + bounds.height));
+    Form* form = ctrl->getTopLevelForm();
+    if (form)
+    {
+        if (form->_node)
+        {
+            // Form is attached to a scene node, so project the screen space point into the
+            // form's coordinate space (which may be transformed by the node).
+            Vector3 point;
+            if (form->projectPoint(*x, *y, &point))
+            {
+                *x = (int)point.x;
+                *y = form->_bounds.height - (int)point.y;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        *x -= form->_bounds.x;
+        *y -= form->_bounds.y;
+
+        return true;
+    }
+
+    return false;
 }
 
-bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+Control* Form::findInputControl(int* x, int* y, bool focus)
 {
-    // Check for a collision with each Form in __forms.
-    // Pass the event on.
-    size_t size = __forms.size();
-    for (size_t i = 0; i < size; ++i)
+    for (int i = (int)__forms.size() - 1; i >= 0; --i)
     {
         Form* form = __forms[i];
-        GP_ASSERT(form);
+        if (!form || !form->isEnabled() || !form->isVisible())
+            continue;
+
+        // Convert to local form coordinates
+        int formX = *x;
+        int formY = *y;
+        if (!screenToForm(form, &formX, &formY))
+            continue;
+
+        // Search for an input control within this form
+        Control* ctrl = findInputControl(form, formX, formY, focus);
+        if (ctrl)
+        {
+            *x = formX;
+            *y = formY;
+            return ctrl;
+        }
+
+        // If the form consumes input events and the point intersects the form,
+        // don't traverse other forms below it.
+        if (form->_consumeInputEvents && form->_absoluteClipBounds.contains(formX, formY))
+            return NULL;
+    }
+
+    return NULL;
+}
+
+Control* Form::findInputControl(Control* control, int x, int y, bool focus)
+{
+    Control* result = NULL;
 
-        if (form->isEnabled() && form->isVisible())
+    // Does the passed in control's bounds intersect the specified coordinates - and 
+    // does the control support the specified input state?
+    if (control->_consumeInputEvents && control->_visible && control->_enabled && (!focus || control->canFocus()))
+    {
+        if (control->_absoluteClipBounds.contains(x, y))
+            result = control;
+    }
+
+    // If the control has children, search for an input control inside it that also
+    // supports the above conditions.
+    if (control->isContainer())
+    {
+        Container* container = static_cast<Container*>(control);
+        for (int i = (int)container->getControlCount() - 1; i >= 0; --i)
         {
-            if (form->_node)
+            Control* ctrl = findInputControl(container->getControl((unsigned int)i), x, y, focus);
+            if (ctrl)
+                result = ctrl;
+        }
+    }
+
+    return result;
+}
+
+Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
+{
+    Control* ctrl = NULL;
+
+    int newX = *x;
+    int newY = *y;
+
+    if (pressed)
+    {
+        // Update active state changes
+        if ((ctrl = findInputControl(&newX, &newY, false)) != NULL)
+        {
+            if (_activeControl != ctrl || _activeControlState != Control::ACTIVE)
             {
-                Vector3 point;
-                if (form->projectPoint(x, y, &point))
+                if (_activeControl)
+                    _activeControl->_dirty = true;
+
+                _activeControl = ctrl;
+                _activeControlState = Control::ACTIVE;
+                _activeControl->_dirty = true;
+            }
+
+            ctrl->notifyListeners(Control::Listener::PRESS);
+        }
+    }
+    else // !pressed
+    {
+        Control* active = _activeControlState == Control::ACTIVE ? _activeControl : NULL;
+
+        if (active)
+        {
+            active->addRef(); // protect against event-hanlder evil
+
+            // Release happened for the active control (that was pressed)
+            ctrl = active;
+
+            // Transform point to form-space
+            screenToForm(ctrl, &newX, &newY);
+
+            // No longer any active control
+            _activeControl->_dirty = true;
+            _activeControl = NULL;
+            _activeControlState = Control::NORMAL;
+        }
+        else
+        {
+            // Update active and hover control state on release
+            Control* inputControl = findInputControl(&newX, &newY, false);
+            if (inputControl)
+            {
+                ctrl = inputControl;
+
+                if (_activeControl != ctrl || _activeControlState != Control::HOVER)
                 {
-                    const Rectangle& bounds = form->getBounds();
-                    if (shouldPropagateTouchEvent(form->getState(), evt, bounds, point.x, point.y))
-                    {
-                        if (form->touchEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, contactIndex))
-                            return true;
-                    }
+                    if (_activeControl)
+                        _activeControl->_dirty = true;
+
+                    _activeControl = ctrl;
+                    _activeControlState = Control::HOVER;
+                    _activeControl->_dirty = true;
                 }
             }
             else
             {
-                // Simply compare with the form's bounds.
-                const Rectangle& bounds = form->getBounds();
-                if (shouldPropagateTouchEvent(form->getState(), evt, bounds, x, y))
+                // No longer any active control
+                if (_activeControl)
+                    _activeControl->_dirty = true;
+
+                _activeControl = NULL;
+                _activeControlState = Control::NORMAL;
+            }
+        }
+
+        if (active)
+        {
+            // Fire release event for the previously active control
+            active->notifyListeners(Control::Listener::RELEASE);
+
+            // If the release event was received on the same control that was
+            // originally pressed, fire a click event
+            if (active->_absoluteClipBounds.contains(newX, newY))
+            {
+                if (!active->_parent || !active->_parent->isScrolling())
                 {
-                    // Pass on the event's position relative to the form.
-                    if (form->touchEvent(evt, x - bounds.x, y - bounds.y, contactIndex))
-                        return true;
+                    active->notifyListeners(Control::Listener::CLICK);
                 }
             }
+
+            active->release();
         }
     }
-    return false;
+
+    *x = newX;
+    *y = newY;
+
+    return ctrl;
 }
 
-bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
+Control* Form::handlePointerMove(int* x, int* y)
 {
-    size_t size = __forms.size();
-    for (size_t i = 0; i < size; ++i)
+    Control* ctrl = NULL;
+
+    // Handle hover control changes on move, only if there is no currently active control
+    // (i.e. when the mouse or a finger is not down).
+    if (_activeControl && (_activeControlState == Control::ACTIVE))
     {
-        Form* form = __forms[i];
-        GP_ASSERT(form);
-        if (form->isEnabled() && form->isVisible() && form->hasFocus() && !form->_isGamepad)
+        ctrl = _activeControl;
+        screenToForm(ctrl, x, y);
+    }
+    else
+    {
+        ctrl = findInputControl(x, y, false);
+        if (ctrl)
         {
-            if (form->keyEvent(evt, key))
-                return true;
+            // Update hover control
+            if (_activeControl != ctrl || _activeControlState != Control::HOVER)
+            {
+                if (_activeControl)
+                    _activeControl->_dirty = true;
+
+                _activeControl = ctrl;
+                _activeControlState = Control::HOVER;
+                _activeControl->_dirty = true;
+            }
+        }
+        else
+        {
+            // No active/hover control
+            if (_activeControl)
+                _activeControl->_dirty = true;
+
+            _activeControl = NULL;
+            _activeControlState = Control::NORMAL;
         }
     }
-    return false;
+
+    return ctrl;
 }
 
-static bool shouldPropagateMouseEvent(Control::State state, Mouse::MouseEvent evt, const Rectangle& bounds, int x, int y)
+void Form::verifyRemovedControlState(Control* control)
 {
-    return (state != Control::NORMAL ||
-            ((evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
-              evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
-              evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON ||
-              evt == Mouse::MOUSE_MOVE ||
-              evt == Mouse::MOUSE_WHEEL) &&
-                x >= bounds.x &&
-                x <= bounds.x + bounds.width &&
-                y >= bounds.y &&
-                y <= bounds.y + bounds.height));
+    if (_focusControl == control)
+        _focusControl = NULL;
+
+    if (_activeControl == control)
+    {
+        _activeControl = NULL;
+        _activeControlState = Control::NORMAL;
+    }
 }
 
-bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+// Generic pointer event handler that both touch and mouse events map to.
+// Mappings:
+//   mouse - true for mouse events, false for touch events
+//   evt - Mouse::MouseEvent or Touch::TouchEvent
+//   x, y - Point of event
+//   param - wheelData for mouse events, contactIndex for touch events
+bool Form::pointerEventInternal(bool mouse, int evt, int x, int y, int param)
 {
     // Do not process mouse input when mouse is captured
-    if (Game::getInstance()->isMouseCaptured())
+    if (mouse && Game::getInstance()->isMouseCaptured())
         return false;
 
-    for (size_t i = 0; i < __forms.size(); ++i)
+    // Is this a press event (TOUCH_PRESS has the same value as MOUSE_PRESS_LEFT_BUTTON)
+    bool pressEvent = evt == Touch::TOUCH_PRESS || (mouse && (evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON || evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON));
+
+    Control* ctrl = NULL;
+    int formX = x;
+    int formY = y;
+
+    if (mouse || (param == 0))
     {
-        Form* form = __forms[i];
-        GP_ASSERT(form);
+        // Note: TOUCH_PRESS and TOUCH_RELEASE have same values as MOUSE_PRESS_LEFT_BUTTON and MOUSE_RELEASE_LEFT_BUTTON
+        if (evt == Touch::TOUCH_PRESS)
+        {
+            ctrl = handlePointerPressRelease(&formX, &formY, true);
+        }
+        else if (evt == Touch::TOUCH_RELEASE)
+        {
+            ctrl = handlePointerPressRelease(&formX, &formY, false);
+        }
+        else if ((mouse && evt == Mouse::MOUSE_MOVE) || (!mouse && evt == Touch::TOUCH_MOVE))
+        {
+            ctrl = handlePointerMove(&formX, &formY);
+        }
+    }
 
-        if (form->isEnabled() && form->isVisible())
+    // Dispatch input events to all controls that intersect this point
+    if (ctrl == NULL)
+    {
+        formX = x;
+        formY = y;
+        ctrl = findInputControl(&formX, &formY, false);
+    }
+
+    if (ctrl)
+    {
+        // Handle container scrolling
+        Control* tmp = ctrl;
+        while (tmp)
         {
-            if (form->_node)
+            if (tmp->isContainer())
             {
-                Vector3 point;
-                if (form->projectPoint(x, y, &point))
+                Container* container = static_cast<Container*>(tmp);
+                if (container->_scroll != SCROLL_NONE)
                 {
-                    const Rectangle& bounds = form->getBounds();
-                    if (shouldPropagateMouseEvent(form->getState(), evt, bounds, point.x, point.y))
+                    if (mouse)
+                    {
+                        if (container->mouseEventScroll((Mouse::MouseEvent)evt, formX - tmp->_absoluteBounds.x, formY - tmp->_absoluteBounds.y, param))
+                            return true;
+                    }
+                    else
                     {
-                        if (form->mouseEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, wheelDelta))
+                        if (container->touchEventScroll((Touch::TouchEvent)evt, formX - tmp->_absoluteBounds.x, formY - tmp->_absoluteBounds.y, param))
                             return true;
                     }
+                    break; // scrollable parent container found
+                }
+            }
+            tmp = tmp->_parent;
+        }
+
+        // Handle setting focus for all press events
+        if (pressEvent)
+        {
+            Control* focusControl = ctrl;
+            while (focusControl && !focusControl->setFocus())
+                focusControl = focusControl->_parent;
+
+            if (focusControl == NULL)
+            {
+                // Nothing got focus on this press, so remove current focused control
+                setFocusControl(NULL);
+            }
+        }
+
+        // Dispatch the event from the bottom upwards, until a control intersecting the point consumes the event
+        while (ctrl)
+        {
+            int localX = formX - ctrl->_absoluteBounds.x;
+            int localY = formY - ctrl->_absoluteBounds.y;
+            if (mouse)
+            {
+                if (ctrl->mouseEvent((Mouse::MouseEvent)evt, localX, localY, param))
+                    return true;
+
+                // Forward to touch event hanlder if unhandled by mouse handler
+                switch (evt)
+                {
+                case Mouse::MOUSE_PRESS_LEFT_BUTTON:
+                    if (ctrl->touchEvent(Touch::TOUCH_PRESS, localX, localY, 0))
+                        return true;
+                    break;
+                case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
+                    if (ctrl->touchEvent(Touch::TOUCH_RELEASE, localX, localY, 0))
+                        return true;
+                    break;
+                case Mouse::MOUSE_MOVE:
+                    if (ctrl->touchEvent(Touch::TOUCH_MOVE, localX, localY, 0))
+                        return true;
+                    break;
                 }
             }
             else
             {
-                // Simply compare with the form's bounds.
-                const Rectangle& bounds = form->getBounds();
-                if (shouldPropagateMouseEvent(form->getState(), evt, bounds, x, y))
+                if (ctrl->touchEvent((Touch::TouchEvent)evt, localX, localY, param))
+                    return true;
+            }
+
+            // Consume all input events anyways?
+            if (ctrl->getConsumeInputEvents())
+                return true;
+
+            ctrl = ctrl->getParent();
+        }
+    }
+    else
+    {
+        // If this was a press event, remove all focus
+        if (pressEvent)
+        {
+            setFocusControl(NULL);
+        }
+    }
+
+    return false;
+}
+
+bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    return pointerEventInternal(false, evt, x, y, (int)contactIndex);
+}
+
+bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+{
+    return pointerEventInternal(true, evt, x, y, wheelDelta);
+}
+
+bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
+{
+    switch (key)
+    {
+    case Keyboard::KEY_ESCAPE:
+        return false; // ignore escape key presses
+
+    case Keyboard::KEY_SHIFT:
+        if (evt == Keyboard::KEY_PRESS)
+            _shiftKeyDown = true;
+        else if (evt == Keyboard::KEY_RELEASE)
+            _shiftKeyDown = false;
+        break;
+    }
+    if (key == Keyboard::KEY_ESCAPE)
+        return false;
+
+    // Handle focus changing
+    if (_focusControl)
+    {
+        switch (evt)
+        {
+        case Keyboard::KEY_CHAR:
+            switch (key)
+            {
+            case Keyboard::KEY_TAB:
+                if (_focusControl->_parent)
                 {
-                    // Pass on the event's position relative to the form.
-                    if (form->mouseEvent(evt, x - bounds.x, y - bounds.y, wheelDelta))
+                    if (_focusControl->_parent->moveFocus(_shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
                         return true;
                 }
+                break;
             }
+            break;
         }
     }
+
+    // Dispatch key events
+    Control* ctrl = _focusControl;
+    while (ctrl)
+    {
+        if (ctrl->isEnabled() && ctrl->isVisible())
+        {
+            if (ctrl->keyEvent(evt, key))
+                return true;
+        }
+
+        ctrl = ctrl->getParent();
+    }
+
     return false;
 }
 
-void Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
+void Form::pollGamepads()
+{
+    Game* game = Game::getInstance();
+
+    // If no gamepads are connected, return immediately
+    unsigned int gamepadCount = game->getGamepadCount();
+    if (gamepadCount == 0)
+        return;
+
+    // For now, always use gamepad zero for controlling the UI.
+    // Possibly allow the developer to set the active gamepad for UI later.
+    Gamepad* gamepad = game->getGamepad(0, true);
+    if (!gamepad)
+        return;
+
+    pollGamepad(gamepad);
+}
+
+bool Form::pollGamepad(Gamepad* gamepad)
 {
-    for (size_t i = 0; i < __forms.size(); ++i)
+    // Get the currently focused control's container for focus management and scrolling
+    if (!_focusControl)
+        return false;
+
+    // Get parent container
+    Container* parentContainer = NULL;
+    if (_focusControl->_parent)
+        parentContainer = _focusControl->_parent;
+
+    // Get scroll container
+    Container* scrollContainer = NULL;
+    if (_focusControl->isContainer())
     {
-        Form* form = __forms[i];
-        GP_ASSERT(form);
+        scrollContainer = static_cast<Container*>(_focusControl);
+        if (scrollContainer->_scroll == SCROLL_NONE)
+            scrollContainer = NULL;
+    }
+    if (!scrollContainer && parentContainer && parentContainer->_scroll != SCROLL_NONE)
+        scrollContainer = parentContainer;
+
+    // Static static maintained across function calls
+    static bool scrolling = false;
+    static double lastFocusChangeTime = 0;
+
+    bool focusPressed = false;
+    bool stillScrolling = false;
+    double currentTime = Game::getAbsoluteTime();
+    double focusChangeElapsedTime = currentTime - lastFocusChangeTime;
+
+    // Is a selection button down (i.e. buttons used for UI clicking/interactions)?
+    bool selectButtonDown = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
+
+    if (!selectButtonDown)
+    {
+        // Get values of analog joysticks 1 and 2 (assume left and right analog sticks)
+        Vector2 joystick;
+        unsigned int joystickCount = gamepad->getJoystickCount();
+        gamepad->getJoystickValues(0, &joystick);
+
+        if (parentContainer)
+        {
+            // The Dpad and left analog stick (i.e. first analog stick when there are two joysticks) controls focus
+            if (gamepad->isButtonDown(Gamepad::BUTTON_UP) || (joystickCount > 1 && joystick.y > JOYSTICK_THRESHOLD))
+            {
+                focusPressed = true;
+                if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(UP))
+                {
+                    lastFocusChangeTime = currentTime;
+                }
+            }
+
+            if (gamepad->isButtonDown(Gamepad::BUTTON_DOWN) || (joystickCount > 1 && joystick.y < -JOYSTICK_THRESHOLD))
+            {
+                focusPressed = true;
+                if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(DOWN))
+                {
+                    lastFocusChangeTime = currentTime;
+                }
+            }
+
+            if (gamepad->isButtonDown(Gamepad::BUTTON_LEFT) || (joystickCount > 1 && joystick.x < -JOYSTICK_THRESHOLD))
+            {
+                focusPressed = true;
+                if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(LEFT))
+                {
+                    lastFocusChangeTime = currentTime;
+                }
+            }
+
+            if (gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) || (joystickCount > 1 && joystick.x > JOYSTICK_THRESHOLD))
+            {
+                focusPressed = true;
+                if (focusChangeElapsedTime > GAMEPAD_FOCUS_REPEAT_DELAY && parentContainer->moveFocus(RIGHT))
+                {
+                    lastFocusChangeTime = currentTime;
+                }
+            }
+        }
+
+        // The RIGHT analog stick (i.e. second), or ONLY analog stick (when only 1 joystick), is used to scroll.
+        if (scrollContainer && joystickCount > 0)
+        {
+            if (joystickCount > 1)
+                gamepad->getJoystickValues(1, &joystick);
+            if (std::fabs(joystick.x) > JOYSTICK_THRESHOLD || std::fabs(joystick.y) > JOYSTICK_THRESHOLD)
+            {
+                scrollContainer->startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, !scrolling);
+                scrolling = stillScrolling = true;
+            }
+        }
+    }
+
+    if (!focusPressed)
+    {
+        // Reset focus repeat
+        lastFocusChangeTime = 0;
+    }
 
-        if (form->isEnabled() && form->isVisible() && form->hasFocus())
+    if (scrolling && !stillScrolling)
+    {
+        scrolling = false;
+        if (scrollContainer)
+            scrollContainer->stopScrolling();
+    }
+
+    return focusPressed || scrolling;
+}
+
+bool Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
+{
+    if (!_focusControl)
+        return false;
+
+    bool selectButtonPressed = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
+
+    // Fire press, release and click events to focused controls
+    switch (evt)
+    {
+    case Gamepad::BUTTON_EVENT:
+        if (selectButtonPressed && (_activeControl != _focusControl || _activeControlState != Control::ACTIVE))
+        {
+            _activeControl = _focusControl;
+            _activeControlState = Control::ACTIVE;
+            _activeControl->notifyListeners(Control::Listener::PRESS);
+            return true;
+        }
+        else if (!selectButtonPressed && _activeControl == _focusControl && _activeControlState == Control::ACTIVE)
+        {
+            _activeControlState = Control::NORMAL;
+            _activeControl->notifyListeners(Control::Listener::RELEASE);
+            _activeControl->notifyListeners(Control::Listener::CLICK);
+            return true;
+        }
+        break;
+    }
+
+    // Dispatch gamepad events to focused controls (or their parents)
+    Control * ctrl = _focusControl;
+    while (ctrl)
+    {
+        if (ctrl->isEnabled() && ctrl->isVisible())
         {
-            if (form->gamepadEvent(evt, gamepad, analogIndex))
-                return;
+            if (ctrl->gamepadEvent(evt, gamepad, analogIndex))
+                return true;
         }
+
+        ctrl = ctrl->getParent();
     }
+
+    return false;
 }
 
 void Form::resizeEventInternal(unsigned int width, unsigned int height)
 {
-    for (size_t i = 0; i < __forms.size(); ++i)
+    for (size_t i = 0, size = __forms.size(); i < size; ++i)
     {
         Form* form = __forms[i];
         if (form)
@@ -619,6 +1067,9 @@ void Form::resizeEventInternal(unsigned int width, unsigned int height)
 
 bool Form::projectPoint(int x, int y, Vector3* point)
 {
+    if (!_node)
+        return false;
+
     Scene* scene = _node->getScene();
     Camera* camera;
 
@@ -676,4 +1127,78 @@ unsigned int Form::nextPowerOfTwo(unsigned int v)
     }
 }
 
+void Form::controlDisabled(Control* control)
+{
+    if (Form::_focusControl && (Form::_focusControl == control || Form::_focusControl->isChild(control)))
+    {
+        setFocusControl(NULL);
+    }
+
+    if (Form::_activeControl)
+    {
+        if (Form::_activeControl == control || Form::_activeControl->isChild(control))
+        {
+            Form::_activeControl = NULL;
+            Form::_activeControlState = Control::NORMAL;
+        }
+    }
+}
+
+void Form::setFocusControl(Control* control)
+{
+    Control* oldFocus = _focusControl;
+
+    _focusControl = control;
+
+    // Deactivate the old focus control
+    if (oldFocus)
+    {
+        oldFocus->_dirty = true;
+        oldFocus->notifyListeners(Control::Listener::FOCUS_LOST);
+    }
+
+    // Activate the new focus control
+    if (_focusControl)
+    {
+        _focusControl->_dirty = true;
+        _focusControl->notifyListeners(Control::Listener::FOCUS_GAINED);
+
+        // Set the activeControl property of the control's parent container
+        Container* parent = NULL;
+        if (_focusControl->_parent)
+        {
+            parent = _focusControl->_parent;
+            parent->_activeControl = _focusControl;
+        }
+
+        // If this control is inside a scrollable container and is not fully visible,
+        // scroll the container so that it is.
+        if (parent && parent->_scroll != SCROLL_NONE && !parent->_viewportBounds.isEmpty())
+        {
+            const Rectangle& bounds = _focusControl->getBounds();
+            if (bounds.x < parent->_scrollPosition.x)
+            {
+                // Control is to the left of the scrolled viewport.
+                parent->_scrollPosition.x = -bounds.x;
+            }
+            else if (bounds.x + bounds.width > parent->_scrollPosition.x + parent->_viewportBounds.width)
+            {
+                // Control is off to the right.
+                parent->_scrollPosition.x = -(bounds.x + bounds.width - parent->_viewportBounds.width);
+            }
+
+            if (bounds.y < parent->_viewportBounds.y - parent->_scrollPosition.y)
+            {
+                // Control is above the viewport.
+                parent->_scrollPosition.y = -bounds.y;
+            }
+            else if (bounds.y + bounds.height > parent->_viewportBounds.height - parent->_scrollPosition.y)
+            {
+                // Control is below the viewport.
+                parent->_scrollPosition.y = -(bounds.y + bounds.height - parent->_viewportBounds.height);
+            }
+        }
+    }
+}
+
 }

+ 52 - 2
gameplay/src/Form.h

@@ -51,6 +51,8 @@ class Form : public Container
     friend class Platform;
     friend class Game;
     friend class Gamepad;
+    friend class Control;
+    friend class Container;
 
 public:
 
@@ -85,6 +87,23 @@ public:
      */
     static Form* getForm(const char* id);
     
+    /**
+     * Returns the current UI control that is in focus.
+     *
+     * @return The current control in focus, or NULL if no controls are in focus.
+     */
+    static Control* getFocusControl();
+
+    /**
+     * Removes focus from any currently focused UI control.
+     */
+    static void clearFocus();
+
+    /**
+     * @see Container#isForm()
+     */
+    bool isForm() const;
+
     /**
      * Gets the theme for the form.
      *
@@ -119,6 +138,13 @@ public:
      */
     const char* getType() const;
 
+    /**
+     * Returns the single currently active control within the UI system.
+     *
+     * @return The currently active control, or NULL if no controls are currently active.
+     */
+    static Control* getActiveControl();
+
 protected:
 
     /**
@@ -183,7 +209,7 @@ private:
      *
      * @see Control::gamepadEvent
      */
-    static void gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
+    static bool gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
 
     /**
      * Fired by the platform when the game window resizes.
@@ -218,6 +244,28 @@ private:
      */
     void updateFrameBuffer();
 
+    static bool pointerEventInternal(bool mouse, int evt, int x, int y, int param);
+
+    static Control* findInputControl(int* x, int* y, bool focus);
+
+    static Control* findInputControl(Control* control, int x, int y, bool focus);
+
+    static Control* handlePointerPressRelease(int* x, int* y, bool pressed);
+
+    static Control* handlePointerMove(int* x, int* y);
+
+    static bool screenToForm(Control* ctrl, int* x, int* y);
+
+    static void verifyRemovedControlState(Control* control);
+
+    static void controlDisabled(Control* control);
+
+    static void setFocusControl(Control* control);
+
+    static void pollGamepads();
+
+    static bool pollGamepad(Gamepad* gamepad);
+
     Theme* _theme;                      // The Theme applied to this Form.
     FrameBuffer* _frameBuffer;          // FBO the Form is rendered into for texturing the quad. 
     SpriteBatch* _spriteBatch;
@@ -227,7 +275,9 @@ private:
     float _u2;
     float _v1;
     Matrix _projectionMatrix;           // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
-    bool _isGamepad;
+    static Control* _focusControl;
+    static Control* _activeControl;
+    static Control::State _activeControlState;
 };
 
 }

+ 14 - 14
gameplay/src/FrameBuffer.h

@@ -13,11 +13,11 @@ namespace gameplay
  * Defines a frame buffer object that may contain one or more render targets and optionally
  * a depth-stencil target.
  *
- * Frame buffers can be created and used for off-screen rendering, which is useful for 
+ * Frame buffers can be created and used for off-screen rendering, which is useful for
  * techniques such as shadow mapping and post-processing. Render targets within a frame
  * buffer can be both written to and read (by calling RenderTarget::getTexture).
  *
- * When binding a custom frame buffer, you should always store the return value of 
+ * When binding a custom frame buffer, you should always store the return value of
  * FrameBuffer::bind and restore it when you are finished drawing to your frame buffer.
  *
  * To bind the default frame buffer, call FrameBuffer::bindDefault.
@@ -97,7 +97,7 @@ public:
      * @return The number of color attachments available on the current hardware.
      */
     static unsigned int getMaxRenderTargets();
- 
+
     /**
      * Set a RenderTarget on this FrameBuffer's color attachment at the specified index.
      *
@@ -105,7 +105,7 @@ public:
      * @param index The index of the color attachment to set.
      */
     void setRenderTarget(RenderTarget* target, unsigned int index = 0);
- 
+
     /**
      * Get the RenderTarget attached to the FrameBuffer's color attachment at the specified index.
      *
@@ -121,30 +121,30 @@ public:
      * @return The number of render targets attached.
      */
     unsigned int getRenderTargetCount() const;
- 
+
     /**
      * Set this FrameBuffer's DepthStencilTarget.
      *
      * @param target The DepthStencilTarget to set on this FrameBuffer.
      */
     void setDepthStencilTarget(DepthStencilTarget* target);
-  
+
     /**
      * Get this FrameBuffer's DepthStencilTarget.
      *
      * @return This FrameBuffer's DepthStencilTarget.
      */
     DepthStencilTarget* getDepthStencilTarget() const;
- 
+
     /**
-     * Determines whether this is the default frame bufffer.
+     * Determines whether this is the default frame buffer.
      *
      * @return true if this is the default frame buffer, false otherwise.
      */
     bool isDefault() const;
 
     /**
-     * Binds this FrameBuffer for off-screen rendering and return you the curently bound one.
+     * Binds this FrameBuffer for off-screen rendering and return you the currently bound one.
      *
      * You should keep the return FrameBuffer and store it and call bind() when you rendering is complete.
      *
@@ -154,17 +154,17 @@ public:
 
 	/**
 	 * Records a screenshot of what is stored on the current FrameBuffer.
-	 * 
+	 *
 	 * @return A screenshot of the current framebuffer's content.
 	 */
 	static Image* createScreenshot();
 
 	/**
 	 * Records a screenshot of what is stored on the current FrameBuffer to an Image.
-	 * 
+	 *
 	 * The Image must be the same size as the FrameBuffer, otherwise the operation will fail.
 	 * The Image must be format RGBA.
-	 * 
+	 *
 	 * @param image The Image to write the current framebuffer's content to.
 	 */
 	static void getScreenshot(Image* image);
@@ -174,7 +174,7 @@ public:
      *
      * @ return The default framebuffer.
      */
-    static FrameBuffer* bindDefault(); 
+    static FrameBuffer* bindDefault();
 
     /**
      * Gets the currently bound FrameBuffer.
@@ -182,7 +182,7 @@ public:
      * @return The currently bound FrameBuffer.
      */
     static FrameBuffer* getCurrent();
-     
+
 private:
 
     /**

+ 4 - 13
gameplay/src/Game.cpp

@@ -5,6 +5,7 @@
 #include "FileSystem.h"
 #include "FrameBuffer.h"
 #include "SceneLoader.h"
+#include "ControlFactory.h"
 
 /** @script{ignore} */
 GLenum __gl_error_code = GL_NO_ERROR;
@@ -24,7 +25,7 @@ Game::Game()
       _clearDepth(1.0f), _clearStencil(0), _properties(NULL),
       _animationController(NULL), _audioController(NULL),
       _physicsController(NULL), _aiController(NULL), _audioListener(NULL),
-      _timeEvents(NULL), _scriptController(NULL), _socialController(NULL), _scriptListeners(NULL)
+      _timeEvents(NULL), _scriptController(NULL), _scriptListeners(NULL)
 {
     GP_ASSERT(__gameInstance == NULL);
     __gameInstance = this;
@@ -114,9 +115,6 @@ bool Game::startup()
     _scriptController = new ScriptController();
     _scriptController->initialize();
 
-    _socialController = new SocialController();
-    _socialController->initialize();
-
     // Load any gamepads, ui or physical.
     loadGamepads();
 
@@ -196,9 +194,8 @@ void Game::shutdown()
         SAFE_DELETE(_physicsController);
         _aiController->finalize();
         SAFE_DELETE(_aiController);
-
-        _socialController->initialize();
-        SAFE_DELETE(_socialController);
+        
+        ControlFactory::finalize();
 
         // Note: we do not clean up the script controller here
         // because users can call Game::exit() from a script.
@@ -228,7 +225,6 @@ void Game::pause()
         _audioController->pause();
         _physicsController->pause();
         _aiController->pause();
-        _socialController->pause();
     }
 
     ++_pausedCount;
@@ -252,7 +248,6 @@ void Game::resume()
             _audioController->resume();
             _physicsController->resume();
             _aiController->resume();
-            _socialController->resume();
         }
     }
 }
@@ -337,9 +332,6 @@ void Game::frame()
         // Audio Rendering.
         _audioController->update(elapsedTime);
 
-        // Social Update.
-        _socialController->update(elapsedTime);
-
         // Graphics Rendering.
         render(elapsedTime);
 
@@ -402,7 +394,6 @@ void Game::updateOnce()
     _aiController->update(elapsedTime);
     _audioController->update(elapsedTime);
     _scriptController->update(elapsedTime);
-    _socialController->update(elapsedTime);
 }
 
 void Game::setViewport(const Rectangle& viewport)

+ 0 - 12
gameplay/src/Game.h

@@ -9,7 +9,6 @@
 #include "AudioController.h"
 #include "AnimationController.h"
 #include "PhysicsController.h"
-#include "SocialController.h"
 #include "AIController.h"
 #include "AudioListener.h"
 #include "Rectangle.h"
@@ -259,16 +258,6 @@ public:
      */
     inline ScriptController* getScriptController() const;
 
-    /**
-     * Gets the social controller for managing control of social apis
-     * associated with the game.
-     *
-     * @return The script controller for this game.
-     *
-     * @script{ignore}
-     */
-    inline SocialController* getSocialController() const;
-
     /**
      * Gets the audio listener for 3D audio.
      * 
@@ -771,7 +760,6 @@ private:
     AudioListener* _audioListener;              // The audio listener in 3D space.
     std::priority_queue<TimeEvent, std::vector<TimeEvent>, std::less<TimeEvent> >* _timeEvents;     // Contains the scheduled time events.
     ScriptController* _scriptController;            // Controls the scripting engine.
-    SocialController* _socialController;        // Controls social aspect of the game.
     std::vector<ScriptListener*>* _scriptListeners; // Lua script listeners.
 
     // Note: Do not add STL object member variables on the stack; this will cause false memory leaks to be reported.

+ 0 - 5
gameplay/src/Game.inl

@@ -63,11 +63,6 @@ inline AIController* Game::getAIController() const
     return _aiController;
 }
 
-inline SocialController* Game::getSocialController() const
-{
-    return _socialController;
-}
-
 template <class T>
 void Game::renderOnce(T* instance, void (T::*method)(void*), void* cookie)
 {

+ 1 - 1
gameplay/src/Gamepad.cpp

@@ -19,7 +19,6 @@ Gamepad::Gamepad(const char* formPath)
     _form = Form::create(formPath);
     GP_ASSERT(_form);
     _form->setConsumeInputEvents(false);
-    _form->_isGamepad = true;
     _vendorString = "None";
     _productString = "Virtual";
 
@@ -149,6 +148,7 @@ void Gamepad::bindGamepadControls(Container* container)
         {
             Button* button = (Button*)control;
             button->setConsumeInputEvents(true);
+            button->setCanFocus(false);
             _uiButtons[button->getDataBinding()] = button;
             _buttonCount++;
         }

+ 8 - 8
gameplay/src/HeightField.h

@@ -7,7 +7,7 @@ namespace gameplay
 {
 
     /**
-     * Defines a reference counted class that holds heightfeild data.
+     * Defines a reference counted class that holds heightfield data.
      *
      * Heightfields can be used to construct both Terrain objects as well as PhysicsCollisionShape
      * heightfield defintions, which are used in heightfield rigid body creation. Heightfields can
@@ -31,7 +31,7 @@ namespace gameplay
          * Creates a HeightField from the specified heightfield image.
          *
          * The specified image path must refer to a valid heightfield image. Supported images are
-         * the same as those supported by the Image class (i.e. PNG). 
+         * the same as those supported by the Image class (i.e. PNG).
          *
          * The minHeight and maxHeight parameters provides a mapping from heightfield pixel
          * intensity to height values. The minHeight parameter is mapped to zero intensity
@@ -40,7 +40,7 @@ namespace gameplay
          * @param path Path to a heightfield image.
          * @param heightMin Minimum height value for a zero intensity pixel.
          * @param heightMax Maximum height value for a full intensity heightfield pixel (must be >= minHeight).
-         * 
+         *
          * @return The new HeightField.
          */
         static HeightField* createFromImage(const char* path, float heightMin = 0, float heightMax = 1);
@@ -54,7 +54,7 @@ namespace gameplay
          * This method automatically determines (based on file size) whether the input file
          * is RAW8 or RAW16. RAW files must have a .raw or .r16 file extension.
          *
-         * RAW files are commonly used in software that produces heightmap images. Using RAW16 is 
+         * RAW files are commonly used in software that produces heightmap images. Using RAW16 is
          * preferred or any 8-bit heightfield source since it allows greater precision, resulting in
          * smoother height transitions.
          *
@@ -67,13 +67,13 @@ namespace gameplay
          * @param height Height of the RAW data.
          * @param heightMin Minimum height value for a zero intensity pixel.
          * @param heightMax Maximum height value for a full intensity heightfield pixel (must be >= minHeight).
-         * 
+         *
          * @return The new HeightField.
          */
         static HeightField* createFromRAW(const char* path, unsigned int width, unsigned int height, float heightMin = 0, float heightMax = 1);
 
         /**
-         * Returns a pointer to the underying height array.
+         * Returns a pointer to the underlying height array.
          *
          * The array is packed in row major order, meaning that the data is aligned in rows,
          * from top left to bottom right.
@@ -87,7 +87,7 @@ namespace gameplay
          *
          * The specified row and column are specified as floating point numbers so that values
          * between points can be specified. In this case, a height value is calculated that is
-         * interpolated between neighboring height values. 
+         * interpolated between neighboring height values.
          *
          * If the specified point lies outside the heightfield, it is clamped to the boundary
          * of the heightfield.
@@ -108,7 +108,7 @@ namespace gameplay
 
         /**
          * Returns the number of columns in the heightfield.
-         * 
+         *
          * @return The column count.
          */
         unsigned int getColumnCount() const;

+ 169 - 171
gameplay/src/ImageControl.cpp

@@ -1,171 +1,169 @@
-#include "Base.h"
-#include "ImageControl.h"
-
-namespace gameplay
-{
-
-ImageControl::ImageControl() :
-    _srcRegion(Rectangle::empty()), _dstRegion(Rectangle::empty()), _batch(NULL),
-    _tw(0.0f), _th(0.0f), _uvs(Theme::UVs::full())
-{
-}
-
-ImageControl::~ImageControl()
-{
-    SAFE_DELETE(_batch);
-}
-
-ImageControl* ImageControl::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    ImageControl* imageControl = new ImageControl();
-    if (id)
-        imageControl->_id = id;
-    imageControl->setStyle(style);
-
-    imageControl->_consumeInputEvents = false;
-    imageControl->_focusIndex = -2;
-
-    return imageControl;
-}
-
-Control* ImageControl::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    ImageControl* imageControl = new ImageControl();
-    imageControl->initialize(style, properties);
-
-    imageControl->_consumeInputEvents = false;
-    imageControl->_focusIndex = -2;
-
-    return imageControl;
-}
-
-void ImageControl::initialize(Theme::Style* style, Properties* properties)
-{
-    GP_ASSERT(properties);
-
-    Control::initialize(style, properties);
-
-    std::string path;
-    if (properties->getPath("path", &path))
-    {
-        setImage(path.c_str());
-    }
-
-    if (properties->exists("srcRegion"))
-    {
-        Vector4 region;
-        properties->getVector4("srcRegion", &region);
-        setRegionSrc(region.x, region.y, region.z, region.w);
-    }
-
-    if (properties->exists("dstRegion"))
-    {
-        Vector4 region;
-        properties->getVector4("dstRegion", &region);
-        setRegionDst(region.x, region.y, region.z, region.w);
-    }
-}
-
-void ImageControl::setImage(const char* path)
-{
-    SAFE_DELETE(_batch);
-    Texture* texture = Texture::create(path);
-    _batch = SpriteBatch::create(texture);
-    _tw = 1.0f / texture->getWidth();
-    _th = 1.0f / texture->getHeight();
-    texture->release();
-    _dirty = true;
-}
-
-void ImageControl::setRegionSrc(float x, float y, float width, float height)
-{
-    _srcRegion.set(x, y, width, height);
-
-    _uvs.u1 = x * _tw;
-    _uvs.u2 = (x + width) * _tw;
-    _uvs.v1 = 1.0f - (y * _th);
-    _uvs.v2 = 1.0f - ((y + height) * _th);
-    _dirty = true;
-}
-
-void ImageControl::setRegionSrc(const Rectangle& region)
-{
-    setRegionSrc(region.x, region.y, region.width, region.height);
-    _dirty = true;
-}
-
-const Rectangle& ImageControl::getRegionSrc() const
-{
-    return _srcRegion;
-}
-
-void ImageControl::setRegionDst(float x, float y, float width, float height)
-{
-    _dstRegion.set(x, y, width, height);
-    _dirty = true;
-}
-
-void ImageControl::setRegionDst(const Rectangle& region)
-{
-    setRegionDst(region.x, region.y, region.width, region.height);
-    _dirty = true;
-}
-
-const Rectangle& ImageControl::getRegionDst() const
-{
-    return _dstRegion;
-}
-
-const char* ImageControl::getType() const
-{
-    return "image";
-}
-
-void ImageControl::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
-{
-    spriteBatch->finish();
-
-    // An ImageControl is not part of the texture atlas but should use the same projection matrix.
-    _batch->setProjectionMatrix(spriteBatch->getProjectionMatrix());
-
-    Vector4 color = Vector4::one();
-    color.w *= _opacity;
-
-    _batch->start();
-    if (_dstRegion.isEmpty())
-    {
-        _batch->draw(_viewportBounds.x, _viewportBounds.y, _viewportBounds.width, _viewportBounds.height,
-            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, color, _viewportClipBounds);
-    }
-    else
-    {
-        _batch->draw(_viewportBounds.x + _dstRegion.x, _viewportBounds.y + _dstRegion.y,
-            _dstRegion.width, _dstRegion.height,
-            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, color, _viewportClipBounds);
-    }
-    _batch->finish();
-
-    spriteBatch->start();
-}
-
-void ImageControl::update(const Control* container, const Vector2& offset)
-{
-    Button::update(container, offset);
-
-    if (_batch)
-    {
-        if (_autoWidth == Control::AUTO_SIZE_FIT)
-        {
-            setWidth(_batch->getSampler()->getTexture()->getWidth());
-        }
-
-        if (_autoHeight == Control::AUTO_SIZE_FIT)
-        {
-            setHeight(_batch->getSampler()->getTexture()->getWidth());
-        }
-    }
-}
-
-}
+#include "Base.h"
+#include "ImageControl.h"
+
+namespace gameplay
+{
+
+ImageControl::ImageControl() :
+    _srcRegion(Rectangle::empty()), _dstRegion(Rectangle::empty()), _batch(NULL),
+    _tw(0.0f), _th(0.0f), _uvs(Theme::UVs::full())
+{
+}
+
+ImageControl::~ImageControl()
+{
+    SAFE_DELETE(_batch);
+}
+
+ImageControl* ImageControl::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    ImageControl* imageControl = new ImageControl();
+    if (id)
+        imageControl->_id = id;
+    imageControl->setStyle(style);
+
+    imageControl->_focusIndex = -2;
+
+    return imageControl;
+}
+
+Control* ImageControl::create(Theme::Style* style, Properties* properties)
+{
+    ImageControl* imageControl = new ImageControl();
+    imageControl->initialize(style, properties);
+
+    imageControl->_focusIndex = -2;
+
+    return imageControl;
+}
+
+void ImageControl::initialize(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Control::initialize(style, properties);
+
+    std::string path;
+    if (properties->getPath("path", &path))
+    {
+        setImage(path.c_str());
+    }
+
+    if (properties->exists("srcRegion"))
+    {
+        Vector4 region;
+        properties->getVector4("srcRegion", &region);
+        setRegionSrc(region.x, region.y, region.z, region.w);
+    }
+
+    if (properties->exists("dstRegion"))
+    {
+        Vector4 region;
+        properties->getVector4("dstRegion", &region);
+        setRegionDst(region.x, region.y, region.z, region.w);
+    }
+}
+
+void ImageControl::setImage(const char* path)
+{
+    SAFE_DELETE(_batch);
+    Texture* texture = Texture::create(path);
+    _batch = SpriteBatch::create(texture);
+    _tw = 1.0f / texture->getWidth();
+    _th = 1.0f / texture->getHeight();
+    texture->release();
+    _dirty = true;
+}
+
+void ImageControl::setRegionSrc(float x, float y, float width, float height)
+{
+    _srcRegion.set(x, y, width, height);
+
+    _uvs.u1 = x * _tw;
+    _uvs.u2 = (x + width) * _tw;
+    _uvs.v1 = 1.0f - (y * _th);
+    _uvs.v2 = 1.0f - ((y + height) * _th);
+    _dirty = true;
+}
+
+void ImageControl::setRegionSrc(const Rectangle& region)
+{
+    setRegionSrc(region.x, region.y, region.width, region.height);
+    _dirty = true;
+}
+
+const Rectangle& ImageControl::getRegionSrc() const
+{
+    return _srcRegion;
+}
+
+void ImageControl::setRegionDst(float x, float y, float width, float height)
+{
+    _dstRegion.set(x, y, width, height);
+    _dirty = true;
+}
+
+void ImageControl::setRegionDst(const Rectangle& region)
+{
+    setRegionDst(region.x, region.y, region.width, region.height);
+    _dirty = true;
+}
+
+const Rectangle& ImageControl::getRegionDst() const
+{
+    return _dstRegion;
+}
+
+const char* ImageControl::getType() const
+{
+    return "image";
+}
+
+void ImageControl::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    spriteBatch->finish();
+
+    // An ImageControl is not part of the texture atlas but should use the same projection matrix.
+    _batch->setProjectionMatrix(spriteBatch->getProjectionMatrix());
+
+    Vector4 color = Vector4::one();
+    color.w *= _opacity;
+
+    _batch->start();
+    if (_dstRegion.isEmpty())
+    {
+        _batch->draw(_viewportBounds.x, _viewportBounds.y, _viewportBounds.width, _viewportBounds.height,
+            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, color, _viewportClipBounds);
+    }
+    else
+    {
+        _batch->draw(_viewportBounds.x + _dstRegion.x, _viewportBounds.y + _dstRegion.y,
+            _dstRegion.width, _dstRegion.height,
+            _uvs.u1, _uvs.v1, _uvs.u2, _uvs.v2, color, _viewportClipBounds);
+    }
+    _batch->finish();
+
+    spriteBatch->start();
+}
+
+void ImageControl::update(const Control* container, const Vector2& offset)
+{
+    Control::update(container, offset);
+
+    if (_batch)
+    {
+        if (_autoWidth == Control::AUTO_SIZE_FIT)
+        {
+            setWidth(_batch->getSampler()->getTexture()->getWidth());
+        }
+
+        if (_autoHeight == Control::AUTO_SIZE_FIT)
+        {
+            setHeight(_batch->getSampler()->getTexture()->getWidth());
+        }
+    }
+}
+
+}

+ 152 - 152
gameplay/src/ImageControl.h

@@ -1,152 +1,152 @@
-#ifndef IMAGECONTROL_H_
-#define IMAGECONTROL_H_
-
-#include "Button.h"
-#include "Theme.h"
-#include "Image.h"
-#include "SpriteBatch.h"
-#include "Rectangle.h"
-
-namespace gameplay
-{
-
-/**
- * An ImageControl allows forms to display images from arbitrary files not specified in the theme.
- *
- * The following properties are available for image controls:
-
- @verbatim
-     image <control ID>
-     {
-         style          = <styleID>
-         alignment      = <Control::Alignment constant> // Note: 'position' will be ignored.
-         position       = <x, y>
-         autoWidth      = <bool>
-         autoHeight     = <bool>
-         size           = <width, height>
-         width          = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
-         height         = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
-         consumeEvents  = <bool>    // Whether the label propagates input events to the Game's input event handler. Default is true.
-         path           = <string>  // Path to image or texture atlas.
-         srcRegion      = <x, y, width, height>  // Region within file to create UVs from.
-         dstRegion      = <x, y, width, height>  // Region of control's viewport to draw into.
-     }
- @endverbatim
- */
-class ImageControl : public Button
-{
-    friend class Container;
-	friend class ControlFactory;
-
-public:
-
-    /**
-     * Create a new ImageControl.
-     *
-     * @param id The control's ID.
-     * @param style The control's style.
-     *
-     * @return The new ImageControl.
-     * @script{create}
-     */
-    static ImageControl* create(const char* id, Theme::Style* style);
-
-    /**
-     * Set the path of the image for this ImageControl to display.
-     *
-     * @param path The path to the image.
-     */
-    void setImage(const char* path);
-
-    /**
-     * Set the source region of this ImageControl.  This is the region of the file,
-     * in pixels, to use when drawing.
-     *
-     * @param x The x coordinate of the source region.
-     * @param y The y coordinate of the source region.
-     * @param width The width of the source region.
-     * @param height The height of the source region.
-     */
-    void setRegionSrc(float x, float y, float width, float height);
-
-    /**
-     * Set the source region of this ImageControl.  This is the region of the file,
-     * in pixels, to use when drawing.
-     *
-     * @param region The new source region.
-     */
-    void setRegionSrc(const Rectangle& region);
-
-    /**
-     * Get the source region of this ImageControl.
-     *
-     * @return The source region of this ImageControl.
-     */
-    const Rectangle& getRegionSrc() const;
-
-    /**
-     * Sets the destination region of this ImageControl.  This is the region
-     * within the control's viewport to draw the image.
-     *
-     * @param x The x coordinate of the destination region.
-     * @param y The y coordinate of the destination region.
-     * @param width The width of the destination region.
-     * @param height The height of the destination region.
-     */
-    void setRegionDst(float x, float y, float width, float height);
-    
-    /**
-     * Sets the destination region of this ImageControl.  This is the region
-     * within the control's viewport to draw the image.
-     *
-     * @param region The new destination region.
-     */
-    void setRegionDst(const Rectangle& region);
-
-    /**
-     * Get the destination region of this ImageControl.
-     *
-     * @return The destination region of this ImageControl.
-     */
-    const Rectangle& getRegionDst() const;
-
-    const char* getType() const;
-
-protected:
-
-    ImageControl();
-    
-    virtual ~ImageControl();
-
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
-
-    virtual void initialize(Theme::Style* style, Properties* properties);
-
-    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-    /**
-     * @see Control#update(const Control*, const Vector2&)
-     */
-    void update(const Control* container, const Vector2& offset);
-
-    // Source region.
-    Rectangle _srcRegion;
-    // Destination region.
-    Rectangle _dstRegion;
-    SpriteBatch* _batch;
-    
-    // One over texture width and height, for use when calculating UVs from a new source region.
-    float _tw;
-    float _th;
-    
-    // Calculated UVs.
-    Theme::UVs _uvs;
-
-private:
-
-    ImageControl(const ImageControl& copy);
-};
-
-}
-
-#endif
+#ifndef IMAGECONTROL_H_
+#define IMAGECONTROL_H_
+
+#include "Control.h"
+#include "Theme.h"
+#include "Image.h"
+#include "SpriteBatch.h"
+#include "Rectangle.h"
+
+namespace gameplay
+{
+
+/**
+ * An ImageControl allows forms to display images from arbitrary files not specified in the theme.
+ *
+ * The following properties are available for image controls:
+
+ @verbatim
+     image <control ID>
+     {
+         style          = <styleID>
+         alignment      = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position       = <x, y>
+         autoWidth      = <bool>
+         autoHeight     = <bool>
+         size           = <width, height>
+         width          = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height         = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         consumeEvents  = <bool>    // Whether the label propagates input events to the Game's input event handler. Default is true.
+         path           = <string>  // Path to image or texture atlas.
+         srcRegion      = <x, y, width, height>  // Region within file to create UVs from.
+         dstRegion      = <x, y, width, height>  // Region of control's viewport to draw into.
+     }
+ @endverbatim
+ */
+class ImageControl : public Control
+{
+    friend class Container;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Create a new ImageControl.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new ImageControl.
+     * @script{create}
+     */
+    static ImageControl* create(const char* id, Theme::Style* style);
+
+    /**
+     * Set the path of the image for this ImageControl to display.
+     *
+     * @param path The path to the image.
+     */
+    void setImage(const char* path);
+
+    /**
+     * Set the source region of this ImageControl.  This is the region of the file,
+     * in pixels, to use when drawing.
+     *
+     * @param x The x coordinate of the source region.
+     * @param y The y coordinate of the source region.
+     * @param width The width of the source region.
+     * @param height The height of the source region.
+     */
+    void setRegionSrc(float x, float y, float width, float height);
+
+    /**
+     * Set the source region of this ImageControl.  This is the region of the file,
+     * in pixels, to use when drawing.
+     *
+     * @param region The new source region.
+     */
+    void setRegionSrc(const Rectangle& region);
+
+    /**
+     * Get the source region of this ImageControl.
+     *
+     * @return The source region of this ImageControl.
+     */
+    const Rectangle& getRegionSrc() const;
+
+    /**
+     * Sets the destination region of this ImageControl.  This is the region
+     * within the control's viewport to draw the image.
+     *
+     * @param x The x coordinate of the destination region.
+     * @param y The y coordinate of the destination region.
+     * @param width The width of the destination region.
+     * @param height The height of the destination region.
+     */
+    void setRegionDst(float x, float y, float width, float height);
+
+    /**
+     * Sets the destination region of this ImageControl.  This is the region
+     * within the control's viewport to draw the image.
+     *
+     * @param region The new destination region.
+     */
+    void setRegionDst(const Rectangle& region);
+
+    /**
+     * Get the destination region of this ImageControl.
+     *
+     * @return The destination region of this ImageControl.
+     */
+    const Rectangle& getRegionDst() const;
+
+    const char* getType() const;
+
+protected:
+
+    ImageControl();
+
+    virtual ~ImageControl();
+
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    virtual void initialize(Theme::Style* style, Properties* properties);
+
+    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    /**
+     * @see Control#update(const Control*, const Vector2&)
+     */
+    void update(const Control* container, const Vector2& offset);
+
+    // Source region.
+    Rectangle _srcRegion;
+    // Destination region.
+    Rectangle _dstRegion;
+    SpriteBatch* _batch;
+    
+    // One over texture width and height, for use when calculating UVs from a new source region.
+    float _tw;
+    float _th;
+    
+    // Calculated UVs.
+    Theme::UVs _uvs;
+
+private:
+
+    ImageControl(const ImageControl& copy);
+};
+
+}
+
+#endif

+ 293 - 292
gameplay/src/Joystick.cpp

@@ -1,292 +1,293 @@
-#include "Base.h"
-#include "Joystick.h"
-
-namespace gameplay
-{
-
-Joystick::Joystick() : _radius(1.0f), _relative(true), _innerSize(NULL), _outerSize(NULL)
-{
-}
-
-Joystick::~Joystick()
-{
-    if (_innerSize)
-        SAFE_DELETE(_innerSize);
-    if (_outerSize)
-        SAFE_DELETE(_outerSize);
-}
-
-Joystick* Joystick::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    Joystick* joystick = new Joystick();
-    if (id)
-        joystick->_id = id;
-    joystick->setStyle(style);
-
-    return joystick;
-}
-
-Control* Joystick::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    Joystick* joystick = new Joystick();
-    joystick->initialize(style, properties);
-    joystick->_index = properties->getInt("index");
-    return joystick;
-}
-
-void Joystick::initialize(Theme::Style* style, Properties* properties)
-{
-    GP_ASSERT(properties);
-
-    Control::initialize(style, properties);
-
-    if (!properties->exists("radius"))
-    {
-        GP_ERROR("Failed to load joystick; required attribute 'radius' is missing.");
-        return;
-    }
-    _radius = properties->getFloat("radius");
-    GP_ASSERT(_radius != 0.0f);
-
-    if (properties->exists("relative"))
-    {
-        setRelative(properties->getBool("relative"));
-    }
-    else
-    {
-        setRelative(false);
-    }
-
-    Theme::ThemeImage* inner = getImage("inner", _state);
-    if (inner)
-    {
-        _innerSize = new Vector2();
-        Vector2 innerSize;
-        if (properties->getVector2("innerRegion", &innerSize))
-        {
-            _innerSize->set(innerSize.x, innerSize.y);
-        }
-        else
-        {
-            const Rectangle& rect = inner->getRegion();
-            _innerSize->set(rect.width, rect.height);
-        }
-    }
-
-    Theme::ThemeImage* outer = getImage("outer", _state);
-    if (outer)
-    {
-        _outerSize = new Vector2();
-        Vector2 outerSize;
-        if (properties->getVector2("outerRegion", &outerSize))
-        {
-            _outerSize->set(outerSize.x, outerSize.y);
-        }
-        else
-        {
-            const Rectangle& rect = outer->getRegion();
-            _outerSize->set(rect.width, rect.height);
-        }
-        _screenRegion.width = _outerSize->x;
-        _screenRegion.height = _outerSize->y;
-    }
-    else
-    {
-        if (inner)
-        {
-            const Rectangle& rect = inner->getRegion();
-            _screenRegion.width = rect.width;
-            _screenRegion.height = rect.height;
-        }
-        else
-        {
-            _screenRegion.width = _radius * 2.0f;
-            _screenRegion.height = _screenRegion.width;
-        }
-    }
-}
-
-void Joystick::addListener(Control::Listener* listener, int eventFlags)
-{
-    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
-    {
-        GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
-    }
-
-    Control::addListener(listener, eventFlags);
-}
-
-bool Joystick::touchEvent(Touch::TouchEvent touchEvent, int x, int y, unsigned int contactIndex)
-{
-    switch (touchEvent)
-    {
-        case Touch::TOUCH_PRESS:
-        {
-            if (_contactIndex == INVALID_CONTACT_INDEX)
-            {
-                float dx = 0.0f;
-                float dy = 0.0f;
-
-                _contactIndex = (int) contactIndex;
-                notifyListeners(Control::Listener::PRESS);
-
-                // Get the displacement of the touch from the centre.
-                if (!_relative)
-                {
-                    dx = x - _screenRegion.width * 0.5f;
-                    dy = _screenRegion.height * 0.5f - y;
-                }
-                else
-                {
-                    _screenRegion.x = x + _bounds.x - _screenRegion.width * 0.5f;
-                    _screenRegion.y = y + _bounds.y - _screenRegion.height * 0.5f;
-                }
-
-                _displacement.set(dx, dy);
-
-                // If the displacement is greater than the radius, then cap the displacement to the
-                // radius.
-                
-                Vector2 value;
-                if ((fabs(_displacement.x) > _radius) || (fabs(_displacement.y) > _radius))
-                {
-                    _displacement.normalize();
-                    value.set(_displacement);
-                    _displacement.scale(_radius);
-                }
-                else
-                {
-                    value.set(_displacement);
-                    GP_ASSERT(_radius);
-                    value.scale(1.0f / _radius);
-                }
-
-                // Check if the value has changed. Won't this always be the case?
-                if (_value != value)
-                {
-                    _value.set(value);
-                    _dirty = true;
-                    notifyListeners(Control::Listener::VALUE_CHANGED);
-                }
-
-                setState(ACTIVE);
-                return _consumeInputEvents;
-            }
-            break;
-        }
-        case Touch::TOUCH_MOVE:
-        {
-            if (_contactIndex == (int) contactIndex)
-            {
-                float dx = x - ((_relative) ? _screenRegion.x - _bounds.x : 0.0f) - _screenRegion.width * 0.5f;
-                float dy = -(y - ((_relative) ? _screenRegion.y - _bounds.y : 0.0f) - _screenRegion.height * 0.5f);
-            
-                _displacement.set(dx, dy);
-            
-                Vector2 value;
-                if ((fabs(_displacement.x) > _radius) || (fabs(_displacement.y) > _radius))
-                {
-                    _displacement.normalize();
-                    value.set(_displacement);
-                    _displacement.scale(_radius);
-                }
-                else
-                {
-                    value.set(_displacement);
-                    GP_ASSERT(_radius);
-                    value.scale(1.0f / _radius);
-                }
-
-                if (_value != value)
-                {
-                    _value.set(value);
-                    _dirty = true;
-                    notifyListeners(Control::Listener::VALUE_CHANGED);
-                }
-
-                return _consumeInputEvents;
-            }
-            break;
-        }
-        case Touch::TOUCH_RELEASE:
-        {
-            if (_contactIndex == (int) contactIndex)
-            {
-                _contactIndex = INVALID_CONTACT_INDEX;
-
-                notifyListeners(Control::Listener::RELEASE);
-
-                // Reset displacement and direction vectors.
-                _displacement.set(0.0f, 0.0f);
-                Vector2 value(_displacement);
-                if (_value != value)
-                {
-                    _value.set(value);
-                    _dirty = true;
-                    notifyListeners(Control::Listener::VALUE_CHANGED);
-                }
-
-                setState(NORMAL);
-                return _consumeInputEvents;
-            }
-            break;
-        }
-    }
-
-    return false;
-}
-
-void Joystick::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
-{
-    GP_ASSERT(spriteBatch);
-
-    // If the joystick is not absolute, then only draw if it is active.
-    if (!_relative || (_relative && _state == ACTIVE))
-    {
-        if (!_relative)
-        {
-            _screenRegion.x = _viewportClipBounds.x + (_viewportClipBounds.width - _screenRegion.width) / 2.0f;
-            _screenRegion.y = _viewportClipBounds.y + (_viewportClipBounds.height - _screenRegion.height) / 2.0f;
-        }
-
-        // Draw the outer image.
-        Theme::ThemeImage* outer = getImage("outer", _state);
-        if (outer)
-        {
-            const Theme::UVs& uvs = outer->getUVs();
-            const Vector4& color = outer->getColor();
-            if (_relative)
-                spriteBatch->draw(_screenRegion.x, _screenRegion.y, _outerSize->x, _outerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
-            else
-                spriteBatch->draw(_screenRegion.x, _screenRegion.y, _outerSize->x, _outerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
-        }
-
-        // Draw the inner image.
-        Theme::ThemeImage* inner = getImage("inner", _state);
-        if (inner)
-        {
-            Vector2 position(_screenRegion.x, _screenRegion.y);
-            
-            // Adjust position to reflect displacement.
-            position.x += _displacement.x;
-            position.y += -_displacement.y;
-            
-            // Get the uvs and color and draw.
-            const Theme::UVs& uvs = inner->getUVs();
-            const Vector4& color = inner->getColor();
-            if (_relative)
-                spriteBatch->draw(position.x, position.y, _innerSize->x, _innerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
-            else
-                spriteBatch->draw(position.x, position.y, _innerSize->x, _innerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
-        }
-    }
-}
-
-const char* Joystick::getType() const
-{
-    return "joystick";
-}
-
-}
+#include "Base.h"
+#include "Joystick.h"
+
+namespace gameplay
+{
+
+Joystick::Joystick() : _radius(1.0f), _relative(true), _innerSize(NULL), _outerSize(NULL)
+{
+}
+
+Joystick::~Joystick()
+{
+    if (_innerSize)
+        SAFE_DELETE(_innerSize);
+    if (_outerSize)
+        SAFE_DELETE(_outerSize);
+}
+
+Joystick* Joystick::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    Joystick* joystick = new Joystick();
+    if (id)
+        joystick->_id = id;
+    joystick->setStyle(style);
+
+    return joystick;
+}
+
+Control* Joystick::create(Theme::Style* style, Properties* properties)
+{
+    Joystick* joystick = new Joystick();
+    joystick->initialize(style, properties);
+    joystick->_index = properties->getInt("index");
+    return joystick;
+}
+
+void Joystick::initialize(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Control::initialize(style, properties);
+
+    Control::State state = getState();
+
+    if (!properties->exists("radius"))
+    {
+        GP_ERROR("Failed to load joystick; required attribute 'radius' is missing.");
+        return;
+    }
+    _radius = properties->getFloat("radius");
+    GP_ASSERT(_radius != 0.0f);
+
+    if (properties->exists("relative"))
+    {
+        setRelative(properties->getBool("relative"));
+    }
+    else
+    {
+        setRelative(false);
+    }
+
+    Theme::ThemeImage* inner = getImage("inner", state);
+    if (inner)
+    {
+        _innerSize = new Vector2();
+        Vector2 innerSize;
+        if (properties->getVector2("innerRegion", &innerSize))
+        {
+            _innerSize->set(innerSize.x, innerSize.y);
+        }
+        else
+        {
+            const Rectangle& rect = inner->getRegion();
+            _innerSize->set(rect.width, rect.height);
+        }
+    }
+
+    Theme::ThemeImage* outer = getImage("outer", state);
+    if (outer)
+    {
+        _outerSize = new Vector2();
+        Vector2 outerSize;
+        if (properties->getVector2("outerRegion", &outerSize))
+        {
+            _outerSize->set(outerSize.x, outerSize.y);
+        }
+        else
+        {
+            const Rectangle& rect = outer->getRegion();
+            _outerSize->set(rect.width, rect.height);
+        }
+        _screenRegion.width = _outerSize->x;
+        _screenRegion.height = _outerSize->y;
+    }
+    else
+    {
+        if (inner)
+        {
+            const Rectangle& rect = inner->getRegion();
+            _screenRegion.width = rect.width;
+            _screenRegion.height = rect.height;
+        }
+        else
+        {
+            _screenRegion.width = _radius * 2.0f;
+            _screenRegion.height = _screenRegion.width;
+        }
+    }
+}
+
+void Joystick::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
+    {
+        GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
+bool Joystick::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    switch (evt)
+    {
+        case Touch::TOUCH_PRESS:
+        {
+            if (_contactIndex == INVALID_CONTACT_INDEX)
+            {
+                float dx = 0.0f;
+                float dy = 0.0f;
+
+                _contactIndex = (int)contactIndex;
+
+                // Get the displacement of the touch from the centre.
+                if (!_relative)
+                {
+                    dx = x - _screenRegion.width * 0.5f;
+                    dy = _screenRegion.height * 0.5f - y;
+                }
+                else
+                {
+                    _screenRegion.x = x + _bounds.x - _screenRegion.width * 0.5f;
+                    _screenRegion.y = y + _bounds.y - _screenRegion.height * 0.5f;
+                }
+
+                _displacement.set(dx, dy);
+
+                // If the displacement is greater than the radius, then cap the displacement to the
+                // radius.
+
+                Vector2 value;
+                if ((fabs(_displacement.x) > _radius) || (fabs(_displacement.y) > _radius))
+                {
+                    _displacement.normalize();
+                    value.set(_displacement);
+                    _displacement.scale(_radius);
+                }
+                else
+                {
+                    value.set(_displacement);
+                    GP_ASSERT(_radius);
+                    value.scale(1.0f / _radius);
+                }
+
+                // Check if the value has changed. Won't this always be the case?
+                if (_value != value)
+                {
+                    _value.set(value);
+                    _dirty = true;
+                    notifyListeners(Control::Listener::VALUE_CHANGED);
+                }
+
+                return true;
+            }
+            break;
+        }
+
+        case Touch::TOUCH_MOVE:
+        {
+            if (_contactIndex == (int) contactIndex)
+            {
+                float dx = x - ((_relative) ? _screenRegion.x - _bounds.x : 0.0f) - _screenRegion.width * 0.5f;
+                float dy = -(y - ((_relative) ? _screenRegion.y - _bounds.y : 0.0f) - _screenRegion.height * 0.5f);
+
+                _displacement.set(dx, dy);
+
+                Vector2 value;
+                if ((fabs(_displacement.x) > _radius) || (fabs(_displacement.y) > _radius))
+                {
+                    _displacement.normalize();
+                    value.set(_displacement);
+                    _displacement.scale(_radius);
+                }
+                else
+                {
+                    value.set(_displacement);
+                    GP_ASSERT(_radius);
+                    value.scale(1.0f / _radius);
+                }
+
+                if (_value != value)
+                {
+                    _value.set(value);
+                    _dirty = true;
+                    notifyListeners(Control::Listener::VALUE_CHANGED);
+                }
+
+                return true;
+            }
+            break;
+        }
+
+        case Touch::TOUCH_RELEASE:
+        {
+            if (_contactIndex == (int) contactIndex)
+            {
+                _contactIndex = INVALID_CONTACT_INDEX;
+
+                // Reset displacement and direction vectors.
+                _displacement.set(0.0f, 0.0f);
+                Vector2 value(_displacement);
+                if (_value != value)
+                {
+                    _value.set(value);
+                    _dirty = true;
+                    notifyListeners(Control::Listener::VALUE_CHANGED);
+                }
+
+                return true;
+            }
+            break;
+        }
+    }
+
+    return Control::touchEvent(evt, x, y, contactIndex);
+}
+
+void Joystick::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    GP_ASSERT(spriteBatch);
+
+    Control::State state = getState();
+
+    // If the joystick is not absolute, then only draw if it is active.
+    if (!_relative || (_relative && state == ACTIVE))
+    {
+        if (!_relative)
+        {
+            _screenRegion.x = _viewportClipBounds.x + (_viewportClipBounds.width - _screenRegion.width) / 2.0f;
+            _screenRegion.y = _viewportClipBounds.y + (_viewportClipBounds.height - _screenRegion.height) / 2.0f;
+        }
+
+        // Draw the outer image.
+        Theme::ThemeImage* outer = getImage("outer", state);
+        if (outer)
+        {
+            const Theme::UVs& uvs = outer->getUVs();
+            const Vector4& color = outer->getColor();
+            if (_relative)
+                spriteBatch->draw(_screenRegion.x, _screenRegion.y, _outerSize->x, _outerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
+            else
+                spriteBatch->draw(_screenRegion.x, _screenRegion.y, _outerSize->x, _outerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
+        }
+
+        // Draw the inner image.
+        Theme::ThemeImage* inner = getImage("inner", state);
+        if (inner)
+        {
+            Vector2 position(_screenRegion.x, _screenRegion.y);
+            
+            // Adjust position to reflect displacement.
+            position.x += _displacement.x;
+            position.y += -_displacement.y;
+            
+            // Get the uvs and color and draw.
+            const Theme::UVs& uvs = inner->getUVs();
+            const Vector4& color = inner->getColor();
+            if (_relative)
+                spriteBatch->draw(position.x, position.y, _innerSize->x, _innerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
+            else
+                spriteBatch->draw(position.x, position.y, _innerSize->x, _innerSize->y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
+        }
+    }
+}
+
+const char* Joystick::getType() const
+{
+    return "joystick";
+}
+
+}

+ 1 - 2
gameplay/src/Joystick.h

@@ -138,11 +138,10 @@ protected:
      *
      * @param style The style to apply to this joystick.
      * @param properties The properties to set on this joystick.
-     * @param theme The theme to set on this control if needed.
 	 *
      * @return The new joystick.
      */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
+    static Control* create(Theme::Style* style, Properties* properties);
 
     /**
      * Initialize this joystick.

+ 1 - 1
gameplay/src/Keyboard.h

@@ -14,7 +14,7 @@ class Keyboard
 
 public:
 
-   /**
+    /**
      * The keyboard event.
      */
     enum KeyEvent

+ 125 - 127
gameplay/src/Label.cpp

@@ -1,127 +1,125 @@
-#include "Base.h"
-#include "Label.h"
-
-namespace gameplay
-{
-
-Label::Label() : _text(""), _font(NULL)
-{
-}
-
-Label::~Label()
-{
-}
-
-Label* Label::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    Label* label = new Label();
-    if (id)
-        label->_id = id;
-    label->setStyle(style);
-
-    // Labels don't consume input events by default like other controls.
-    label->_consumeInputEvents = false;
-
-    // Ensure that labels cannot receive focus.
-    label->_focusIndex = -2;
-
-    return label;
-}
-
-Control* Label::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    Label* label = new Label();
-    label->initialize(style, properties);
-
-	label->_consumeInputEvents = false;
-    label->_focusIndex = -2;
-
-    return label;
-}
-
-void Label::initialize(Theme::Style* style, Properties* properties)
-{
-    GP_ASSERT(properties);
-
-    Control::initialize(style, properties);
-    const char* text = properties->getString("text");
-    if (text)
-    {
-        _text = text;
-    }
-}
-
-void Label::addListener(Control::Listener* listener, int eventFlags)
-{
-    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
-    {
-        GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
-    }
-    if ((eventFlags & Control::Listener::VALUE_CHANGED) == Control::Listener::VALUE_CHANGED)
-    {
-        GP_ERROR("VALUE_CHANGED event is not applicable to this control.");
-    }
-
-    Control::addListener(listener, eventFlags);
-}
-    
-void Label::setText(const char* text)
-{
-    assert(text);
-
-    if (strcmp(text, _text.c_str()) != 0)
-    {
-        _text = text;
-        _dirty = true;
-    }
-}
-
-const char* Label::getText()
-{
-    return _text.c_str();
-}
-
-void Label::update(const Control* container, const Vector2& offset)
-{
-    Control::update(container, offset);
-
-    _textBounds.set((int)_viewportBounds.x, (int)_viewportBounds.y, _viewportBounds.width, _viewportBounds.height);
-
-    _font = getFont(_state);
-    _textColor = getTextColor(_state);
-    _textColor.w *= _opacity;
-
-    Font* font = getFont(_state);
-    if ((_autoWidth == Control::AUTO_SIZE_FIT || _autoHeight == Control::AUTO_SIZE_FIT) && font)
-    {
-        unsigned int w, h;
-        font->measureText(_text.c_str(), getFontSize(_state), &w, &h);
-        if (_autoWidth == Control::AUTO_SIZE_FIT)
-            setWidth(w + getBorder(_state).left + getBorder(_state).right + getPadding().left + getPadding().right);
-        if (_autoHeight == Control::AUTO_SIZE_FIT)
-            setHeight(h + getBorder(_state).top + getBorder(_state).bottom + getPadding().top + getPadding().bottom);
-    }
-}
-
-void Label::drawText(const Rectangle& clip)
-{
-    if (_text.size() <= 0)
-        return;
-
-    // Draw the text.
-    if (_font)
-    {
-        _font->start();
-        _font->drawText(_text.c_str(), _textBounds, _textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_viewportClipBounds);
-        _font->finish();
-    }
-}
-
-const char* Label::getType() const
-{
-    return "label";
-}
-
-}
+#include "Base.h"
+#include "Label.h"
+
+namespace gameplay
+{
+
+Label::Label() : _text(""), _font(NULL)
+{
+}
+
+Label::~Label()
+{
+}
+
+Label* Label::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    Label* label = new Label();
+    if (id)
+        label->_id = id;
+    label->setStyle(style);
+
+    // Ensure that labels cannot receive focus.
+    label->_focusIndex = -2;
+
+    return label;
+}
+
+Control* Label::create(Theme::Style* style, Properties* properties)
+{
+    Label* label = new Label();
+    label->initialize(style, properties);
+
+    label->_focusIndex = -2;
+
+    return label;
+}
+
+void Label::initialize(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Control::initialize(style, properties);
+    const char* text = properties->getString("text");
+    if (text)
+    {
+        _text = text;
+    }
+}
+
+void Label::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
+    {
+        GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
+    }
+    if ((eventFlags & Control::Listener::VALUE_CHANGED) == Control::Listener::VALUE_CHANGED)
+    {
+        GP_ERROR("VALUE_CHANGED event is not applicable to this control.");
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+    
+void Label::setText(const char* text)
+{
+    assert(text);
+
+    if (strcmp(text, _text.c_str()) != 0)
+    {
+        _text = text;
+        _dirty = true;
+    }
+}
+
+const char* Label::getText()
+{
+    return _text.c_str();
+}
+
+void Label::update(const Control* container, const Vector2& offset)
+{
+    Control::update(container, offset);
+
+    _textBounds.set((int)_viewportBounds.x, (int)_viewportBounds.y, _viewportBounds.width, _viewportBounds.height);
+
+    Control::State state = getState();
+    _font = getFont(state);
+    _textColor = getTextColor(state);
+    _textColor.w *= _opacity;
+
+    Font* font = getFont(state);
+    if ((_autoWidth == Control::AUTO_SIZE_FIT || _autoHeight == Control::AUTO_SIZE_FIT) && font)
+    {
+        unsigned int w, h;
+        font->measureText(_text.c_str(), getFontSize(state), &w, &h);
+        if (_autoWidth == Control::AUTO_SIZE_FIT)
+            setWidth(w + getBorder(state).left + getBorder(state).right + getPadding().left + getPadding().right);
+        if (_autoHeight == Control::AUTO_SIZE_FIT)
+            setHeight(h + getBorder(state).top + getBorder(state).bottom + getPadding().top + getPadding().bottom);
+    }
+}
+
+void Label::drawText(const Rectangle& clip)
+{
+    if (_text.size() <= 0)
+        return;
+
+    // Draw the text.
+    if (_font)
+    {
+        Control::State state = getState();
+        _font->start();
+        _font->drawText(_text.c_str(), _textBounds, _textColor, getFontSize(state), getTextAlignment(state), true, getTextRightToLeft(state), &_viewportClipBounds);
+        _font->finish();
+    }
+}
+
+const char* Label::getType() const
+{
+    return "label";
+}
+
+}

+ 1 - 2
gameplay/src/Label.h

@@ -94,11 +94,10 @@ protected:
      *
      * @param style The style to apply to this label.
      * @param properties The properties to set on this label.
-     * @param theme The theme to set on this control if needed
 	 * 
      * @return The new label.
      */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
+    static Control* create(Theme::Style* style, Properties* properties);
 
     /**
      * Initialize this label.

+ 1 - 1
gameplay/src/Material.cpp

@@ -31,7 +31,7 @@ Material* Material::create(const char* url)
     Properties* properties = Properties::create(url);
     if (properties == NULL)
     {
-        GP_ERROR("Failed to create material from file.");
+        GP_WARN("Failed to create material from file.");
         return NULL;
     }
 

+ 1 - 1
gameplay/src/Material.h

@@ -35,7 +35,7 @@ public:
      * 
      * @param url The URL pointing to the Properties object defining the material.
      * 
-     * @return A new Material.
+     * @return A new Material or NULL if there was an error.
      * @script{create}
      */
     static Material* create(const char* url);

+ 14 - 14
gameplay/src/Model.h

@@ -33,14 +33,14 @@ public:
 
     /**
      * Returns the Mesh for this Model.
-     * 
+     *
      * @return The Mesh for this Model.
      */
     Mesh* getMesh() const;
 
     /**
      * Returns the number of parts in the Mesh for this Model.
-     * 
+     *
      * @return The number of parts in the Mesh for this Model.
      */
     unsigned int getMeshPartCount() const;
@@ -52,7 +52,7 @@ public:
      * mesh part, the shared Material will be returned.
      *
      * @param partIndex The index of the mesh part whose Material to return (-1 for shared material).
-     * 
+     *
      * @return The requested Material, or NULL if no Material is set.
      */
     Material* getMaterial(int partIndex = -1);
@@ -83,12 +83,12 @@ public:
      *
      * Mesh parts will use an explicitly set part material, if set; otherwise they
      * will use the globally set material.
-     * 
+     *
      * @param vshPath The path to the vertex shader file.
      * @param fshPath The path to the fragment shader file.
      * @param defines A new-line delimited list of preprocessor defines. May be NULL.
      * @param partIndex The index of the mesh part to set the material for (-1 for shared material).
-     * 
+     *
      * @return The newly created and bound Material, or NULL if the Material could not be created.
      */
     Material* setMaterial(const char* vshPath, const char* fshPath, const char* defines = NULL, int partIndex = -1);
@@ -103,10 +103,10 @@ public:
      *
      * Mesh parts will use an explicitly set part material, if set; otherwise they
      * will use the globally set material.
-     * 
+     *
      * @param materialPath The path to the material file.
      * @param partIndex The index of the mesh part to set the material for (-1 for shared material).
-     * 
+     *
      * @return The newly created and bound Material, or NULL if the Material could not be created.
      */
     Material* setMaterial(const char* materialPath, int partIndex = -1);
@@ -122,14 +122,14 @@ public:
 
     /**
      * Returns the MeshSkin.
-     * 
+     *
      * @return The MeshSkin, or NULL if one is not set.
      */
     MeshSkin* getSkin() const;
 
     /**
      * Returns the node that is associated with this model.
-     * 
+     *
      * @return The node that is associated with this model.
      */
     Node* getNode() const;
@@ -139,7 +139,7 @@ public:
      *
      * This method is automatically called when a model is attached to a node
      * and therefore should not normally be called explicitly.
-     * 
+     *
      * @param node The node that is associated with this model.
      */
     void setNode(Node* node);
@@ -148,7 +148,7 @@ public:
      * Sets if this model cast shadows.
      *
      * Note: This is only applied to a SceneRenderer.
-     * 
+     *
      * @param casts if this model casts shadows
      * @see SceneRenderer
      */
@@ -172,7 +172,7 @@ public:
     void setShadowReceiver(bool receives);
 
     /**
-     * Returns whether this objects recieves shadows.
+     * Returns whether this objects receives shadows.
      *
      * Note: This is only applied to a SceneRenderer.
      *
@@ -213,7 +213,7 @@ private:
 
     /**
      * Sets the MeshSkin for this model.
-     * 
+     *
      * @param skin The MeshSkin for this model.
      */
     void setSkin(MeshSkin* skin);
@@ -225,7 +225,7 @@ private:
 
     /**
      * Clones the model and returns a new model.
-     * 
+     *
      * @param context The clone context.
      * @return The new cloned model.
      */

+ 1343 - 1331
gameplay/src/Node.cpp

@@ -1,1331 +1,1343 @@
-#include "Base.h"
-#include "Node.h"
-#include "AudioSource.h"
-#include "Scene.h"
-#include "Joint.h"
-#include "PhysicsRigidBody.h"
-#include "PhysicsVehicle.h"
-#include "PhysicsVehicleWheel.h"
-#include "PhysicsGhostObject.h"
-#include "PhysicsCharacter.h"
-#include "Game.h"
-#include "Terrain.h"
-
-// Node dirty flags
-#define NODE_DIRTY_WORLD 1
-#define NODE_DIRTY_BOUNDS 2
-#define NODE_DIRTY_ALL (NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS)
-
-namespace gameplay
-{
-
-Node::Node(const char* id)
-    : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(0), _visible(true),
-    _tags(NULL), _camera(NULL), _light(NULL), _model(NULL), _terrain(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL),
-    _collisionObject(NULL), _agent(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
-{
-    if (id)
-    {
-        _id = id;
-    }
-}
-
-Node::~Node()
-{
-    removeAllChildren();
-
-    if (_model)
-        _model->setNode(NULL);
-    if (_audioSource)
-        _audioSource->setNode(NULL);
-    if (_particleEmitter)
-        _particleEmitter->setNode(NULL);
-    if (_form)
-        _form->setNode(NULL);
-
-    SAFE_RELEASE(_camera);
-    SAFE_RELEASE(_light);
-    SAFE_RELEASE(_model);
-    SAFE_RELEASE(_terrain);
-    SAFE_RELEASE(_audioSource);
-    SAFE_RELEASE(_particleEmitter);
-    SAFE_RELEASE(_form);
-    SAFE_DELETE(_collisionObject);
-    SAFE_DELETE(_tags);
-
-    setAgent(NULL);
-
-    // Cleanup user data
-    if (_userData)
-    {
-        // Call custom cleanup callback if specified
-        if (_userData->cleanupCallback)
-            _userData->cleanupCallback(_userData->pointer);
-        SAFE_DELETE(_userData);
-    }
-}
-
-Node* Node::create(const char* id)
-{
-    return new Node(id);
-}
-
-const char* Node::getId() const
-{
-    return _id.c_str();
-}
-
-void Node::setId(const char* id)
-{
-    if (id)
-    {
-        _id = id;
-    }
-}
-
-Node::Type Node::getType() const
-{
-    return Node::NODE;
-}
-
-void Node::addChild(Node* child)
-{
-    GP_ASSERT(child);
-
-    if (child->_parent == this)
-    {
-        // This node is already present in our hierarchy
-        return;
-    }
-
-    child->addRef();
-
-    // If the item belongs to another hierarchy, remove it first.
-    if (child->_parent)
-    {
-        child->_parent->removeChild(child);
-    }
-    else if (child->_scene)
-    {
-        child->_scene->removeNode(child);
-    }
-
-    // Add child to the end of the list.
-    // NOTE: This is different than the original behavior which inserted nodes
-    // into the beginning of the list. Although slightly slower to add to the
-    // end of the list, it makes scene traversal and drawing order more
-    // predictable, so I've changed it.
-    if (_firstChild)
-    {
-        Node* n = _firstChild;
-        while (n->_nextSibling)
-            n = n->_nextSibling;
-        n->_nextSibling = child;
-        child->_prevSibling = n;
-    }
-    else
-    {
-        _firstChild = child;
-    }
-
-    child->_parent = this;
-
-    ++_childCount;
-
-    setBoundsDirty();
-
-    if (_notifyHierarchyChanged)
-    {
-        hierarchyChanged();
-    }
-}
-
-void Node::removeChild(Node* child)
-{
-    if (child == NULL || child->_parent != this)
-    {
-        // The child is not in our hierarchy.
-        return;
-    }
-
-    // Call remove on the child.
-    child->remove();
-
-    SAFE_RELEASE(child);
-}
-
-void Node::removeAllChildren()
-{
-    _notifyHierarchyChanged = false;
-
-    while (_firstChild)
-    {
-        removeChild(_firstChild);
-    }
-
-    _notifyHierarchyChanged = true;
-    hierarchyChanged();
-}
-
-void Node::remove()
-{
-    // Re-link our neighbours.
-    if (_prevSibling)
-    {
-        _prevSibling->_nextSibling = _nextSibling;
-    }
-    if (_nextSibling)
-    {
-        _nextSibling->_prevSibling = _prevSibling;
-    }
-
-    // Update our parent.
-    Node* parent = _parent;
-    if (parent)
-    {
-        if (this == parent->_firstChild)
-        {
-            parent->_firstChild = _nextSibling;
-        }
-
-        --parent->_childCount;
-    }
-
-    _nextSibling = NULL;
-    _prevSibling = NULL;
-    _parent = NULL;
-
-    if (parent && parent->_notifyHierarchyChanged)
-    {
-        parent->hierarchyChanged();
-    }
-}
-
-Node* Node::getFirstChild() const
-{
-    return _firstChild;
-}
-
-Node* Node::getNextSibling() const
-{
-    return _nextSibling;
-}
-
-Node* Node::getPreviousSibling() const
-{
-    return _prevSibling;
-}
-
-Node* Node::getParent() const
-{
-    return _parent;
-}
-
-bool Node::hasTag(const char* name) const
-{
-    GP_ASSERT(name);
-
-    return (_tags ? _tags->find(name) != _tags->end() : false);
-}
-
-const char* Node::getTag(const char* name) const
-{
-    GP_ASSERT(name);
-
-    if (!_tags)
-        return NULL;
-
-    std::map<std::string, std::string>::const_iterator itr = _tags->find(name);
-    return (itr == _tags->end() ? NULL : itr->second.c_str());
-}
-
-void Node::setTag(const char* name, const char* value)
-{
-    GP_ASSERT(name);
-
-    if (value == NULL)
-    {
-        // Removing tag
-        if (_tags)
-        {
-            _tags->erase(name);
-            if (_tags->size() == 0)
-                SAFE_DELETE(_tags);
-        }
-    }
-    else
-    {
-        // Setting tag
-        if (_tags == NULL)
-            _tags = new std::map<std::string, std::string>();
-
-        (*_tags)[name] = value;
-    }
-}
-
-void* Node::getUserPointer() const
-{
-    return (_userData ? _userData->pointer : NULL);
-}
-
-void Node::setUserPointer(void* pointer, void (*cleanupCallback)(void*))
-{
-    // If existing user pointer is being changed, call cleanup function to free previous pointer
-    if (_userData && _userData->pointer && _userData->cleanupCallback && pointer != _userData->pointer)
-    {
-        _userData->cleanupCallback(_userData->pointer);
-    }
-
-    if (pointer)
-    {
-        // Assign user pointer
-        if (_userData == NULL)
-            _userData = new UserData();
-
-        _userData->pointer = pointer;
-        _userData->cleanupCallback = cleanupCallback;
-    }
-    else
-    {
-        // Clear user pointer
-        SAFE_DELETE(_userData);
-    }
-}
-
-void Node::setVisible(bool visible)
-{
-    if (_visible != visible)
-    {
-        _visible = visible;
-    }
-}
-
-bool Node::isVisible() const
-{
-    return _visible;
-}
-
-bool Node::isVisibleInHierarchy() const
-{
-   if (!_visible)
-       return false;
-   Node* node = _parent;
-   while (node)
-   {
-       if (!node->_visible)
-           return false;
-   }
-   return true;
-}
-
-unsigned int Node::getChildCount() const
-{
-    return _childCount;
-}
-
-Node* Node::findNode(const char* id, bool recursive, bool exactMatch) const
-{
-    GP_ASSERT(id);
-
-    // If the node has a model with a mesh skin, search the skin's hierarchy as well.
-    Node* rootNode = NULL;
-    if (_model != NULL && _model->getSkin() != NULL && (rootNode = _model->getSkin()->_rootNode) != NULL)
-    {
-        if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
-            return rootNode;
-        
-        Node* match = rootNode->findNode(id, true, exactMatch);
-        if (match)
-        {
-            return match;
-        }
-    }
-    
-    // Search immediate children first.
-    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-    {
-        // Does this child's ID match?
-        if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
-        {
-            return child;
-        }
-    }
-
-    // Recurse.
-    if (recursive)
-    {
-        for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-        {
-            Node* match = child->findNode(id, true, exactMatch);
-            if (match)
-            {
-                return match;
-            }
-        }
-    }
-
-    return NULL;
-}   
-
-unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch) const
-{
-    GP_ASSERT(id);
-    
-    unsigned int count = 0;
-
-    // If the node has a model with a mesh skin, search the skin's hierarchy as well.
-    Node* rootNode = NULL;
-    if (_model != NULL && _model->getSkin() != NULL && (rootNode = _model->getSkin()->_rootNode) != NULL)
-    {
-        if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
-        {
-            nodes.push_back(rootNode);
-            ++count;
-        }
-        count += rootNode->findNodes(id, nodes, true, exactMatch);
-    }
-
-    // Search immediate children first.
-    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-    {
-        // Does this child's ID match?
-        if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
-        {
-            nodes.push_back(child);
-            ++count;
-        }
-    }
-
-    // Recurse.
-    if (recursive)
-    {
-        for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-        {
-            count += child->findNodes(id, nodes, true, exactMatch);
-        }
-    }
-
-    return count;
-}
-
-Scene* Node::getScene() const
-{
-    if (_scene)
-        return _scene;
-
-    // Search our parent for the scene
-    if (_parent)
-    {
-        Scene* scene = _parent->getScene();
-        if (scene)
-            return scene;
-    }
-
-    return NULL;
-}
-
-Node* Node::getRootNode() const
-{
-    Node* n = const_cast<Node*>(this);
-    while (n->getParent())
-    {
-        n = n->getParent();
-    }
-    return n;
-}
-
-bool Node::isStatic() const
-{
-    return (_collisionObject && _collisionObject->isStatic());
-}
-
-const Matrix& Node::getWorldMatrix() const
-{
-    if (_dirtyBits & NODE_DIRTY_WORLD)
-    {
-        // Clear our dirty flag immediately to prevent this block from being entered if our
-        // parent calls our getWorldMatrix() method as a result of the following calculations.
-        _dirtyBits &= ~NODE_DIRTY_WORLD;
-
-        if (!isStatic())
-        {
-            // If we have a parent, multiply our parent world transform by our local
-            // transform to obtain our final resolved world transform.
-            Node* parent = getParent();
-            if (parent && (!_collisionObject || _collisionObject->isKinematic()))
-            {
-                Matrix::multiply(parent->getWorldMatrix(), getMatrix(), &_world);
-            }
-            else
-            {
-                _world = getMatrix();
-            }
-
-            // Our world matrix was just updated, so call getWorldMatrix() on all child nodes
-            // to force their resolved world matrices to be updated.
-            for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-            {
-                child->getWorldMatrix();
-            }
-        }
-    }
-
-    return _world;
-}
-
-const Matrix& Node::getWorldViewMatrix() const
-{
-    static Matrix worldView;
-
-    Matrix::multiply(getViewMatrix(), getWorldMatrix(), &worldView);
-
-    return worldView;
-}
-
-const Matrix& Node::getInverseTransposeWorldViewMatrix() const
-{
-    static Matrix invTransWorldView;
-    Matrix::multiply(getViewMatrix(), getWorldMatrix(), &invTransWorldView);
-    invTransWorldView.invert();
-    invTransWorldView.transpose();
-    return invTransWorldView;
-}
-
-const Matrix& Node::getInverseTransposeWorldMatrix() const
-{
-    static Matrix invTransWorld;
-    invTransWorld = getWorldMatrix();
-    invTransWorld.invert();
-    invTransWorld.transpose();
-    return invTransWorld;
-}
-
-const Matrix& Node::getViewMatrix() const
-{
-    Scene* scene = getScene();
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (camera)
-    {
-        return camera->getViewMatrix();
-    }
-    else
-    {
-        return Matrix::identity();
-    }
-}
-
-const Matrix& Node::getInverseViewMatrix() const
-{
-    Scene* scene = getScene();
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (camera)
-    {
-        return camera->getInverseViewMatrix();
-    }
-    else
-    {
-        return Matrix::identity();
-    }
-}
-
-const Matrix& Node::getProjectionMatrix() const
-{
-    Scene* scene = getScene();
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (camera)
-    {
-        return camera->getProjectionMatrix();
-    }
-    else
-    {
-        return Matrix::identity();
-    }
-}
-
-const Matrix& Node::getViewProjectionMatrix() const
-{
-    Scene* scene = getScene();
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (camera)
-    {
-        return camera->getViewProjectionMatrix();
-    }
-    else
-    {
-        return Matrix::identity();
-    }
-}
-
-const Matrix& Node::getInverseViewProjectionMatrix() const
-{
-    Scene* scene = getScene();
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (camera)
-    {
-        return camera->getInverseViewProjectionMatrix();
-    }
-
-    return Matrix::identity();
-}
-
-const Matrix& Node::getWorldViewProjectionMatrix() const
-{
-    static Matrix worldViewProj;
-
-    // Always re-calculate worldViewProjection matrix since it's extremely difficult
-    // to track whether the camera has changed (it may frequently change every frame).
-    Matrix::multiply(getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
-
-    return worldViewProj;
-}
-
-Vector3 Node::getTranslationWorld() const
-{
-    Vector3 translation;
-    getWorldMatrix().getTranslation(&translation);
-    return translation;
-}
-
-Vector3 Node::getTranslationView() const
-{
-    Vector3 translation;
-    getWorldMatrix().getTranslation(&translation);
-    getViewMatrix().transformPoint(&translation);
-    return translation;
-}
-
-Vector3 Node::getForwardVectorWorld() const
-{
-    Vector3 vector;
-    getWorldMatrix().getForwardVector(&vector);
-    return vector;
-}
-
-Vector3 Node::getForwardVectorView() const
-{
-    Vector3 vector;
-    getWorldMatrix().getForwardVector(&vector);
-    getViewMatrix().transformVector(&vector);
-    return vector;
-}
-
-Vector3 Node::getRightVectorWorld() const
-{
-    Vector3 vector;
-    getWorldMatrix().getRightVector(&vector);
-    return vector;
-}
-
-Vector3 Node::getUpVectorWorld() const
-{
-    Vector3 vector;
-    getWorldMatrix().getUpVector(&vector);
-    return vector;
-}
-
-Vector3 Node::getActiveCameraTranslationWorld() const
-{
-    Scene* scene = getScene();
-    if (scene)
-    {
-        Camera* camera = scene->getActiveCamera();
-        if (camera)
-        {
-            Node* cameraNode = camera->getNode();
-            if (cameraNode)
-            {
-                return cameraNode->getTranslationWorld();
-            }
-        }
-    }
-
-    return Vector3::zero();
-}
-
-Vector3 Node::getActiveCameraTranslationView() const
-{
-    Scene* scene = getScene();
-    if (scene)
-    {
-        Camera* camera = scene->getActiveCamera();
-        if (camera)
-        {
-            Node* cameraNode = camera->getNode();
-            if (cameraNode)
-            {
-                return cameraNode->getTranslationView();
-            }
-        }
-    }
-
-    return Vector3::zero();
-}
-
-void Node::hierarchyChanged()
-{
-    // When our hierarchy changes our world transform is affected, so we must dirty it.
-    transformChanged();
-}
-
-void Node::transformChanged()
-{
-    // Our local transform was changed, so mark our world matrices dirty.
-    _dirtyBits |= NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS;
-
-    // Notify our children that their transform has also changed (since transforms are inherited).
-    for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
-    {
-        if (Transform::isTransformChangedSuspended())
-        {
-            // If the DIRTY_NOTIFY bit is not set
-            if (!n->isDirty(Transform::DIRTY_NOTIFY))
-            {
-                n->transformChanged();
-                suspendTransformChange(n);
-            }
-        }
-        else
-        {
-            n->transformChanged();
-        }
-    }
-
-    Transform::transformChanged();
-}
-
-void Node::setBoundsDirty()
-{
-    // Mark ourself and our parent nodes as dirty
-    _dirtyBits |= NODE_DIRTY_BOUNDS;
-
-    // Mark our parent bounds as dirty as well
-    if (_parent)
-        _parent->setBoundsDirty();
-}
-
-Animation* Node::getAnimation(const char* id) const
-{
-    Animation* animation = ((AnimationTarget*)this)->getAnimation(id);
-    if (animation)
-        return animation;
-    
-    // See if this node has a model, then drill down.
-    Model* model = this->getModel();
-    if (model)
-    {
-        // Check to see if there's any animations with the ID on the joints.
-        MeshSkin* skin = model->getSkin();
-        if (skin)
-        {
-            Node* rootNode = skin->_rootNode;
-            if (rootNode)
-            {
-                animation = rootNode->getAnimation(id);
-                if (animation)
-                    return animation;
-            }
-        }
-
-        // Check to see if any of the model's material parameter's has an animation
-        // with the given ID.
-        Material* material = model->getMaterial();
-        if (material)
-        {
-            // How to access material parameters? hidden on the Material::RenderState.
-            std::vector<MaterialParameter*>::iterator itr = material->_parameters.begin();
-            for (; itr != material->_parameters.end(); itr++)
-            {
-                GP_ASSERT(*itr);
-                animation = ((MaterialParameter*)(*itr))->getAnimation(id);
-                if (animation)
-                    return animation;
-            }
-        }
-    }
-
-    // look through form for animations.
-    Form* form = this->getForm();
-    if (form)
-    {
-        animation = form->getAnimation(id);
-        if (animation)
-            return animation;
-    }
-
-    // Look through this node's children for an animation with the specified ID.
-    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-    {
-        animation = child->getAnimation(id);
-        if (animation)
-            return animation;
-    }
-    
-    return NULL;
-}
-
-Camera* Node::getCamera() const
-{
-    return _camera;
-}
-
-void Node::setCamera(Camera* camera)
-{
-    if (_camera != camera)
-    {
-        if (_camera)
-        {
-            _camera->setNode(NULL);
-            SAFE_RELEASE(_camera);
-        }
-
-        _camera = camera;
-
-        if (_camera)
-        {
-            _camera->addRef();
-            _camera->setNode(this);
-        }
-    }
-}
-
-Light* Node::getLight() const
-{
-    return _light;
-}
-
-void Node::setLight(Light* light)
-{
-    if (_light != light)
-    {
-        if (_light)
-        {
-            _light->setNode(NULL);
-            SAFE_RELEASE(_light);
-        }
-
-        _light = light;
-
-        if (_light)
-        {
-            _light->addRef();
-            _light->setNode(this);
-        }
-
-        setBoundsDirty();
-    }
-}
-
-Model* Node::getModel() const
-{
-    return _model;
-}
-
-void Node::setModel(Model* model)
-{
-    if (_model != model)
-    {
-        if (_model)
-        {
-            _model->setNode(NULL);
-            SAFE_RELEASE(_model);
-        }
-
-        _model = model;
-
-        if (_model)
-        {
-            _model->addRef();
-            _model->setNode(this);
-        }
-    }
-}
-
-Terrain* Node::getTerrain() const
-{
-    return _terrain;
-}
-
-void Node::setTerrain(Terrain* terrain)
-{
-    if (_terrain != terrain)
-    {
-        if (_terrain)
-        {
-            _terrain->setNode(NULL);
-            SAFE_RELEASE(_terrain);
-        }
-
-        _terrain = terrain;
-
-        if (_terrain)
-        {
-            _terrain->addRef();
-            _terrain->setNode(this);
-        }
-
-        setBoundsDirty();
-    }
-}
-
-Form* Node::getForm() const
-{
-    return _form;
-}
-
-void Node::setForm(Form* form)
-{
-    if (_form != form)
-    {
-        if (_form)
-        {
-            _form->setNode(NULL);
-            SAFE_RELEASE(_form);
-        }
-
-        _form = form;
-
-        if (_form)
-        {
-            _form->addRef();
-            _form->setNode(this);
-        }
-    }
-}
-
-const BoundingSphere& Node::getBoundingSphere() const
-{
-    if (_dirtyBits & NODE_DIRTY_BOUNDS)
-    {
-        _dirtyBits &= ~NODE_DIRTY_BOUNDS;
-
-        const Matrix& worldMatrix = getWorldMatrix();
-
-        // Start with our local bounding sphere
-        // TODO: Incorporate bounds from entities other than mesh (i.e. emitters, audiosource, etc)
-        bool empty = true;
-        if (_terrain)
-        {
-            _bounds.set(_terrain->getBoundingBox());
-            empty = false;
-        }
-        if (_model && _model->getMesh())
-        {
-            if (empty)
-            {
-                _bounds.set(_model->getMesh()->getBoundingSphere());
-                empty = false;
-            }
-            else
-            {
-                _bounds.merge(_model->getMesh()->getBoundingSphere());
-            }
-        }
-        if (_light)
-        {
-            switch (_light->getLightType())
-            {
-            case Light::POINT:
-                if (empty)
-                {
-                    _bounds.set(Vector3::zero(), _light->getRange());
-                    empty = false;
-                }
-                else
-                {
-                    _bounds.merge(BoundingSphere(Vector3::zero(), _light->getRange()));
-                }
-                break;
-            case Light::SPOT:
-                // TODO: Implement spot light bounds
-                break;
-            }
-        }
-        if (empty)
-        {
-            // Empty bounding sphere, set the world translation with zero radius
-            worldMatrix.getTranslation(&_bounds.center);
-            _bounds.radius = 0;
-        }
-
-        // Transform the sphere (if not empty) into world space.
-        if (!empty)
-        {
-            bool applyWorldTransform = true;
-            if (_model && _model->getSkin())
-            {
-                // Special case: If the root joint of our mesh skin is parented by any nodes, 
-                // multiply the world matrix of the root joint's parent by this node's
-                // world matrix. This computes a final world matrix used for transforming this
-                // node's bounding volume. This allows us to store a much smaller bounding
-                // volume approximation than would otherwise be possible for skinned meshes,
-                // since joint parent nodes that are not in the matrix palette do not need to
-                // be considered as directly transforming vertices on the GPU (they can instead
-                // be applied directly to the bounding volume transformation below).
-                GP_ASSERT(_model->getSkin()->getRootJoint());
-                Node* jointParent = _model->getSkin()->getRootJoint()->getParent();
-                if (jointParent)
-                {
-                    // TODO: Should we protect against the case where joints are nested directly
-                    // in the node hierachy of the model (this is normally not the case)?
-                    Matrix boundsMatrix;
-                    Matrix::multiply(getWorldMatrix(), jointParent->getWorldMatrix(), &boundsMatrix);
-                    _bounds.transform(boundsMatrix);
-                    applyWorldTransform = false;
-                }
-            }
-            if (applyWorldTransform)
-            {
-                _bounds.transform(getWorldMatrix());
-            }
-        }
-
-        // Merge this world-space bounding sphere with our childrens' bounding volumes.
-        for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
-        {
-            const BoundingSphere& childSphere = n->getBoundingSphere();
-            if (!childSphere.isEmpty())
-            {
-                if (empty)
-                {
-                    _bounds.set(childSphere);
-                    empty = false;
-                }
-                else
-                {
-                    _bounds.merge(childSphere);
-                }
-            }
-        }
-    }
-
-    return _bounds;
-}
-
-Node* Node::clone() const
-{
-    NodeCloneContext context;
-    return cloneRecursive(context);
-}
-
-Node* Node::cloneSingleNode(NodeCloneContext &context) const
-{
-    Node* copy = Node::create(getId());
-    context.registerClonedNode(this, copy);
-    cloneInto(copy, context);
-    return copy;
-}
-
-Node* Node::cloneRecursive(NodeCloneContext &context) const
-{
-    Node* copy = cloneSingleNode(context);
-    GP_ASSERT(copy);
-
-    // Add child nodes
-    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
-    {
-        Node* childCopy = child->cloneRecursive(context);
-        GP_ASSERT(childCopy);
-        copy->addChild(childCopy);
-        childCopy->release();
-    }
-
-    return copy;
-}
-
-void Node::cloneInto(Node* node, NodeCloneContext &context) const
-{
-    GP_ASSERT(node);
-    Transform::cloneInto(node, context);
-
-    // TODO: Clone the rest of the node data.
-
-    if (Camera* camera = getCamera())
-    {
-        Camera* cameraClone = camera->clone(context);
-        node->setCamera(cameraClone);
-        cameraClone->release();
-    }
-    if (Light* light = getLight())
-    {
-        Light* lightClone = light->clone(context);
-        node->setLight(lightClone);
-        lightClone->release();
-    }
-    if (AudioSource* audio = getAudioSource())
-    {
-        AudioSource* audioClone = audio->clone(context);
-        node->setAudioSource(audioClone);
-        audioClone->release();
-    }
-    if (Model* model = getModel())
-    {
-        Model* modelClone = model->clone(context);
-        node->setModel(modelClone);
-        modelClone->release();
-    }
-    if (ParticleEmitter* emitter = getParticleEmitter())
-    {
-        ParticleEmitter* emitterClone = emitter->clone();
-        node->setParticleEmitter(emitterClone);
-        emitterClone->release();
-    }
-    node->_world = _world;
-    node->_bounds = _bounds;
-
-    // Note: Do not clone _userData - we can't make any assumptions about its content and how it's managed,
-    // so it's the caller's responsibility to clone user data if needed.
-
-    if (_tags)
-    {
-        node->_tags = new std::map<std::string, std::string>(_tags->begin(), _tags->end());
-    }
-}
-
-AudioSource* Node::getAudioSource() const
-{
-    return _audioSource;
-}
-
-void Node::setAudioSource(AudioSource* audio)
-{
-    if (_audioSource != audio)
-    {
-        if (_audioSource)
-        {
-            _audioSource->setNode(NULL);
-            SAFE_RELEASE(_audioSource);
-        }
-        
-        _audioSource = audio;
-
-        if (_audioSource)
-        {
-            _audioSource->addRef();
-            _audioSource->setNode(this);
-        }
-    }
-}
-
-ParticleEmitter* Node::getParticleEmitter() const
-{
-    return _particleEmitter;
-}
-
-void Node::setParticleEmitter(ParticleEmitter* emitter)
-{
-    if (_particleEmitter != emitter)
-    {
-        if (_particleEmitter)
-        {
-            _particleEmitter->setNode(NULL);
-            SAFE_RELEASE(_particleEmitter);
-        }
-        
-        _particleEmitter = emitter;
-
-        if (_particleEmitter)
-        {
-            _particleEmitter->addRef();
-            _particleEmitter->setNode(this);
-        }
-    }
-}
-
-PhysicsCollisionObject* Node::getCollisionObject() const
-{
-    return _collisionObject;
-}
-
-PhysicsCollisionObject* Node::setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters, int group, int mask)
-{
-    SAFE_DELETE(_collisionObject);
-
-    switch (type)
-    {
-    case PhysicsCollisionObject::RIGID_BODY:
-        {
-            _collisionObject = new PhysicsRigidBody(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters(), group, mask);
-        }
-        break;
-
-    case PhysicsCollisionObject::GHOST_OBJECT:
-        {
-            _collisionObject = new PhysicsGhostObject(this, shape, group, mask);
-        }
-        break;
-
-    case PhysicsCollisionObject::CHARACTER:
-        {
-            _collisionObject = new PhysicsCharacter(this, shape, rigidBodyParameters ? rigidBodyParameters->mass : 1.0f);
-        }
-        break;
-
-    case PhysicsCollisionObject::VEHICLE:
-        {
-            _collisionObject = new PhysicsVehicle(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
-        }
-        break;
-
-    case PhysicsCollisionObject::VEHICLE_WHEEL:
-        {
-            //
-            // PhysicsVehicleWheel is special because this call will traverse up the scene graph for the
-            // first ancestor node that is shared with another node of collision type VEHICLE, and then
-            // proceed to add itself as a wheel onto that vehicle. This is by design, and allows the
-            // visual scene hierarchy to be the sole representation of the relationship between physics
-            // objects rather than forcing that upon the otherwise-flat ".physics" (properties) file.
-            //
-            // IMPORTANT: The VEHICLE must come before the VEHICLE_WHEEL in the ".scene" (properties) file!
-            //
-            _collisionObject = new PhysicsVehicleWheel(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
-        }
-        break;
-
-    case PhysicsCollisionObject::NONE:
-        break;  // Already deleted, Just don't add a new collision object back.
-    }
-
-    return _collisionObject;
-}
-
-PhysicsCollisionObject* Node::setCollisionObject(const char* url)
-{
-    // Load the collision object properties from file.
-    Properties* properties = Properties::create(url);
-    if (properties == NULL)
-    {
-        GP_ERROR("Failed to load collision object file: %s", url);
-        return NULL;
-    }
-
-    PhysicsCollisionObject* collisionObject = setCollisionObject((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());
-    SAFE_DELETE(properties);
-
-    return collisionObject;
-}
-
-PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
-{
-    SAFE_DELETE(_collisionObject);
-
-    // Check if the properties is valid.
-    if (!properties || !(strcmp(properties->getNamespace(), "collisionObject") == 0))
-    {
-        GP_ERROR("Failed to load collision object from properties object: must be non-null object and have namespace equal to 'collisionObject'.");
-        return NULL;
-    }
-
-    if (const char* type = properties->getString("type"))
-    {
-        if (strcmp(type, "CHARACTER") == 0)
-        {
-            _collisionObject = PhysicsCharacter::create(this, properties);
-        }
-        else if (strcmp(type, "GHOST_OBJECT") == 0)
-        {
-            _collisionObject = PhysicsGhostObject::create(this, properties);
-        }
-        else if (strcmp(type, "RIGID_BODY") == 0)
-        {
-            _collisionObject = PhysicsRigidBody::create(this, properties);
-        }
-        else if (strcmp(type, "VEHICLE") == 0)
-        {
-            _collisionObject = PhysicsVehicle::create(this, properties);
-        }
-        else if (strcmp(type, "VEHICLE_WHEEL") == 0)
-        {
-            //
-            // PhysicsVehicleWheel is special because this call will traverse up the scene graph for the
-            // first ancestor node that is shared with another node of collision type VEHICLE, and then
-            // proceed to add itself as a wheel onto that vehicle. This is by design, and allows the
-            // visual scene hierarchy to be the sole representation of the relationship between physics
-            // objects rather than forcing that upon the otherwise-flat ".physics" (properties) file.
-            //
-            // IMPORTANT: The VEHICLE must come before the VEHICLE_WHEEL in the ".scene" (properties) file!
-            //
-            _collisionObject = PhysicsVehicleWheel::create(this, properties);
-        }
-        else
-        {
-            GP_ERROR("Unsupported collision object type '%s'.", type);
-            return NULL;
-        }
-    }
-    else
-    {
-        GP_ERROR("Failed to load collision object from properties object; required attribute 'type' is missing.");
-        return NULL;
-    }
-
-    return _collisionObject;
-}
-
-AIAgent* Node::getAgent() const
-{
-    return _agent;
-}
-
-void Node::setAgent(AIAgent* agent)
-{
-    if (agent != _agent)
-    {
-        if (_agent)
-        {
-            Game::getInstance()->getAIController()->removeAgent(_agent);
-            _agent->_node = NULL;
-            SAFE_RELEASE(_agent);
-        }
-
-        _agent = agent;
-
-        if (_agent)
-        {
-            _agent->addRef();
-            _agent->_node = this;
-            Game::getInstance()->getAIController()->addAgent(_agent);
-        }
-    }
-}
-
-NodeCloneContext::NodeCloneContext()
-{
-}
-
-NodeCloneContext::~NodeCloneContext()
-{
-}
-
-Animation* NodeCloneContext::findClonedAnimation(const Animation* animation)
-{
-    GP_ASSERT(animation);
-
-    std::map<const Animation*, Animation*>::iterator it = _clonedAnimations.find(animation);
-    return it != _clonedAnimations.end() ? it->second : NULL;
-}
-
-void NodeCloneContext::registerClonedAnimation(const Animation* original, Animation* clone)
-{
-    GP_ASSERT(original);
-    GP_ASSERT(clone);
-
-    _clonedAnimations[original] = clone;
-}
-
-Node* NodeCloneContext::findClonedNode(const Node* node)
-{
-    GP_ASSERT(node);
-
-    std::map<const Node*, Node*>::iterator it = _clonedNodes.find(node);
-    return it != _clonedNodes.end() ? it->second : NULL;
-}
-
-void NodeCloneContext::registerClonedNode(const Node* original, Node* clone)
-{
-    GP_ASSERT(original);
-    GP_ASSERT(clone);
-
-    _clonedNodes[original] = clone;
-}
-
-}
+#include "Base.h"
+#include "Node.h"
+#include "AudioSource.h"
+#include "Scene.h"
+#include "Joint.h"
+#include "PhysicsRigidBody.h"
+#include "PhysicsVehicle.h"
+#include "PhysicsVehicleWheel.h"
+#include "PhysicsGhostObject.h"
+#include "PhysicsCharacter.h"
+#include "Game.h"
+#include "Terrain.h"
+
+// Node dirty flags
+#define NODE_DIRTY_WORLD 1
+#define NODE_DIRTY_BOUNDS 2
+#define NODE_DIRTY_ALL (NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS)
+
+namespace gameplay
+{
+
+Node::Node(const char* id)
+    : _scene(NULL), _firstChild(NULL), _nextSibling(NULL), _prevSibling(NULL), _parent(NULL), _childCount(0), _active(true),
+    _tags(NULL), _camera(NULL), _light(NULL), _model(NULL), _terrain(NULL), _form(NULL), _audioSource(NULL), _particleEmitter(NULL),
+    _collisionObject(NULL), _agent(NULL), _dirtyBits(NODE_DIRTY_ALL), _notifyHierarchyChanged(true), _userData(NULL)
+{
+    if (id)
+    {
+        _id = id;
+    }
+}
+
+Node::~Node()
+{
+    removeAllChildren();
+
+    if (_model)
+        _model->setNode(NULL);
+    if (_audioSource)
+        _audioSource->setNode(NULL);
+    if (_particleEmitter)
+        _particleEmitter->setNode(NULL);
+    if (_form)
+        _form->setNode(NULL);
+
+    SAFE_RELEASE(_camera);
+    SAFE_RELEASE(_light);
+    SAFE_RELEASE(_model);
+    SAFE_RELEASE(_terrain);
+    SAFE_RELEASE(_audioSource);
+    SAFE_RELEASE(_particleEmitter);
+    SAFE_RELEASE(_form);
+    SAFE_DELETE(_collisionObject);
+    SAFE_DELETE(_tags);
+
+    setAgent(NULL);
+
+    // Cleanup user data
+    if (_userData)
+    {
+        // Call custom cleanup callback if specified
+        if (_userData->cleanupCallback)
+            _userData->cleanupCallback(_userData->pointer);
+        SAFE_DELETE(_userData);
+    }
+}
+
+Node* Node::create(const char* id)
+{
+    return new Node(id);
+}
+
+const char* Node::getId() const
+{
+    return _id.c_str();
+}
+
+void Node::setId(const char* id)
+{
+    if (id)
+    {
+        _id = id;
+    }
+}
+
+Node::Type Node::getType() const
+{
+    return Node::NODE;
+}
+
+void Node::addChild(Node* child)
+{
+    GP_ASSERT(child);
+
+    if (child->_parent == this)
+    {
+        // This node is already present in our hierarchy
+        return;
+    }
+
+    child->addRef();
+
+    // If the item belongs to another hierarchy, remove it first.
+    if (child->_parent)
+    {
+        child->_parent->removeChild(child);
+    }
+    else if (child->_scene)
+    {
+        child->_scene->removeNode(child);
+    }
+
+    // Add child to the end of the list.
+    // NOTE: This is different than the original behavior which inserted nodes
+    // into the beginning of the list. Although slightly slower to add to the
+    // end of the list, it makes scene traversal and drawing order more
+    // predictable, so I've changed it.
+    if (_firstChild)
+    {
+        Node* n = _firstChild;
+        while (n->_nextSibling)
+            n = n->_nextSibling;
+        n->_nextSibling = child;
+        child->_prevSibling = n;
+    }
+    else
+    {
+        _firstChild = child;
+    }
+
+    child->_parent = this;
+
+    ++_childCount;
+
+    setBoundsDirty();
+
+    if (_notifyHierarchyChanged)
+    {
+        hierarchyChanged();
+    }
+}
+
+void Node::removeChild(Node* child)
+{
+    if (child == NULL || child->_parent != this)
+    {
+        // The child is not in our hierarchy.
+        return;
+    }
+
+    // Call remove on the child.
+    child->remove();
+
+    SAFE_RELEASE(child);
+}
+
+void Node::removeAllChildren()
+{
+    _notifyHierarchyChanged = false;
+
+    while (_firstChild)
+    {
+        removeChild(_firstChild);
+    }
+
+    _notifyHierarchyChanged = true;
+    hierarchyChanged();
+}
+
+void Node::remove()
+{
+    // Re-link our neighbours.
+    if (_prevSibling)
+    {
+        _prevSibling->_nextSibling = _nextSibling;
+    }
+    if (_nextSibling)
+    {
+        _nextSibling->_prevSibling = _prevSibling;
+    }
+
+    // Update our parent.
+    Node* parent = _parent;
+    if (parent)
+    {
+        if (this == parent->_firstChild)
+        {
+            parent->_firstChild = _nextSibling;
+        }
+
+        --parent->_childCount;
+    }
+
+    _nextSibling = NULL;
+    _prevSibling = NULL;
+    _parent = NULL;
+
+    if (parent && parent->_notifyHierarchyChanged)
+    {
+        parent->hierarchyChanged();
+    }
+}
+
+Node* Node::getFirstChild() const
+{
+    return _firstChild;
+}
+
+Node* Node::getNextSibling() const
+{
+    return _nextSibling;
+}
+
+Node* Node::getPreviousSibling() const
+{
+    return _prevSibling;
+}
+
+Node* Node::getParent() const
+{
+    return _parent;
+}
+
+bool Node::hasTag(const char* name) const
+{
+    GP_ASSERT(name);
+
+    return (_tags ? _tags->find(name) != _tags->end() : false);
+}
+
+const char* Node::getTag(const char* name) const
+{
+    GP_ASSERT(name);
+
+    if (!_tags)
+        return NULL;
+
+    std::map<std::string, std::string>::const_iterator itr = _tags->find(name);
+    return (itr == _tags->end() ? NULL : itr->second.c_str());
+}
+
+void Node::setTag(const char* name, const char* value)
+{
+    GP_ASSERT(name);
+
+    if (value == NULL)
+    {
+        // Removing tag
+        if (_tags)
+        {
+            _tags->erase(name);
+            if (_tags->size() == 0)
+                SAFE_DELETE(_tags);
+        }
+    }
+    else
+    {
+        // Setting tag
+        if (_tags == NULL)
+            _tags = new std::map<std::string, std::string>();
+
+        (*_tags)[name] = value;
+    }
+}
+
+void* Node::getUserPointer() const
+{
+    return (_userData ? _userData->pointer : NULL);
+}
+
+void Node::setUserPointer(void* pointer, void (*cleanupCallback)(void*))
+{
+    // If existing user pointer is being changed, call cleanup function to free previous pointer
+    if (_userData && _userData->pointer && _userData->cleanupCallback && pointer != _userData->pointer)
+    {
+        _userData->cleanupCallback(_userData->pointer);
+    }
+
+    if (pointer)
+    {
+        // Assign user pointer
+        if (_userData == NULL)
+            _userData = new UserData();
+
+        _userData->pointer = pointer;
+        _userData->cleanupCallback = cleanupCallback;
+    }
+    else
+    {
+        // Clear user pointer
+        SAFE_DELETE(_userData);
+    }
+}
+
+void Node::setActive(bool active)
+{
+    if (_active != active)
+    {
+        if (_collisionObject)
+            _collisionObject->setEnabled(active);
+
+        _active = active;
+    }
+}
+
+bool Node::isActive() const
+{
+    return _active;
+}
+
+bool Node::isActiveInHierarchy() const
+{
+    if (!_active)
+       return false;
+   Node* node = _parent;
+   while (node)
+   {
+       if (!node->_active)
+           return false;
+   }
+   return true;
+}
+
+unsigned int Node::getChildCount() const
+{
+    return _childCount;
+}
+
+Node* Node::findNode(const char* id, bool recursive, bool exactMatch) const
+{
+    GP_ASSERT(id);
+
+    // If the node has a model with a mesh skin, search the skin's hierarchy as well.
+    Node* rootNode = NULL;
+    if (_model != NULL && _model->getSkin() != NULL && (rootNode = _model->getSkin()->_rootNode) != NULL)
+    {
+        if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
+            return rootNode;
+        
+        Node* match = rootNode->findNode(id, true, exactMatch);
+        if (match)
+        {
+            return match;
+        }
+    }
+    
+    // Search immediate children first.
+    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        // Does this child's ID match?
+        if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
+        {
+            return child;
+        }
+    }
+
+    // Recurse.
+    if (recursive)
+    {
+        for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+        {
+            Node* match = child->findNode(id, true, exactMatch);
+            if (match)
+            {
+                return match;
+            }
+        }
+    }
+
+    return NULL;
+}   
+
+unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool recursive, bool exactMatch) const
+{
+    GP_ASSERT(id);
+    
+    unsigned int count = 0;
+
+    // If the node has a model with a mesh skin, search the skin's hierarchy as well.
+    Node* rootNode = NULL;
+    if (_model != NULL && _model->getSkin() != NULL && (rootNode = _model->getSkin()->_rootNode) != NULL)
+    {
+        if ((exactMatch && rootNode->_id == id) || (!exactMatch && rootNode->_id.find(id) == 0))
+        {
+            nodes.push_back(rootNode);
+            ++count;
+        }
+        count += rootNode->findNodes(id, nodes, true, exactMatch);
+    }
+
+    // Search immediate children first.
+    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        // Does this child's ID match?
+        if ((exactMatch && child->_id == id) || (!exactMatch && child->_id.find(id) == 0))
+        {
+            nodes.push_back(child);
+            ++count;
+        }
+    }
+
+    // Recurse.
+    if (recursive)
+    {
+        for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+        {
+            count += child->findNodes(id, nodes, true, exactMatch);
+        }
+    }
+
+    return count;
+}
+
+Scene* Node::getScene() const
+{
+    if (_scene)
+        return _scene;
+
+    // Search our parent for the scene
+    if (_parent)
+    {
+        Scene* scene = _parent->getScene();
+        if (scene)
+            return scene;
+    }
+
+    return NULL;
+}
+
+Node* Node::getRootNode() const
+{
+    Node* n = const_cast<Node*>(this);
+    while (n->getParent())
+    {
+        n = n->getParent();
+    }
+    return n;
+}
+
+void Node::update(float elapsedTime)
+{
+    for (Node* node = _firstChild; node != NULL; node = node->_nextSibling)
+    {
+        if (node->isActive())
+            node->update(elapsedTime);
+    }
+}
+
+bool Node::isStatic() const
+{
+    return (_collisionObject && _collisionObject->isStatic());
+}
+
+const Matrix& Node::getWorldMatrix() const
+{
+    if (_dirtyBits & NODE_DIRTY_WORLD)
+    {
+        // Clear our dirty flag immediately to prevent this block from being entered if our
+        // parent calls our getWorldMatrix() method as a result of the following calculations.
+        _dirtyBits &= ~NODE_DIRTY_WORLD;
+
+        if (!isStatic())
+        {
+            // If we have a parent, multiply our parent world transform by our local
+            // transform to obtain our final resolved world transform.
+            Node* parent = getParent();
+            if (parent && (!_collisionObject || _collisionObject->isKinematic()))
+            {
+                Matrix::multiply(parent->getWorldMatrix(), getMatrix(), &_world);
+            }
+            else
+            {
+                _world = getMatrix();
+            }
+
+            // Our world matrix was just updated, so call getWorldMatrix() on all child nodes
+            // to force their resolved world matrices to be updated.
+            for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+            {
+                child->getWorldMatrix();
+            }
+        }
+    }
+
+    return _world;
+}
+
+const Matrix& Node::getWorldViewMatrix() const
+{
+    static Matrix worldView;
+
+    Matrix::multiply(getViewMatrix(), getWorldMatrix(), &worldView);
+
+    return worldView;
+}
+
+const Matrix& Node::getInverseTransposeWorldViewMatrix() const
+{
+    static Matrix invTransWorldView;
+    Matrix::multiply(getViewMatrix(), getWorldMatrix(), &invTransWorldView);
+    invTransWorldView.invert();
+    invTransWorldView.transpose();
+    return invTransWorldView;
+}
+
+const Matrix& Node::getInverseTransposeWorldMatrix() const
+{
+    static Matrix invTransWorld;
+    invTransWorld = getWorldMatrix();
+    invTransWorld.invert();
+    invTransWorld.transpose();
+    return invTransWorld;
+}
+
+const Matrix& Node::getViewMatrix() const
+{
+    Scene* scene = getScene();
+    Camera* camera = scene ? scene->getActiveCamera() : NULL;
+    if (camera)
+    {
+        return camera->getViewMatrix();
+    }
+    else
+    {
+        return Matrix::identity();
+    }
+}
+
+const Matrix& Node::getInverseViewMatrix() const
+{
+    Scene* scene = getScene();
+    Camera* camera = scene ? scene->getActiveCamera() : NULL;
+    if (camera)
+    {
+        return camera->getInverseViewMatrix();
+    }
+    else
+    {
+        return Matrix::identity();
+    }
+}
+
+const Matrix& Node::getProjectionMatrix() const
+{
+    Scene* scene = getScene();
+    Camera* camera = scene ? scene->getActiveCamera() : NULL;
+    if (camera)
+    {
+        return camera->getProjectionMatrix();
+    }
+    else
+    {
+        return Matrix::identity();
+    }
+}
+
+const Matrix& Node::getViewProjectionMatrix() const
+{
+    Scene* scene = getScene();
+    Camera* camera = scene ? scene->getActiveCamera() : NULL;
+    if (camera)
+    {
+        return camera->getViewProjectionMatrix();
+    }
+    else
+    {
+        return Matrix::identity();
+    }
+}
+
+const Matrix& Node::getInverseViewProjectionMatrix() const
+{
+    Scene* scene = getScene();
+    Camera* camera = scene ? scene->getActiveCamera() : NULL;
+    if (camera)
+    {
+        return camera->getInverseViewProjectionMatrix();
+    }
+
+    return Matrix::identity();
+}
+
+const Matrix& Node::getWorldViewProjectionMatrix() const
+{
+    static Matrix worldViewProj;
+
+    // Always re-calculate worldViewProjection matrix since it's extremely difficult
+    // to track whether the camera has changed (it may frequently change every frame).
+    Matrix::multiply(getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
+
+    return worldViewProj;
+}
+
+Vector3 Node::getTranslationWorld() const
+{
+    Vector3 translation;
+    getWorldMatrix().getTranslation(&translation);
+    return translation;
+}
+
+Vector3 Node::getTranslationView() const
+{
+    Vector3 translation;
+    getWorldMatrix().getTranslation(&translation);
+    getViewMatrix().transformPoint(&translation);
+    return translation;
+}
+
+Vector3 Node::getForwardVectorWorld() const
+{
+    Vector3 vector;
+    getWorldMatrix().getForwardVector(&vector);
+    return vector;
+}
+
+Vector3 Node::getForwardVectorView() const
+{
+    Vector3 vector;
+    getWorldMatrix().getForwardVector(&vector);
+    getViewMatrix().transformVector(&vector);
+    return vector;
+}
+
+Vector3 Node::getRightVectorWorld() const
+{
+    Vector3 vector;
+    getWorldMatrix().getRightVector(&vector);
+    return vector;
+}
+
+Vector3 Node::getUpVectorWorld() const
+{
+    Vector3 vector;
+    getWorldMatrix().getUpVector(&vector);
+    return vector;
+}
+
+Vector3 Node::getActiveCameraTranslationWorld() const
+{
+    Scene* scene = getScene();
+    if (scene)
+    {
+        Camera* camera = scene->getActiveCamera();
+        if (camera)
+        {
+            Node* cameraNode = camera->getNode();
+            if (cameraNode)
+            {
+                return cameraNode->getTranslationWorld();
+            }
+        }
+    }
+
+    return Vector3::zero();
+}
+
+Vector3 Node::getActiveCameraTranslationView() const
+{
+    Scene* scene = getScene();
+    if (scene)
+    {
+        Camera* camera = scene->getActiveCamera();
+        if (camera)
+        {
+            Node* cameraNode = camera->getNode();
+            if (cameraNode)
+            {
+                return cameraNode->getTranslationView();
+            }
+        }
+    }
+
+    return Vector3::zero();
+}
+
+void Node::hierarchyChanged()
+{
+    // When our hierarchy changes our world transform is affected, so we must dirty it.
+    transformChanged();
+}
+
+void Node::transformChanged()
+{
+    // Our local transform was changed, so mark our world matrices dirty.
+    _dirtyBits |= NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS;
+
+    // Notify our children that their transform has also changed (since transforms are inherited).
+    for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
+    {
+        if (Transform::isTransformChangedSuspended())
+        {
+            // If the DIRTY_NOTIFY bit is not set
+            if (!n->isDirty(Transform::DIRTY_NOTIFY))
+            {
+                n->transformChanged();
+                suspendTransformChange(n);
+            }
+        }
+        else
+        {
+            n->transformChanged();
+        }
+    }
+
+    Transform::transformChanged();
+}
+
+void Node::setBoundsDirty()
+{
+    // Mark ourself and our parent nodes as dirty
+    _dirtyBits |= NODE_DIRTY_BOUNDS;
+
+    // Mark our parent bounds as dirty as well
+    if (_parent)
+        _parent->setBoundsDirty();
+}
+
+Animation* Node::getAnimation(const char* id) const
+{
+    Animation* animation = ((AnimationTarget*)this)->getAnimation(id);
+    if (animation)
+        return animation;
+    
+    // See if this node has a model, then drill down.
+    Model* model = this->getModel();
+    if (model)
+    {
+        // Check to see if there's any animations with the ID on the joints.
+        MeshSkin* skin = model->getSkin();
+        if (skin)
+        {
+            Node* rootNode = skin->_rootNode;
+            if (rootNode)
+            {
+                animation = rootNode->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+
+        // Check to see if any of the model's material parameter's has an animation
+        // with the given ID.
+        Material* material = model->getMaterial();
+        if (material)
+        {
+            // How to access material parameters? hidden on the Material::RenderState.
+            std::vector<MaterialParameter*>::iterator itr = material->_parameters.begin();
+            for (; itr != material->_parameters.end(); itr++)
+            {
+                GP_ASSERT(*itr);
+                animation = ((MaterialParameter*)(*itr))->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+    }
+
+    // look through form for animations.
+    Form* form = this->getForm();
+    if (form)
+    {
+        animation = form->getAnimation(id);
+        if (animation)
+            return animation;
+    }
+
+    // Look through this node's children for an animation with the specified ID.
+    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        animation = child->getAnimation(id);
+        if (animation)
+            return animation;
+    }
+    
+    return NULL;
+}
+
+Camera* Node::getCamera() const
+{
+    return _camera;
+}
+
+void Node::setCamera(Camera* camera)
+{
+    if (_camera != camera)
+    {
+        if (_camera)
+        {
+            _camera->setNode(NULL);
+            SAFE_RELEASE(_camera);
+        }
+
+        _camera = camera;
+
+        if (_camera)
+        {
+            _camera->addRef();
+            _camera->setNode(this);
+        }
+    }
+}
+
+Light* Node::getLight() const
+{
+    return _light;
+}
+
+void Node::setLight(Light* light)
+{
+    if (_light != light)
+    {
+        if (_light)
+        {
+            _light->setNode(NULL);
+            SAFE_RELEASE(_light);
+        }
+
+        _light = light;
+
+        if (_light)
+        {
+            _light->addRef();
+            _light->setNode(this);
+        }
+
+        setBoundsDirty();
+    }
+}
+
+Model* Node::getModel() const
+{
+    return _model;
+}
+
+void Node::setModel(Model* model)
+{
+    if (_model != model)
+    {
+        if (_model)
+        {
+            _model->setNode(NULL);
+            SAFE_RELEASE(_model);
+        }
+
+        _model = model;
+
+        if (_model)
+        {
+            _model->addRef();
+            _model->setNode(this);
+        }
+    }
+}
+
+Terrain* Node::getTerrain() const
+{
+    return _terrain;
+}
+
+void Node::setTerrain(Terrain* terrain)
+{
+    if (_terrain != terrain)
+    {
+        if (_terrain)
+        {
+            _terrain->setNode(NULL);
+            SAFE_RELEASE(_terrain);
+        }
+
+        _terrain = terrain;
+
+        if (_terrain)
+        {
+            _terrain->addRef();
+            _terrain->setNode(this);
+        }
+
+        setBoundsDirty();
+    }
+}
+
+Form* Node::getForm() const
+{
+    return _form;
+}
+
+void Node::setForm(Form* form)
+{
+    if (_form != form)
+    {
+        if (_form)
+        {
+            _form->setNode(NULL);
+            SAFE_RELEASE(_form);
+        }
+
+        _form = form;
+
+        if (_form)
+        {
+            _form->addRef();
+            _form->setNode(this);
+        }
+    }
+}
+
+const BoundingSphere& Node::getBoundingSphere() const
+{
+    if (_dirtyBits & NODE_DIRTY_BOUNDS)
+    {
+        _dirtyBits &= ~NODE_DIRTY_BOUNDS;
+
+        const Matrix& worldMatrix = getWorldMatrix();
+
+        // Start with our local bounding sphere
+        // TODO: Incorporate bounds from entities other than mesh (i.e. emitters, audiosource, etc)
+        bool empty = true;
+        if (_terrain)
+        {
+            _bounds.set(_terrain->getBoundingBox());
+            empty = false;
+        }
+        if (_model && _model->getMesh())
+        {
+            if (empty)
+            {
+                _bounds.set(_model->getMesh()->getBoundingSphere());
+                empty = false;
+            }
+            else
+            {
+                _bounds.merge(_model->getMesh()->getBoundingSphere());
+            }
+        }
+        if (_light)
+        {
+            switch (_light->getLightType())
+            {
+            case Light::POINT:
+                if (empty)
+                {
+                    _bounds.set(Vector3::zero(), _light->getRange());
+                    empty = false;
+                }
+                else
+                {
+                    _bounds.merge(BoundingSphere(Vector3::zero(), _light->getRange()));
+                }
+                break;
+            case Light::SPOT:
+                // TODO: Implement spot light bounds
+                break;
+            }
+        }
+        if (empty)
+        {
+            // Empty bounding sphere, set the world translation with zero radius
+            worldMatrix.getTranslation(&_bounds.center);
+            _bounds.radius = 0;
+        }
+
+        // Transform the sphere (if not empty) into world space.
+        if (!empty)
+        {
+            bool applyWorldTransform = true;
+            if (_model && _model->getSkin())
+            {
+                // Special case: If the root joint of our mesh skin is parented by any nodes, 
+                // multiply the world matrix of the root joint's parent by this node's
+                // world matrix. This computes a final world matrix used for transforming this
+                // node's bounding volume. This allows us to store a much smaller bounding
+                // volume approximation than would otherwise be possible for skinned meshes,
+                // since joint parent nodes that are not in the matrix palette do not need to
+                // be considered as directly transforming vertices on the GPU (they can instead
+                // be applied directly to the bounding volume transformation below).
+                GP_ASSERT(_model->getSkin()->getRootJoint());
+                Node* jointParent = _model->getSkin()->getRootJoint()->getParent();
+                if (jointParent)
+                {
+                    // TODO: Should we protect against the case where joints are nested directly
+                    // in the node hierachy of the model (this is normally not the case)?
+                    Matrix boundsMatrix;
+                    Matrix::multiply(getWorldMatrix(), jointParent->getWorldMatrix(), &boundsMatrix);
+                    _bounds.transform(boundsMatrix);
+                    applyWorldTransform = false;
+                }
+            }
+            if (applyWorldTransform)
+            {
+                _bounds.transform(getWorldMatrix());
+            }
+        }
+
+        // Merge this world-space bounding sphere with our childrens' bounding volumes.
+        for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
+        {
+            const BoundingSphere& childSphere = n->getBoundingSphere();
+            if (!childSphere.isEmpty())
+            {
+                if (empty)
+                {
+                    _bounds.set(childSphere);
+                    empty = false;
+                }
+                else
+                {
+                    _bounds.merge(childSphere);
+                }
+            }
+        }
+    }
+
+    return _bounds;
+}
+
+Node* Node::clone() const
+{
+    NodeCloneContext context;
+    return cloneRecursive(context);
+}
+
+Node* Node::cloneSingleNode(NodeCloneContext &context) const
+{
+    Node* copy = Node::create(getId());
+    context.registerClonedNode(this, copy);
+    cloneInto(copy, context);
+    return copy;
+}
+
+Node* Node::cloneRecursive(NodeCloneContext &context) const
+{
+    Node* copy = cloneSingleNode(context);
+    GP_ASSERT(copy);
+
+    // Add child nodes
+    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
+    {
+        Node* childCopy = child->cloneRecursive(context);
+        GP_ASSERT(childCopy);
+        copy->addChild(childCopy);
+        childCopy->release();
+    }
+
+    return copy;
+}
+
+void Node::cloneInto(Node* node, NodeCloneContext &context) const
+{
+    GP_ASSERT(node);
+    Transform::cloneInto(node, context);
+
+    // TODO: Clone the rest of the node data.
+
+    if (Camera* camera = getCamera())
+    {
+        Camera* cameraClone = camera->clone(context);
+        node->setCamera(cameraClone);
+        cameraClone->release();
+    }
+    if (Light* light = getLight())
+    {
+        Light* lightClone = light->clone(context);
+        node->setLight(lightClone);
+        lightClone->release();
+    }
+    if (AudioSource* audio = getAudioSource())
+    {
+        AudioSource* audioClone = audio->clone(context);
+        node->setAudioSource(audioClone);
+        audioClone->release();
+    }
+    if (Model* model = getModel())
+    {
+        Model* modelClone = model->clone(context);
+        node->setModel(modelClone);
+        modelClone->release();
+    }
+    if (ParticleEmitter* emitter = getParticleEmitter())
+    {
+        ParticleEmitter* emitterClone = emitter->clone();
+        node->setParticleEmitter(emitterClone);
+        emitterClone->release();
+    }
+    node->_world = _world;
+    node->_bounds = _bounds;
+
+    // Note: Do not clone _userData - we can't make any assumptions about its content and how it's managed,
+    // so it's the caller's responsibility to clone user data if needed.
+
+    if (_tags)
+    {
+        node->_tags = new std::map<std::string, std::string>(_tags->begin(), _tags->end());
+    }
+}
+
+AudioSource* Node::getAudioSource() const
+{
+    return _audioSource;
+}
+
+void Node::setAudioSource(AudioSource* audio)
+{
+    if (_audioSource != audio)
+    {
+        if (_audioSource)
+        {
+            _audioSource->setNode(NULL);
+            SAFE_RELEASE(_audioSource);
+        }
+        
+        _audioSource = audio;
+
+        if (_audioSource)
+        {
+            _audioSource->addRef();
+            _audioSource->setNode(this);
+        }
+    }
+}
+
+ParticleEmitter* Node::getParticleEmitter() const
+{
+    return _particleEmitter;
+}
+
+void Node::setParticleEmitter(ParticleEmitter* emitter)
+{
+    if (_particleEmitter != emitter)
+    {
+        if (_particleEmitter)
+        {
+            _particleEmitter->setNode(NULL);
+            SAFE_RELEASE(_particleEmitter);
+        }
+        
+        _particleEmitter = emitter;
+
+        if (_particleEmitter)
+        {
+            _particleEmitter->addRef();
+            _particleEmitter->setNode(this);
+        }
+    }
+}
+
+PhysicsCollisionObject* Node::getCollisionObject() const
+{
+    return _collisionObject;
+}
+
+PhysicsCollisionObject* Node::setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape, PhysicsRigidBody::Parameters* rigidBodyParameters, int group, int mask)
+{
+    SAFE_DELETE(_collisionObject);
+
+    switch (type)
+    {
+    case PhysicsCollisionObject::RIGID_BODY:
+        {
+            _collisionObject = new PhysicsRigidBody(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters(), group, mask);
+        }
+        break;
+
+    case PhysicsCollisionObject::GHOST_OBJECT:
+        {
+            _collisionObject = new PhysicsGhostObject(this, shape, group, mask);
+        }
+        break;
+
+    case PhysicsCollisionObject::CHARACTER:
+        {
+            _collisionObject = new PhysicsCharacter(this, shape, rigidBodyParameters ? rigidBodyParameters->mass : 1.0f);
+        }
+        break;
+
+    case PhysicsCollisionObject::VEHICLE:
+        {
+            _collisionObject = new PhysicsVehicle(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
+        }
+        break;
+
+    case PhysicsCollisionObject::VEHICLE_WHEEL:
+        {
+            //
+            // PhysicsVehicleWheel is special because this call will traverse up the scene graph for the
+            // first ancestor node that is shared with another node of collision type VEHICLE, and then
+            // proceed to add itself as a wheel onto that vehicle. This is by design, and allows the
+            // visual scene hierarchy to be the sole representation of the relationship between physics
+            // objects rather than forcing that upon the otherwise-flat ".physics" (properties) file.
+            //
+            // IMPORTANT: The VEHICLE must come before the VEHICLE_WHEEL in the ".scene" (properties) file!
+            //
+            _collisionObject = new PhysicsVehicleWheel(this, shape, rigidBodyParameters ? *rigidBodyParameters : PhysicsRigidBody::Parameters());
+        }
+        break;
+
+    case PhysicsCollisionObject::NONE:
+        break;  // Already deleted, Just don't add a new collision object back.
+    }
+
+    return _collisionObject;
+}
+
+PhysicsCollisionObject* Node::setCollisionObject(const char* url)
+{
+    // Load the collision object properties from file.
+    Properties* properties = Properties::create(url);
+    if (properties == NULL)
+    {
+        GP_ERROR("Failed to load collision object file: %s", url);
+        return NULL;
+    }
+
+    PhysicsCollisionObject* collisionObject = setCollisionObject((strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace());
+    SAFE_DELETE(properties);
+
+    return collisionObject;
+}
+
+PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
+{
+    SAFE_DELETE(_collisionObject);
+
+    // Check if the properties is valid.
+    if (!properties || !(strcmp(properties->getNamespace(), "collisionObject") == 0))
+    {
+        GP_ERROR("Failed to load collision object from properties object: must be non-null object and have namespace equal to 'collisionObject'.");
+        return NULL;
+    }
+
+    if (const char* type = properties->getString("type"))
+    {
+        if (strcmp(type, "CHARACTER") == 0)
+        {
+            _collisionObject = PhysicsCharacter::create(this, properties);
+        }
+        else if (strcmp(type, "GHOST_OBJECT") == 0)
+        {
+            _collisionObject = PhysicsGhostObject::create(this, properties);
+        }
+        else if (strcmp(type, "RIGID_BODY") == 0)
+        {
+            _collisionObject = PhysicsRigidBody::create(this, properties);
+        }
+        else if (strcmp(type, "VEHICLE") == 0)
+        {
+            _collisionObject = PhysicsVehicle::create(this, properties);
+        }
+        else if (strcmp(type, "VEHICLE_WHEEL") == 0)
+        {
+            //
+            // PhysicsVehicleWheel is special because this call will traverse up the scene graph for the
+            // first ancestor node that is shared with another node of collision type VEHICLE, and then
+            // proceed to add itself as a wheel onto that vehicle. This is by design, and allows the
+            // visual scene hierarchy to be the sole representation of the relationship between physics
+            // objects rather than forcing that upon the otherwise-flat ".physics" (properties) file.
+            //
+            // IMPORTANT: The VEHICLE must come before the VEHICLE_WHEEL in the ".scene" (properties) file!
+            //
+            _collisionObject = PhysicsVehicleWheel::create(this, properties);
+        }
+        else
+        {
+            GP_ERROR("Unsupported collision object type '%s'.", type);
+            return NULL;
+        }
+    }
+    else
+    {
+        GP_ERROR("Failed to load collision object from properties object; required attribute 'type' is missing.");
+        return NULL;
+    }
+
+    return _collisionObject;
+}
+
+AIAgent* Node::getAgent() const
+{
+    return _agent;
+}
+
+void Node::setAgent(AIAgent* agent)
+{
+    if (agent != _agent)
+    {
+        if (_agent)
+        {
+            Game::getInstance()->getAIController()->removeAgent(_agent);
+            _agent->_node = NULL;
+            SAFE_RELEASE(_agent);
+        }
+
+        _agent = agent;
+
+        if (_agent)
+        {
+            _agent->addRef();
+            _agent->_node = this;
+            Game::getInstance()->getAIController()->addAgent(_agent);
+        }
+    }
+}
+
+NodeCloneContext::NodeCloneContext()
+{
+}
+
+NodeCloneContext::~NodeCloneContext()
+{
+}
+
+Animation* NodeCloneContext::findClonedAnimation(const Animation* animation)
+{
+    GP_ASSERT(animation);
+
+    std::map<const Animation*, Animation*>::iterator it = _clonedAnimations.find(animation);
+    return it != _clonedAnimations.end() ? it->second : NULL;
+}
+
+void NodeCloneContext::registerClonedAnimation(const Animation* original, Animation* clone)
+{
+    GP_ASSERT(original);
+    GP_ASSERT(clone);
+
+    _clonedAnimations[original] = clone;
+}
+
+Node* NodeCloneContext::findClonedNode(const Node* node)
+{
+    GP_ASSERT(node);
+
+    std::map<const Node*, Node*>::iterator it = _clonedNodes.find(node);
+    return it != _clonedNodes.end() ? it->second : NULL;
+}
+
+void NodeCloneContext::registerClonedNode(const Node* original, Node* clone)
+{
+    GP_ASSERT(original);
+    GP_ASSERT(clone);
+
+    _clonedNodes[original] = clone;
+}
+
+}

+ 62 - 58
gameplay/src/Node.h

@@ -122,7 +122,7 @@ public:
      * Custom tags can be used for a variety of purposes within a game. For example,
      * a tag called "transparent" can be added to nodes, to indicate which nodes in
      * a scene are transparent. This tag can then be read during rendering to sort
-     * transparent and opaque objects for correct drawing order. 
+     * transparent and opaque objects for correct drawing order.
      *
      * Setting a tag to NULL removes the tag from the Node.
      *
@@ -162,13 +162,13 @@ public:
      * Sets the user pointer for this node.
      *
      * The user pointer is initially NULL and can be set to anything.
-     * This is normally used to store game-specific data, such as 
+     * This is normally used to store game-specific data, such as
      * game state for a particular node.  For example, attributes
      * for a game character, such as hit points, stamina, etc can
      * be defined in a game structure and stored in this field.
      *
      * When a node is deleted, the (optional) cleanup callback
-     * function passed to this function is called to allow the 
+     * function passed to this function is called to allow the
      * user to free any memory associated with the user pointer.
      *
      * @param pointer User pointer.
@@ -181,26 +181,25 @@ public:
     void setUserPointer(void* pointer, void (*cleanupCallback)(void*) = NULL);
 
     /**
-     * Sets if visual components themselves set as visible.
+     * Sets if the node is active in the scene.
      *
-     * @param visible if visual components themselves set as visible.
+     * @param active if the node is active in the scene.
      */
-    void setVisible(bool visible);
+    void setActive(bool active);
 
     /**
-     * Gets if visual components themselves set as visible.
+     * Gets if the node is active in the scene.
      *
-     * @return if visual components themselves set as visible.
+     * @return if the node is active in the scene.
      */
-    bool isVisible() const;
+    bool isActive() const;
 
     /**
-     * Gets if visual components are either inherited visible or they are themselves.
+     * Gets if the node  either inherited active.
      *
-     * @param inherit true if visible is based on inherited behaviour or false is its self is visible.
      * @return if visual components attached on this node should be drawn.
      */
-    bool isVisibleInHierarchy() const;
+    bool isActiveInHierarchy() const;
 
     /**
      * Returns the number of direct children of this item.
@@ -212,7 +211,7 @@ public:
     /**
      * Returns the first child node that matches the given ID.
      *
-     * This method checks the specified ID against its immediate child nodes 
+     * This method checks the specified ID against its immediate child nodes
      * but does not check the ID against itself.
      * If recursive is true, it also traverses the Node's hierarchy with a breadth first search.
      *
@@ -220,7 +219,7 @@ public:
      * @param recursive True to search recursively all the node's children, false for only direct children.
      * @param exactMatch true if only nodes whose ID exactly matches the specified ID are returned,
      *        or false if nodes that start with the given ID are returned.
-     * 
+     *
      * @return The Node found or NULL if not found.
      */
     Node* findNode(const char* id, bool recursive = true, bool exactMatch = true) const;
@@ -233,7 +232,7 @@ public:
      * @param recursive true if a recursive search should be performed, false otherwise.
      * @param exactMatch true if only nodes whose ID exactly matches the specified ID are returned,
      *        or false if nodes that start with the given ID are returned.
-     * 
+     *
      * @return The number of matches found.
      * @script{ignore}
      */
@@ -251,6 +250,11 @@ public:
      */
     Node* getRootNode() const;
 
+    /**
+     * Updates this node and any active children.
+     */
+    void update(float elapsedTime);
+
     /**
      * Returns whether the transformation of this node is static.
      *
@@ -415,7 +419,7 @@ public:
 
     /**
      * Assigns a camera to this node.
-     * 
+     *
      * This will increase the reference count of the new camera and decrease
      * the reference count of the old camera.
      *
@@ -432,7 +436,7 @@ public:
 
     /**
      * Assigns a light to this node.
-     * 
+     *
      * This will increase the reference count of the new light and decrease
      * the reference count of the old light.
      *
@@ -442,14 +446,14 @@ public:
 
     /**
      * Returns the pointer to this node's model.
-     * 
+     *
      * @return The pointer to this node's model or NULL.
      */
     Model* getModel() const;
 
     /**
      * Assigns a model to this node.
-     * 
+     *
      * This will increase the reference count of the new model and decrease
      * the reference count of the old model.
      *
@@ -476,14 +480,14 @@ public:
 
     /**
      * Returns the pointer to this node's form.
-     * 
+     *
      * @return The pointer to this node's form or NULL.
      */
     Form* getForm() const;
 
     /**
      * Assigns a form to this node.
-     * 
+     *
      * @param form The form pointer. May be NULL.
      */
     void setForm(Form* form);
@@ -497,7 +501,7 @@ public:
 
     /**
      * Assigns an audio source to this node.
-     * 
+     *
      * This will increase the reference count of the new audio source and decrease
      * the reference count of the old audio source.
      *
@@ -514,7 +518,7 @@ public:
 
     /**
      * Assigns a particle emitter to this node.
-     * 
+     *
      * This will increase the reference count of the new particle emitter and decrease
      * the reference count of the old particle emitter.
      *
@@ -535,7 +539,7 @@ public:
     /**
      * Sets (or disables) the physics collision object for this node.
      *
-     * The supported collision object types include rigid bodies, ghost objects, 
+     * The supported collision object types include rigid bodies, ghost objects,
      * characters, vehicles, and vehicle wheels.
      *
      * Rigid bodies are used to represent most physical objects in a game. The important
@@ -551,7 +555,7 @@ public:
      * Ghost objects are a simple type of collision object that are not simulated. By default
      * they pass through other objects in the scene without affecting them. Ghost objects do
      * receive collision events however, which makes them useful for representing non-simulated
-     * entities in a game that still require collision events, such as volumetric triggers, 
+     * entities in a game that still require collision events, such as volumetric triggers,
      * power-ups, etc.
      *
      * Characters are an extension of ghost objects which provide a number of additional features
@@ -575,21 +579,21 @@ public:
      * @param group Group identifier of the object for collision filtering.
      * @param mask Bitmask to filter groups of objects to collide with this one.
      */
-    PhysicsCollisionObject* setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape = PhysicsCollisionShape::box(), 
+    PhysicsCollisionObject* setCollisionObject(PhysicsCollisionObject::Type type, const PhysicsCollisionShape::Definition& shape = PhysicsCollisionShape::box(),
                                                PhysicsRigidBody::Parameters* rigidBodyParameters = NULL, int group = PHYSICS_COLLISION_GROUP_DEFAULT, int mask = PHYSICS_COLLISION_MASK_DEFAULT);
 
     /**
-     * Sets the physics collision object for this node using the data from the Properties object defined at the specified URL, 
+     * Sets the physics collision object for this node using the data from the Properties object defined at the specified URL,
      * where the URL is of the format "<file-path>.<extension>#<namespace-id>/<namespace-id>/.../<namespace-id>"
-     * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional). 
-     * 
+     * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional).
+     *
      * @param url The URL pointing to the Properties object defining the physics collision object.
      */
     PhysicsCollisionObject* setCollisionObject(const char* url);
 
     /**
      * Sets the physics collision object for this node from the given properties object.
-     * 
+     *
      * @param properties The properties object defining the collision object.
      */
     PhysicsCollisionObject* setCollisionObject(Properties* properties);
@@ -612,7 +616,7 @@ public:
      * Returns the bounding sphere for the Node, in world space.
      *
      * The bounding sphere for a node represents the area, in world
-     * space, that the node contains. This includes the space occupied 
+     * space, that the node contains. This includes the space occupied
      * by any child nodes as well as the space occupied by any data
      * inside the node (such as models).
      *
@@ -631,7 +635,7 @@ public:
 
     /**
      * Clones the node and all of its child nodes.
-     * 
+     *
      * @return A new node.
      * @script{create}
      */
@@ -651,25 +655,25 @@ protected:
 
     /**
      * Clones a single node and its data but not its children.
-     * 
+     *
      * @param context The clone context.
-     * 
+     *
      * @return Pointer to the newly created node.
      */
     virtual Node* cloneSingleNode(NodeCloneContext &context) const;
 
     /**
      * Recursively clones this node and its children.
-     * 
+     *
      * @param context The clone context.
-     * 
+     *
      * @return The newly created node.
      */
     Node* cloneRecursive(NodeCloneContext &context) const;
 
     /**
      * Copies the data from this node into the given node.
-     * 
+     *
      * @param node The node to copy the data to.
      * @param context The clone context.
      */
@@ -724,7 +728,7 @@ protected:
          */
         void* pointer;
 
-        /** 
+        /**
          * Cleanup callback.
          */
         void (*cleanupCallback)(void*);
@@ -737,19 +741,19 @@ protected:
 
     /**
      * The Node's ID.
-     */ 
+     */
     std::string _id;
 
     /**
      * Pointer to the Node's first child.
      */
     Node* _firstChild;
-    
+
     /**
      * Pointer to the Node's next child.
      */
     Node* _nextSibling;
-    
+
     /**
      * Pointer to the Node's previous sibling.
      */
@@ -766,9 +770,9 @@ protected:
     unsigned int _childCount;
 
     /**
-     * If this node is visible. This may not be visiblein hierarchy if its parents are hidden
+     * If this node is active in the scrne. This may not be active in hierarchy if its parents are not active.
      */
-    bool _visible;
+    bool _active;
 
     /**
      * List of custom tags for a node.
@@ -782,7 +786,7 @@ protected:
 
     /**
      * Pointer to the Light attached to the Node.
-     */ 
+     */
     Light* _light;
 
     /**
@@ -799,22 +803,22 @@ protected:
      * Pointer to the Form attached to the Node.
      */
     Form* _form;
-    
+
     /**
      * Pointer to the AudioSource attached to the Node.
      */
     AudioSource* _audioSource;
-    
+
     /**
      * Pointer to the ParticleEmitter attached to the Node.
      */
     ParticleEmitter* _particleEmitter;
-    
+
     /**
      * Pointer to the PhysicsCollisionObject attached to the Node.
      */
     PhysicsCollisionObject* _collisionObject;
-    
+
     /**
      * Pointer to the AI agent attached to the Node.
      */
@@ -829,10 +833,10 @@ protected:
      * Dirty bits flag for the Node.
      */
     mutable int _dirtyBits;
-    
+
     /**
      * A flag indicating if the Node's hierarchy has changed.
-     */ 
+     */
     bool _notifyHierarchyChanged;
 
     /**
@@ -848,7 +852,7 @@ protected:
 
 /**
  * NodeCloneContext represents the context data that is kept when cloning a node.
- * 
+ *
  * The NodeCloneContext is used to make sure objects don't get cloned twice.
  */
 class NodeCloneContext
@@ -867,16 +871,16 @@ public:
 
     /**
      * Finds the cloned animation of the given animation or NULL if this animation was not registered with this context.
-     * 
+     *
      * @param animation The animation to search for the cloned copy of.
-     * 
+     *
      * @return The cloned animation or NULL if not found.
      */
     Animation* findClonedAnimation(const Animation* animation);
 
     /**
      * Registers the cloned animation with this context so that it doesn't get cloned twice.
-     * 
+     *
      * @param original The pointer to the original animation.
      * @param clone The pointer to the cloned animation.
      */
@@ -884,23 +888,23 @@ public:
 
     /**
      * Finds the cloned node of the given node or NULL if this node was not registered with this context.
-     * 
+     *
      * @param node The node to search for the cloned copy of.
-     * 
+     *
      * @return The cloned node or NULL if not found.
      */
     Node* findClonedNode(const Node* node);
 
     /**
      * Registers the cloned node with this context so that it doens't get cloned twice.
-     * 
+     *
      * @param original The pointer to the original node.
      * @param clone The pointer to the cloned node.
      */
     void registerClonedNode(const Node* original, Node* clone);
 
 private:
-    
+
     /**
      * Hidden copy constructor.
      */

+ 6 - 16
gameplay/src/PhysicsVehicleWheel.cpp

@@ -7,29 +7,20 @@ namespace gameplay
 {
 
 PhysicsVehicleWheel::PhysicsVehicleWheel(Node* node, const PhysicsCollisionShape::Definition& shape, const PhysicsRigidBody::Parameters& parameters)
-    : PhysicsCollisionObject(node), _rigidBody(NULL), _host(NULL), _indexInHost(0)
+    : PhysicsCollisionObject(node), _host(NULL), _indexInHost(0)
 {
-    // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
-    // that is where the rigid body gets added to the dynamics world.
-    _rigidBody = new PhysicsRigidBody(node, shape, parameters);
-
     findAncestorAndBind();
 }
 
-PhysicsVehicleWheel::PhysicsVehicleWheel(Node* node, PhysicsRigidBody* rigidBody)
-    : PhysicsCollisionObject(node), _rigidBody(NULL), _host(NULL), _indexInHost(0)
+PhysicsVehicleWheel::PhysicsVehicleWheel(Node* node)
+    : PhysicsCollisionObject(node), _host(NULL), _indexInHost(0)
 {
-    _rigidBody = rigidBody;
-
     findAncestorAndBind();
 }
 
 PhysicsVehicleWheel* PhysicsVehicleWheel::create(Node* node, Properties* properties)
 {
-    // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
-    // that is where the rigid body gets added to the dynamics world.
-    PhysicsRigidBody* rigidBody = PhysicsRigidBody::create(node, properties, "VEHICLE_WHEEL");
-    PhysicsVehicleWheel* wheel = new PhysicsVehicleWheel(node, rigidBody);
+    PhysicsVehicleWheel* wheel = new PhysicsVehicleWheel(node);
 
     // Load the defined wheel parameters.
     properties->rewind();
@@ -100,14 +91,13 @@ PhysicsVehicleWheel* PhysicsVehicleWheel::create(Node* node, Properties* propert
 
 PhysicsVehicleWheel::~PhysicsVehicleWheel()
 {
-    SAFE_DELETE(_rigidBody);
 }
 
 btCollisionObject* PhysicsVehicleWheel::getCollisionObject() const
 {
-    GP_ASSERT(_rigidBody);
+    GP_ASSERT(_host);
 
-    return _rigidBody->getCollisionObject();
+    return _host->getCollisionObject();
 }
 
 PhysicsCollisionObject::Type PhysicsVehicleWheel::getType() const

+ 3 - 6
gameplay/src/PhysicsVehicleWheel.h

@@ -285,16 +285,14 @@ private:
     PhysicsVehicleWheel(Node* node, const PhysicsCollisionShape::Definition& shape, const PhysicsRigidBody::Parameters& parameters);
 
     /**
-     * Creates a vehicle wheel based on the given rigid body and some 'safe' defaults.
+     * Creates a vehicle wheel based on some 'safe' defaults.
      * Also, traverse up the scene graph until we find the first common ancestor with another node
      * of collision type VEHICLE and add ourself as a wheel onto that vehicle. This assumes that the
      * VEHICLE comes before the VEHICLE_WHEEL in the ".scene" (properties) file.
      * 
-     * @param node The node to create a rigid body for; note that the node must have
-     *      a model attached to it prior to creating a rigid body for it.
-     * @param rigidBody The rigid body.
+     * @param node The node to create a vehicle wheel for.
      */
-    PhysicsVehicleWheel(Node* node, PhysicsRigidBody* rigidBody);
+    PhysicsVehicleWheel(Node* node);
 
     /**
      * Private copy constructor to prevent copying.
@@ -380,7 +378,6 @@ private:
      */
     void getWheelPos(Vector3* result) const;
 
-    PhysicsRigidBody* _rigidBody;
     PhysicsVehicle* _host;
     unsigned int _indexInHost;
     Vector3 _initialOffset;

+ 4 - 12
gameplay/src/Platform.cpp

@@ -101,19 +101,11 @@ void Platform::resizeEventInternal(unsigned int width, unsigned int height)
 
 void Platform::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
 {
-	switch(evt)
-	{
-	case Gamepad::CONNECTED_EVENT:
-	case Gamepad::DISCONNECTED_EVENT:
-		Game::getInstance()->gamepadEvent(evt, gamepad);
+    if (!Form::gamepadEventInternal(evt, gamepad, analogIndex))
+    {
+        Game::getInstance()->gamepadEvent(evt, gamepad);
         Game::getInstance()->getScriptController()->gamepadEvent(evt, gamepad);
-		break;
-	case Gamepad::BUTTON_EVENT:
-	case Gamepad::JOYSTICK_EVENT:
-	case Gamepad::TRIGGER_EVENT:
-		Form::gamepadEventInternal(evt, gamepad, analogIndex);
-		break;
-	}
+    }
 }
 
 void Platform::gamepadEventConnectedInternal(GamepadHandle handle,  unsigned int buttonCount, unsigned int joystickCount, unsigned int triggerCount,

+ 17 - 17
gameplay/src/Platform.h

@@ -15,8 +15,8 @@ class Game;
 
 /**
  * Defines a platform abstraction.
- * 
- * This class has only a few public methods for creating a platform 
+ *
+ * This class has only a few public methods for creating a platform
  *
  */
 class Platform
@@ -36,7 +36,7 @@ public:
      * Creates a platform for the specified game which it will interact with.
      *
      * @param game The game to create a platform for.
-     * 
+     *
      * @return The created platform interface.
      * @script{ignore}
      */
@@ -47,7 +47,7 @@ public:
      *
      * This method handles all OS window messages and drives the game loop.
      * It normally does not return until the application is closed.
-     * 
+     *
      * If a attachToWindow is passed to Platform::create the message pump will instead attach
      * to or allow the attachToWindow to drive the game loop on the platform.
      *
@@ -61,9 +61,9 @@ public:
     static void swapBuffers();
 
 private:
-    
+
     /**
-     * This method informs the platform that the game is shutting down 
+     * This method informs the platform that the game is shutting down
      * and anything platform specific should be shutdown as well or halted
      * This function is called automatically when the game shutdown function is called
      */
@@ -76,17 +76,17 @@ private:
      * @return whether a programmatic exit is allowed on this platform.
      */
     static bool canExit();
-    
+
     /**
      * Gets the display width.
-     * 
+     *
      * @return The display width.
      */
     static unsigned int getDisplayWidth();
-    
+
     /**
      * Gets the display height.
-     * 
+     *
      * @return The display height.
      */
     static unsigned int getDisplayHeight();
@@ -107,7 +107,7 @@ private:
 
     /**
      * Gets whether vertical sync is enabled for the game display.
-     * 
+     *
      * @return true if vsync is enabled; false if not.
      */
     static bool isVsync();
@@ -155,7 +155,7 @@ private:
      * Whether the platform has mouse support.
      */
     static bool hasMouse();
-    
+
     /**
      * Enables or disabled mouse capture.
      *
@@ -210,7 +210,7 @@ private:
      * accelerometer data with data from other sensors as well, such as the gyros.
      * This method is best used to obtain an indication of device orientation; it
      * does not necessarily distinguish between acceleration and rotation rate.
-     * 
+     *
      * @param pitch The accelerometer pitch. Zero if hasAccelerometer() returns false.
      * @param roll The accelerometer roll. Zero if hasAccelerometer() returns false.
      */
@@ -232,12 +232,12 @@ private:
 
     /**
      * Gets the command line arguments.
-     * 
+     *
      * @param argc The number of command line arguments.
      * @param argv The array of command line arguments.
      */
     static void getArguments(int* argc, char*** argv);
-    
+
     /**
      * Shows or hides the virtual keyboard (if supported).
      *
@@ -377,7 +377,7 @@ public:
      * @script{ignore}
      */
     static void gamepadEventConnectedInternal(GamepadHandle handle, unsigned int buttonCount, unsigned int joystickCount, unsigned int triggerCount,
-                                              unsigned int vendorId, unsigned int productId, 
+                                              unsigned int vendorId, unsigned int productId,
                                               const char* vendorString, const char* productString);
 
     /**
@@ -388,7 +388,7 @@ public:
     static void gamepadEventDisconnectedInternal(GamepadHandle handle);
 
     /**
-     * Internal metehod used by Gamepad that polls the platform for the updated Gamepad
+     * Internal method used by Gamepad that polls the platform for the updated Gamepad
      * states such as joysticks, buttons and trigger values.
      *
      * @param gamepad The gamepad to be returned with the latest polled values populated.

+ 5 - 3
gameplay/src/PlatformBlackBerry.cpp

@@ -601,7 +601,7 @@ void Platform::pollGamepadState(Gamepad* gamepad)
             screen_get_device_property_iv(gamepad->_handle, SCREEN_PROPERTY_ANALOG1, analog);
             break;
         }
-        
+
         // So far we've tested two gamepads with analog sticks on BlackBerry:
         // the SteelSeries FREE, and the iControlPad.
         // Both return values between -128 and +127, with the y axis starting from
@@ -1009,7 +1009,7 @@ Platform* Platform::create(Game* game)
     screenDevs = (screen_device_t*)calloc(count, sizeof(screen_device_t));
     screen_get_context_property_pv(__screenContext, SCREEN_PROPERTY_DEVICES, (void**)screenDevs);
 
-	for (int i = 0; i < count; i++) 
+	for (int i = 0; i < count; i++)
     {
 	    int type;
         screen_get_device_property_iv(screenDevs[i], SCREEN_PROPERTY_TYPE, &type);
@@ -1086,7 +1086,7 @@ int Platform::enterMessagePump()
     while (true)
     {
         bps_event_t* event = NULL;
-        
+
         while (true)
         {
             rc = bps_get_event(&event, 1);
@@ -1095,9 +1095,11 @@ int Platform::enterMessagePump()
             if (event == NULL)
                 break;
 
+#ifdef GP_USE_SOCIAL
             // if the social controller needs to deal with the event do that here
             if (Game::getInstance()->getSocialController()->handleEvent(event))
             	break;
+#endif
 
             domain = bps_event_get_domain(event);
 

+ 51 - 14
gameplay/src/PlatformMacOSX.mm

@@ -13,6 +13,7 @@
 #import <OpenGL/OpenGL.h>
 #import <mach/mach_time.h>
 #import <Foundation/Foundation.h>
+#import <GameKit/GameKit.h>
 
 // These should probably be moved to a platform common file
 #define SONY_USB_VENDOR_ID              0x054c
@@ -999,11 +1000,9 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 }
 
-- (void)mouseMoved:(NSEvent*) event 
+// helper function to handle mouse capture
+bool getMousePointForEvent(NSPoint& point, NSEvent* event)
 {
-    NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    
-    float y;
     if (__mouseCaptured)
     {
         if (__mouseCapturedFirstPass)
@@ -1011,36 +1010,61 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
             // Discard the first mouseMoved event following transition into capture
             // since it contains bogus x,y data.
             __mouseCapturedFirstPass = false;
-            return;
+            return false;
         }
-
+        
         point.x = [event deltaX];
         point.y = [event deltaY];
-
+        
         NSWindow* window = __view.window;
         NSRect rect = window.frame;
         CGPoint centerPoint;
         centerPoint.x = rect.origin.x + (rect.size.width / 2);
         centerPoint.y = rect.origin.y + (rect.size.height / 2);
         CGDisplayMoveCursorToPoint(CGDisplayPrimaryDisplay(NULL), centerPoint);
-        y = point.y;
     }
     else
     {
-        y = __height - point.y;
+        point.y = __height - point.y;
     }
+
+    return true;
+}
+
+- (void)mouseMoved:(NSEvent*) event
+{
+    NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     
+    if (!getMousePointForEvent(point, event))
+    {
+        return;
+    }
+
     [__view->gameLock lock];
-    gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, y, 0);
+    gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, point.y, 0);
     [__view->gameLock unlock];
 }
 
 - (void) mouseDragged: (NSEvent*) event
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    if (__leftMouseDown && !__mouseCaptured)
+    if (__leftMouseDown)
     {
-        [self mouse: Mouse::MOUSE_MOVE orTouchEvent: Touch::TOUCH_MOVE x: point.x y: __height - point.y s: 0];
+        if (__mouseCaptured)
+        {
+            if (!getMousePointForEvent(point, event))
+            {
+                return;
+            }
+            
+            [__view->gameLock lock];
+            gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, point.y, 0);
+            [__view->gameLock unlock];
+        }
+        else
+        {
+            [self mouse: Mouse::MOUSE_MOVE orTouchEvent: Touch::TOUCH_MOVE x: point.x y: __height - point.y s: 0];
+        }
     }
 }
 
@@ -1068,10 +1092,15 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     
+    if (!getMousePointForEvent(point, event))
+    {
+        return;
+    }
+    
     // In right-mouse case, whether __rightMouseDown is true or false
     // this should not matter, mouse move is still occuring
     [__view->gameLock lock];
-    gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, __height - point.y, 0);
+    gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, point.y, 0);
     [__view->gameLock unlock];
 }
 
@@ -1553,8 +1582,10 @@ int getUnicode(int key)
 @end
 
 @interface FullscreenWindow : NSWindow
-{ 
+{
 }
+
+- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController;
 @end
 
 @implementation FullscreenWindow
@@ -1562,6 +1593,12 @@ int getUnicode(int key)
 {
     return YES;
 }
+
+- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
+{
+    GKDialogController *sdc = [GKDialogController sharedDialogController];
+    [sdc dismiss: self];
+}
 @end
 
 

+ 4 - 9
gameplay/src/PlatformWindows.cpp

@@ -90,6 +90,7 @@ static gameplay::Keyboard::Key getKey(WPARAM win32KeyCode, bool shiftDown)
     case VK_ESCAPE:
         return gameplay::Keyboard::KEY_ESCAPE;
     case VK_BACK:
+    case VK_F16: // generated by CTRL + BACKSPACE
         return gameplay::Keyboard::KEY_BACKSPACE;
     case VK_TAB:
         return shiftDown ? gameplay::Keyboard::KEY_BACK_TAB : gameplay::Keyboard::KEY_TAB;
@@ -444,9 +445,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         if (wParam == VK_CAPITAL)
             capsOn = !capsOn;
 
-        // Suppress key repeats.
-        if ((lParam & 0x40000000) == 0)
-            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
+        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
         break;
         
     case WM_KEYUP:
@@ -457,15 +456,11 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         break;
 
     case WM_CHAR:
-        // Suppress key repeats.
-        if ((lParam & 0x40000000) == 0)
-            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
+        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
         break;
 
     case WM_UNICHAR:
-        // Suppress key repeats.
-        if ((lParam & 0x40000000) == 0)
-            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
+        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
         break;
 
     case WM_SETFOCUS:

+ 6 - 0
gameplay/src/PlatformiOS.mm

@@ -8,6 +8,7 @@
 #include "ScriptController.h"
 #include <unistd.h>
 #import <UIKit/UIKit.h>
+#import <GameKit/GameKit.h>
 #import <QuartzCore/QuartzCore.h>
 #import <CoreMotion/CoreMotion.h>
 #import <OpenGLES/EAGL.h>
@@ -749,6 +750,7 @@ int getUnicode(int key);
 @interface ViewController : UIViewController
 - (void)startUpdating;
 - (void)stopUpdating;
+- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController;
 @end
 
 
@@ -821,6 +823,10 @@ int getUnicode(int key);
     [(View*)self.view stopUpdating];
 }
 
+- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
+{
+    [self dismissViewControllerAnimated:YES completion:nil];
+}
 @end
 
 

+ 4 - 3
gameplay/src/Properties.cpp

@@ -84,7 +84,7 @@ Properties* Properties::create(const char* url)
     std::auto_ptr<Stream> stream(FileSystem::open(fileString.c_str()));
     if (stream.get() == NULL)
     {
-        GP_ERROR("Failed to open file '%s'.", fileString.c_str());
+        GP_WARN("Failed to open file '%s'.", fileString.c_str());
         return NULL;
     }
 
@@ -96,7 +96,8 @@ Properties* Properties::create(const char* url)
     Properties* p = getPropertiesFromNamespacePath(properties, namespacePath);
     if (!p)
     {
-        GP_ERROR("Failed to load properties from url '%s'.", url);
+        GP_WARN("Failed to load properties from url '%s'.", url);
+        SAFE_DELETE(properties);
         return NULL;
     }
 
@@ -1102,7 +1103,7 @@ Properties* getPropertiesFromNamespacePath(Properties* properties, const std::ve
             {
                 if (iter == NULL)
                 {
-                    GP_ERROR("Failed to load properties object from url.");
+                    GP_WARN("Failed to load properties object from url.");
                     return NULL;
                 }
 

+ 2 - 0
gameplay/src/Properties.h

@@ -151,6 +151,8 @@ public:
      * (and "#<namespace-id>/<namespace-id>/.../<namespace-id>" is optional).
      * 
      * @param url The URL to create the properties from.
+     * 
+     * @return The created Properties or NULL if there was an error.
      * @script{create}
      */
     static Properties* create(const char* url);

+ 235 - 266
gameplay/src/RadioButton.cpp

@@ -1,266 +1,235 @@
-#include "Base.h"
-#include "RadioButton.h"
-
-namespace gameplay
-{
-static std::vector<RadioButton*> __radioButtons;
-
-RadioButton::RadioButton() : _selected(false), _image(NULL)
-{
-}
-
-RadioButton::~RadioButton()
-{
-    // Remove this RadioButton from the global list.
-    std::vector<RadioButton*>::iterator it = std::find(__radioButtons.begin(), __radioButtons.end(), this);
-    if (it != __radioButtons.end())
-    {
-        __radioButtons.erase(it);
-    }
-}
-
-RadioButton* RadioButton::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    RadioButton* radioButton = new RadioButton();
-    if (id)
-        radioButton->_id = id;
-    radioButton->setStyle(style);
-
-    __radioButtons.push_back(radioButton);
-
-    return radioButton;
-}
-
-Control* RadioButton::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    GP_ASSERT(properties);
-
-    RadioButton* radioButton = new RadioButton();
-    radioButton->initialize(style, properties);
-
-    properties->getVector2("imageSize", &radioButton->_imageSize);
-
-    if (properties->getBool("selected"))
-    {
-        RadioButton::clearSelected(radioButton->_groupId);
-        radioButton->_selected = true;
-    }
-
-    const char* groupId = properties->getString("group");
-    if (groupId)
-    {
-        radioButton->_groupId = groupId;
-    }
-
-    __radioButtons.push_back(radioButton);
-
-    return radioButton;
-}
-
-bool RadioButton::isSelected() const
-{
-    return _selected;
-}
-
-void RadioButton::setSelected(bool selected)
-{
-    if (selected)
-        RadioButton::clearSelected(_groupId);
-
-    if (selected != _selected)
-    {
-        _selected = selected;
-        _dirty = true;
-        notifyListeners(Control::Listener::VALUE_CHANGED);
-    }
-}
-
-void RadioButton::setImageSize(float width, float height)
-{
-    _imageSize.set(width, height);
-    _dirty = true;
-}
-
-const Vector2& RadioButton::getImageSize() const
-{
-    return _imageSize;
-}
-
-void RadioButton::addListener(Control::Listener* listener, int eventFlags)
-{
-    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
-    {
-        GP_ERROR("TEXT_CHANGED event is not applicable to RadioButton.");
-    }
-
-    Control::addListener(listener, eventFlags);
-}
-
-bool RadioButton::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    switch (evt)
-    {
-    case Touch::TOUCH_RELEASE:
-        {
-            if (_contactIndex == (int) _contactIndex && _state == Control::ACTIVE)
-            {
-                if (!_parent->isScrolling() &&
-                    x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                    y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-                {
-                    if (!_selected)
-                    {
-                        RadioButton::clearSelected(_groupId);
-                        _selected = true;
-                        notifyListeners(Control::Listener::VALUE_CHANGED);
-                    }
-                }
-            }
-        }
-        break;
-    }
-
-    return Button::touchEvent(evt, x, y, contactIndex);
-}
-
-bool RadioButton::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
-{
-    switch (evt)
-    {
-    case Gamepad::BUTTON_EVENT:
-        if (_state == Control::ACTIVE)
-        {
-            if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
-                !gamepad->isButtonDown(Gamepad::BUTTON_X))
-            {
-                RadioButton::clearSelected(_groupId);
-                _selected = true;
-                notifyListeners(Control::Listener::VALUE_CHANGED);
-            }
-        }
-        break;
-    }
-
-    return Button::gamepadEvent(evt, gamepad, analogIndex);
-}
-
-void RadioButton::clearSelected(const std::string& groupId)
-{
-    std::vector<RadioButton*>::const_iterator it;
-    for (it = __radioButtons.begin(); it < __radioButtons.end(); ++it)
-    {
-        RadioButton* radioButton = *it;
-        GP_ASSERT(radioButton);
-        if (groupId == radioButton->_groupId)
-        {
-            radioButton->_selected = false;
-            radioButton->_dirty = true;
-            radioButton->notifyListeners(Control::Listener::VALUE_CHANGED);
-        }
-    }
-}
-
-bool RadioButton::keyEvent(Keyboard::KeyEvent evt, int key)
-{
-    if (_state == ACTIVE && evt == Keyboard::KEY_RELEASE && key == Keyboard::KEY_RETURN && !_selected)
-    {
-        RadioButton::clearSelected(_groupId);
-        _selected = true;
-        notifyListeners(Control::Listener::VALUE_CHANGED);
-    }
-
-    return Button::keyEvent(evt, key);
-}
-
-void RadioButton::update(const Control* container, const Vector2& offset)
-{
-    Label::update(container, offset);
-
-    Vector2 size;
-    if (_imageSize.isZero())
-    {
-        if (_selected)
-        {
-            const Rectangle& selectedRegion = getImageRegion("selected", _state);
-            size.set(selectedRegion.width, selectedRegion.height);
-        }
-        else
-        {
-            const Rectangle& unselectedRegion = getImageRegion("unselected", _state);
-            size.set(unselectedRegion.width, unselectedRegion.height);
-        }
-    }
-    else
-    {
-        size.set(_imageSize);
-    }
-
-    if (_autoWidth == Control::AUTO_SIZE_FIT)
-    {
-        // Text-only width was already measured in Label::update - append image
-        setWidth(size.x + _bounds.width + 5);
-    }
-
-    if (_autoHeight == Control::AUTO_SIZE_FIT)
-    {
-        // Text-only width was already measured in Label::update - append image
-        setHeight(std::max(getHeight(), size.y));
-    }
-
-    _textBounds.x += size.x + 5;
-    
-    if (_selected)
-    {
-        _image = getImage("selected", _state);
-    }
-    else
-    {
-        _image = getImage("unselected", _state);
-    }
-}
-
-void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
-{
-    GP_ASSERT(spriteBatch);
-    GP_ASSERT(_image);
-
-    // Left, v-center.
-    // TODO: Set an alignment for radio button images.   
-    const Rectangle& region = _image->getRegion();
-    const Theme::UVs& uvs = _image->getUVs();
-    Vector4 color = _image->getColor();
-    color.w *= _opacity;
-
-    Vector2 size;
-    if (_imageSize.isZero())
-    {
-        size.set(region.width, region.height);
-    }
-    else
-    {
-        size.set(_imageSize);
-    }
-
-    Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
-
-    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
-}
-
-const char* RadioButton::getType() const
-{
-    return "radioButton";
-}
-
-void RadioButton::setGroupId(const char* groupId)
-{
-    _groupId = groupId;
-}
-
-const char* RadioButton::getGroupId() const
-{
-    return _groupId.c_str();
-}
-
-}
+#include "Base.h"
+#include "RadioButton.h"
+
+namespace gameplay
+{
+static std::vector<RadioButton*> __radioButtons;
+
+RadioButton::RadioButton() : _selected(false), _image(NULL)
+{
+}
+
+RadioButton::~RadioButton()
+{
+    // Remove this RadioButton from the global list.
+    std::vector<RadioButton*>::iterator it = std::find(__radioButtons.begin(), __radioButtons.end(), this);
+    if (it != __radioButtons.end())
+    {
+        __radioButtons.erase(it);
+    }
+}
+
+RadioButton* RadioButton::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    RadioButton* radioButton = new RadioButton();
+    if (id)
+        radioButton->_id = id;
+    radioButton->setStyle(style);
+
+    __radioButtons.push_back(radioButton);
+
+    return radioButton;
+}
+
+Control* RadioButton::create(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    RadioButton* radioButton = new RadioButton();
+    radioButton->initialize(style, properties);
+
+    properties->getVector2("imageSize", &radioButton->_imageSize);
+
+    if (properties->getBool("selected"))
+    {
+        RadioButton::clearSelected(radioButton->_groupId);
+        radioButton->_selected = true;
+    }
+
+    const char* groupId = properties->getString("group");
+    if (groupId)
+    {
+        radioButton->_groupId = groupId;
+    }
+
+    __radioButtons.push_back(radioButton);
+
+    return radioButton;
+}
+
+bool RadioButton::isSelected() const
+{
+    return _selected;
+}
+
+void RadioButton::setSelected(bool selected)
+{
+    if (selected)
+        RadioButton::clearSelected(_groupId);
+
+    if (selected != _selected)
+    {
+        _selected = selected;
+        _dirty = true;
+        notifyListeners(Control::Listener::VALUE_CHANGED);
+    }
+}
+
+void RadioButton::setImageSize(float width, float height)
+{
+    _imageSize.set(width, height);
+    _dirty = true;
+}
+
+const Vector2& RadioButton::getImageSize() const
+{
+    return _imageSize;
+}
+
+void RadioButton::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
+    {
+        GP_ERROR("TEXT_CHANGED event is not applicable to RadioButton.");
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
+void RadioButton::clearSelected(const std::string& groupId)
+{
+    std::vector<RadioButton*>::const_iterator it;
+    for (it = __radioButtons.begin(); it < __radioButtons.end(); ++it)
+    {
+        RadioButton* radioButton = *it;
+        GP_ASSERT(radioButton);
+        if (groupId == radioButton->_groupId)
+        {
+            radioButton->_selected = false;
+            radioButton->_dirty = true;
+            radioButton->notifyListeners(Control::Listener::VALUE_CHANGED);
+        }
+    }
+}
+
+bool RadioButton::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+    if (getState() == ACTIVE && evt == Keyboard::KEY_RELEASE && key == Keyboard::KEY_RETURN && !_selected)
+    {
+        RadioButton::clearSelected(_groupId);
+        _selected = true;
+        notifyListeners(Control::Listener::VALUE_CHANGED);
+    }
+
+    return Button::keyEvent(evt, key);
+}
+
+void RadioButton::controlEvent(Control::Listener::EventType evt)
+{
+    Button::controlEvent(evt);
+
+    switch (evt)
+    {
+    case Control::Listener::CLICK:
+        if (!_selected)
+        {
+            RadioButton::clearSelected(_groupId);
+            _selected = true;
+            notifyListeners(Control::Listener::VALUE_CHANGED);
+        }
+        break;
+    }
+}
+
+void RadioButton::update(const Control* container, const Vector2& offset)
+{
+    Label::update(container, offset);
+
+    Vector2 size;
+    if (_imageSize.isZero())
+    {
+        if (_selected)
+        {
+            const Rectangle& selectedRegion = getImageRegion("selected", getState());
+            size.set(selectedRegion.width, selectedRegion.height);
+        }
+        else
+        {
+            const Rectangle& unselectedRegion = getImageRegion("unselected", getState());
+            size.set(unselectedRegion.width, unselectedRegion.height);
+        }
+    }
+    else
+    {
+        size.set(_imageSize);
+    }
+
+    if (_autoWidth == Control::AUTO_SIZE_FIT)
+    {
+        // Text-only width was already measured in Label::update - append image
+        setWidth(size.x + _bounds.width + 5);
+    }
+
+    if (_autoHeight == Control::AUTO_SIZE_FIT)
+    {
+        // Text-only width was already measured in Label::update - append image
+        setHeight(std::max(getHeight(), size.y));
+    }
+
+    _textBounds.x += size.x + 5;
+    
+    if (_selected)
+    {
+        _image = getImage("selected", getState());
+    }
+    else
+    {
+        _image = getImage("unselected", getState());
+    }
+}
+
+void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    GP_ASSERT(spriteBatch);
+    GP_ASSERT(_image);
+
+    // Left, v-center.
+    // TODO: Set an alignment for radio button images.   
+    const Rectangle& region = _image->getRegion();
+    const Theme::UVs& uvs = _image->getUVs();
+    Vector4 color = _image->getColor();
+    color.w *= _opacity;
+
+    Vector2 size;
+    if (_imageSize.isZero())
+    {
+        size.set(region.width, region.height);
+    }
+    else
+    {
+        size.set(_imageSize);
+    }
+
+    Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
+
+    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
+}
+
+const char* RadioButton::getType() const
+{
+    return "radioButton";
+}
+
+void RadioButton::setGroupId(const char* groupId)
+{
+    _groupId = groupId;
+}
+
+const char* RadioButton::getGroupId() const
+{
+    return _groupId.c_str();
+}
+
+}

+ 198 - 215
gameplay/src/RadioButton.h

@@ -1,215 +1,198 @@
-#ifndef RADIOBUTTON_H_
-#define RADIOBUTTON_H_
-
-#include "Button.h"
-#include "Theme.h"
-#include "Properties.h"
-
-namespace gameplay
-{
-
-/**
- * Similar to a checkbox, a radio button can be toggled between two states.
- *
- * However, a radio button can belong to a group, and only one radio button
- * from a group can be selected at one time.
- *
- * The following properties are available for radio buttons:
-
- @verbatim
-    radioButton <RadioButton ID>
-    {
-         style       = <Style ID>
-         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
-         position    = <x, y>
-         autoWidth   = <bool>
-         autoHeight  = <bool>
-         size        = <width, height>
-         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
-         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
-         text        = <string>
-         group       = <string>
-         iconSize    = <width, height>   // The size to draw the radio button icon, if different from its size in the texture.
-         consumeEvents = <bool>          // Whether the radio button propagates input events to the Game's input event handler. Default is true.
-    }
- @endverbatim
- */
-class RadioButton : public Button
-{
-    friend class Container;
-	friend class ControlFactory;
-
-public:
-
-    /**
-     * Create a new radio button control.
-     *
-     * @param id The control's ID.
-     * @param style The control's style.
-     *
-     * @return The new radio button.
-     * @script{create}
-     */
-    static RadioButton* create(const char* id, Theme::Style* style);
-
-    /**
-     * Get whether this radio button is currently selected.
-     *
-     * @return Whether this radio button is currently selected.
-     */
-    bool isSelected() const;
-
-    /**
-     * Sets whether this radio button is currently selected.
-     */
-    void setSelected(bool selected);
-
-    /**
-     * Set the size to draw the radio button icon.
-     *
-     * @param width The width to draw the radio button icon.
-     * @param height The height to draw the radio button icon.
-     */
-    void setImageSize(float width, float height);
-
-    /**
-     * Get the size at which the radio button icon will be drawn.
-     *
-     * @return The size of the radio button icon.
-     */
-    const Vector2& getImageSize() const;
-
-    /**
-     * @see Control::getType
-     */
-    const char* getType() const;
-
-    /**
-     * Add a listener to be notified of specific events affecting
-     * this control.  Event types can be OR'ed together.
-     * E.g. To listen to touch-press and touch-release events,
-     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
-     * as the second parameter.
-     *
-     * @param listener The listener to add.
-     * @param eventFlags The events to listen for.
-     */
-    virtual void addListener(Control::Listener* listener, int eventFlags);
-
-    /**
-     *
-     * @param groupId
-     */
-    void setGroupId(const char* groupId);
-
-    /**
-     * Gets the RadioButton's group ID.
-     *
-     * @return the RadioButton's group ID.
-     */
-    const char* getGroupId() const;
-
-protected:
-
-    /**
-     * Constructor.
-     */
-    RadioButton();
-
-    /**
-     * Destructor.
-     */
-    virtual ~RadioButton();
-
-    /**
-     * Create a radio button with a given style and properties.
-     *
-     * @param style The style to apply to this radio button.
-     * @param properties The properties to set on this radio button.
-     * @param theme The theme to set on this control if needed
-	 *
-     * @return The new radio button.
-     */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
-
-    /**
-     * Touch callback on touch events.  Controls return true if they consume the touch event.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by the control.
-     *
-     * @see Touch::TouchEvent
-     */
-    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-
-    /**
-     * Gamepad callback on gamepad events.
-     *
-     * @see Control::gamepadEvent
-     */
-    bool gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
-
-    /**
-     * Keyboard callback on key events.
-     *
-     * @see Keyboard::KeyEvent
-     * @see Keyboard::Key
-     */
-    bool keyEvent(Keyboard::KeyEvent evt, int key);
-
-    /**
-     * Called when a control's properties change.  Updates this control's internal rendering
-     * properties, such as its text viewport.
-     *
-     * @param container This control's parent container.
-     * @param offset Positioning offset to add to the control's position.
-     */
-    void update(const Control* container, const Vector2& offset);
-
-    /**
-     * Draw the images associated with this control.
-     *
-     * @param spriteBatch The sprite batch containing this control's icons.
-     * @param clip The clipping rectangle of this control's parent container.
-     */
-    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-    /**
-     * Clear the _selected flag of all radio buttons in the given group.
-     *
-     * @param groupId The group to clear.
-     */
-    static void clearSelected(const std::string& groupId);
-
-    /**
-     * The RadioButton's group ID.
-     */
-    std::string _groupId;
-    
-    /**
-     * Whether the RadioButton is currently selected.
-     */
-    bool _selected;
-    
-    /**
-     * The size at which the RadioButton's icon will be drawn.
-     */
-    Vector2 _imageSize;
-
-    /**
-     * The ThemeImage to use for the RadioButton.
-     */ 
-    Theme::ThemeImage* _image;
-
-private:
-
-    RadioButton(const RadioButton& copy);
-};
-
-}
-
-#endif
+#ifndef RADIOBUTTON_H_
+#define RADIOBUTTON_H_
+
+#include "Button.h"
+#include "Theme.h"
+#include "Properties.h"
+
+namespace gameplay
+{
+
+/**
+ * Similar to a checkbox, a radio button can be toggled between two states.
+ *
+ * However, a radio button can belong to a group, and only one radio button
+ * from a group can be selected at one time.
+ *
+ * The following properties are available for radio buttons:
+
+ @verbatim
+    radioButton <RadioButton ID>
+    {
+         style       = <Style ID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+         group       = <string>
+         iconSize    = <width, height>   // The size to draw the radio button icon, if different from its size in the texture.
+         consumeEvents = <bool>          // Whether the radio button propagates input events to the Game's input event handler. Default is true.
+    }
+ @endverbatim
+ */
+class RadioButton : public Button
+{
+    friend class Container;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Create a new radio button control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new radio button.
+     * @script{create}
+     */
+    static RadioButton* create(const char* id, Theme::Style* style);
+
+    /**
+     * Get whether this radio button is currently selected.
+     *
+     * @return Whether this radio button is currently selected.
+     */
+    bool isSelected() const;
+
+    /**
+     * Sets whether this radio button is currently selected.
+     */
+    void setSelected(bool selected);
+
+    /**
+     * Set the size to draw the radio button icon.
+     *
+     * @param width The width to draw the radio button icon.
+     * @param height The height to draw the radio button icon.
+     */
+    void setImageSize(float width, float height);
+
+    /**
+     * Get the size at which the radio button icon will be drawn.
+     *
+     * @return The size of the radio button icon.
+     */
+    const Vector2& getImageSize() const;
+
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    virtual void addListener(Control::Listener* listener, int eventFlags);
+
+    /**
+     *
+     * @param groupId
+     */
+    void setGroupId(const char* groupId);
+
+    /**
+     * Gets the RadioButton's group ID.
+     *
+     * @return the RadioButton's group ID.
+     */
+    const char* getGroupId() const;
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    RadioButton();
+
+    /**
+     * Destructor.
+     */
+    virtual ~RadioButton();
+
+    /**
+     * Create a radio button with a given style and properties.
+     *
+     * @param style The style to apply to this radio button.
+     * @param properties The properties to set on this radio button.
+     *
+     * @return The new radio button.
+     */
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    /**
+     * Keyboard callback on key events.
+     *
+     * @see Keyboard::KeyEvent
+     * @see Keyboard::Key
+     */
+    bool keyEvent(Keyboard::KeyEvent evt, int key);
+
+    /**
+     * @see Control#controlEvent
+     */
+    void controlEvent(Control::Listener::EventType evt);
+
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param container This control's parent container.
+     * @param offset Positioning offset to add to the control's position.
+     */
+    void update(const Control* container, const Vector2& offset);
+
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
+    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    /**
+     * Clear the _selected flag of all radio buttons in the given group.
+     *
+     * @param groupId The group to clear.
+     */
+    static void clearSelected(const std::string& groupId);
+
+    /**
+     * The RadioButton's group ID.
+     */
+    std::string _groupId;
+    
+    /**
+     * Whether the RadioButton is currently selected.
+     */
+    bool _selected;
+    
+    /**
+     * The size at which the RadioButton's icon will be drawn.
+     */
+    Vector2 _imageSize;
+
+    /**
+     * The ThemeImage to use for the RadioButton.
+     */ 
+    Theme::ThemeImage* _image;
+
+private:
+
+    RadioButton(const RadioButton& copy);
+};
+
+}
+
+#endif

+ 17 - 1
gameplay/src/RenderState.cpp

@@ -85,7 +85,23 @@ MaterialParameter* RenderState::getParameter(const char* name) const
     return param;
 }
 
-void RenderState::clearParameter(const char* name)
+unsigned int RenderState::getParameterCount() const
+{
+    return _parameters.size();
+}
+
+MaterialParameter* RenderState::getParameterByIndex(unsigned int index)
+{
+    return _parameters[index];
+}
+
+void RenderState::addParameter(MaterialParameter* param)
+{
+    _parameters.push_back(param);
+    param->addRef();
+}
+
+void RenderState::removeParameter(const char* name)
 {
     for (size_t i = 0, count = _parameters.size(); i < count; ++i)
     {

+ 24 - 3
gameplay/src/RenderState.h

@@ -418,7 +418,7 @@ public:
     };
 
     /**
-     * Returns a MaterialParameter for the specified name.
+     * Gets a MaterialParameter for the specified name.
      * 
      * The returned MaterialParameter can be used to set values for the specified
      * parameter name.
@@ -433,14 +433,35 @@ public:
     MaterialParameter* getParameter(const char* name) const;
 
     /**
-     * Clears the MaterialParameter with the given name.
+     * Gets the number of material parameters.
+     *
+     * @return The number of material parameters.
+     */
+    unsigned int getParameterCount() const;
+
+    /**
+     * Gets a MaterialParameter for the specified index.
+     *
+     * @return A MaterialParameter for the specified index.
+     */
+    MaterialParameter* getParameterByIndex(unsigned int index);
+
+    /**
+     * Adds a MaterialParameter to the render state.
+     *
+     * @param param The parameters to to added.
+     */
+    void addParameter(MaterialParameter* param);
+
+    /**
+     * Removes(clears) the MaterialParameter with the given name.
      *
      * If a material parameter exists for the given name, it is destroyed and
      * removed from this RenderState.
      *
      * @param name Material parameter (uniform) name.
      */
-    void clearParameter(const char* name);
+    void removeParameter(const char* name);
 
     /**
      * Sets a material parameter auto-binding.

+ 50 - 248
gameplay/src/Scene.cpp

@@ -59,8 +59,9 @@ static bool endsWith(const char* str, const char* suffix, bool ignoreCase)
 }
 
 
-Scene::Scene(const char* id)
-    : _id(id ? id : ""), _activeCamera(NULL), _firstNode(NULL), _lastNode(NULL), _nodeCount(0), _bindAudioListenerToCamera(true), _debugBatch(NULL)
+Scene::Scene()
+    : _id(""), _activeCamera(NULL), _firstNode(NULL), _lastNode(NULL), _nodeCount(0), _bindAudioListenerToCamera(true), 
+      _nextItr(NULL), _nextReset(true)
 {
     __sceneList.push_back(this);
 }
@@ -81,7 +82,6 @@ Scene::~Scene()
 
     // Remove all nodes from the scene
     removeAllNodes();
-    SAFE_DELETE(_debugBatch);
 
     // Remove the scene from global list
     std::vector<Scene*>::iterator itr = std::find(__sceneList.begin(), __sceneList.end(), this);
@@ -91,7 +91,9 @@ Scene::~Scene()
 
 Scene* Scene::create(const char* id)
 {
-    return new Scene(id);
+    Scene* scene = new Scene();
+    scene->setId(id);
+    return scene;
 }
 
 Scene* Scene::load(const char* filePath)
@@ -124,6 +126,7 @@ Scene* Scene::getScene(const char* id)
     return NULL;
 }
 
+
 const char* Scene::getId() const
 {
     return _id.c_str();
@@ -160,7 +163,6 @@ Node* Scene::findNode(const char* id, bool recursive, bool exactMatch) const
             }
         }
     }
-
     return NULL;
 }
 
@@ -322,7 +324,7 @@ Node* Scene::getFirstNode() const
     return _firstNode;
 }
 
-Camera* Scene::getActiveCamera() const
+Camera* Scene::getActiveCamera()
 {
     return _activeCamera;
 }
@@ -382,276 +384,76 @@ void Scene::setAmbientColor(float red, float green, float blue)
     _ambientColor.set(red, green, blue);
 }
 
-static Material* createDebugMaterial()
+void Scene::update(float elapsedTime)
 {
-    // Vertex shader for drawing colored lines.
-    const char* vs_str = 
-    {
-        "uniform mat4 u_viewProjectionMatrix;\n"
-        "attribute vec4 a_position;\n"
-        "attribute vec4 a_color;\n"
-        "varying vec4 v_color;\n"
-        "void main(void) {\n"
-        "    v_color = a_color;\n"
-        "    gl_Position = u_viewProjectionMatrix * a_position;\n"
-        "}"
-    };
-
-    // Fragment shader for drawing colored lines.
-    const char* fs_str = 
+    for (Node* node = _firstNode; node != NULL; node = node->_nextSibling)
     {
-    #ifdef OPENGL_ES
-        "precision highp float;\n"
-    #endif
-        "varying vec4 v_color;\n"
-        "void main(void) {\n"
-        "   gl_FragColor = v_color;\n"
-        "}"
-    };
-
-    Effect* effect = Effect::createFromSource(vs_str, fs_str);
-    Material* material = Material::create(effect);
-    GP_ASSERT(material && material->getStateBlock());
-    material->getStateBlock()->setDepthTest(true);
-
-    SAFE_RELEASE(effect);
-
-    return material;
-}
-
-/**
- * DebugVertex structure.
- * @script{ignore}
- */
-struct DebugVertex
-{
-    /**
-     * The x coordinate of the vertex.
-     */
-    float x;
-
-    /**
-     * The y coordinate of the vertex.
-     */
-    float y;
-    
-    /**
-     * The z coordinate of the vertex.
-     */
-    float z;
-    
-    /** 
-     * The red color component of the vertex.
-     */
-    float r;
-
-    /** 
-     * The green color component of the vertex.
-     */
-    float g;
-    
-    /** 
-     * The blue color component of the vertex.
-     */
-    float b;
-    
-    /** 
-     * The alpha component of the vertex.
-     */
-    float a;
-};
-
-static void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point2, const Vector3& color)
-{
-    GP_ASSERT(batch);
-
-    static DebugVertex verts[2];
-
-    verts[0].x = point1.x;
-    verts[0].y = point1.y;
-    verts[0].z = point1.z;
-    verts[0].r = color.x;
-    verts[0].g = color.y;
-    verts[0].b = color.z;
-    verts[0].a = 1.0f;
-
-    verts[1].x = point2.x;
-    verts[1].y = point2.y;
-    verts[1].z = point2.z;
-    verts[1].r = color.x;
-    verts[1].g = color.y;
-    verts[1].b = color.z;
-    verts[1].a = 1.0f;
-
-    batch->add(verts, 2);
+        if (node->isActive())
+            node->update(elapsedTime);
+    }
 }
 
-#define DEBUG_BOX_COLOR Vector3(0, 1, 0)
-#define DEBUG_SPHERE_COLOR Vector3(0, 1, 0)
-
-static void drawDebugBox(MeshBatch* batch, const BoundingBox& box, const Matrix& matrix)
+void Scene::reset()
 {
-    if (box.isEmpty())
-        return;
-
-    // Transform box into world space (since we only store local boxes on mesh)
-    BoundingBox worldSpaceBox(box);
-    worldSpaceBox.transform(matrix);
-
-    // Get box corners
-    static Vector3 corners[8];
-    worldSpaceBox.getCorners(corners);
-
-    // Draw box lines
-    drawDebugLine(batch, corners[0], corners[1], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[1], corners[2], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[2], corners[3], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[3], corners[0], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[4], corners[5], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[5], corners[6], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[6], corners[7], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[7], corners[4], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[0], corners[7], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[1], corners[6], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[2], corners[5], DEBUG_BOX_COLOR);
-    drawDebugLine(batch, corners[3], corners[4], DEBUG_BOX_COLOR);
+    _nextItr = NULL;
+    _nextReset = true;
 }
 
-static void drawDebugSphere(MeshBatch* batch, const BoundingSphere& sphere)
+Node* Scene::getNext()
 {
-    if (sphere.isEmpty())
-        return;
-
-    // Draw three rings for the sphere (one for the x, y and z axes)
-    Vector3 pos1, pos2;
-    float step = MATH_PI * 0.2f;
-    float max = MATH_PIX2 + step;
-
-    // X ring
-    for (float r = 0.0f; r < max; r += step)
+    if (_nextReset)
     {
-        pos2.x = sphere.center.x;
-        pos2.y = sphere.center.y + std::cos(r) * sphere.radius;
-        pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
-
-        if (r > 0)
-            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-        pos1 = pos2;
-    }
-
-    // Y ring
-    for (float r = 0.0f; r < max; r += step)
-    {
-        pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
-        pos2.y = sphere.center.y;
-        pos2.z = sphere.center.z + std::sin(r) * sphere.radius;
-
-        if (r > 0)
-            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-        pos1 = pos2;
+        _nextItr = findNextVisibleSibling(getFirstNode());
+        _nextReset = false;
     }
-
-    // Z ring
-    for (float r = 0.0f; r < max; r += step)
+    else if (_nextItr)
     {
-        pos2.x = sphere.center.x + std::cos(r) * sphere.radius;
-        pos2.y = sphere.center.y + std::sin(r) * sphere.radius;
-        pos2.z = sphere.center.z;
-
-        if (r > 0)
-            drawDebugLine(batch, pos1, pos2, DEBUG_SPHERE_COLOR);
-
-        pos1 = pos2;
-    }
-}
-
-static void drawDebugNode(Scene* scene, MeshBatch* batch, Node* node, unsigned int debugFlags)
-{
-    GP_ASSERT(node);
-
-    // If the node isn't visible, don't draw its bounds
-    Camera* camera = scene->getActiveCamera();
-    if (camera)
-    {
-        const BoundingSphere& sphere = node->getBoundingSphere();
-        if (!sphere.isEmpty() && !camera->getFrustum().intersects(sphere))
-            return;
-    }
-
-    if (debugFlags & Scene::DEBUG_BOXES)
-    {
-        if (node->getModel())
+        Node* node = findNextVisibleSibling(_nextItr->getFirstChild());
+        if (node == NULL)
         {
-            Model* model = node->getModel();
-            GP_ASSERT(model->getMesh());
-
-            MeshSkin* skin = model->getSkin();
-            if (skin && skin->getRootJoint() && skin->getRootJoint()->getParent())
-            {
-                // For skinned meshes that have a parent node to the skin's root joint,
-                // we need to transform the bounding volume by that parent node's transform
-                // as well to get the full skinned bounding volume.
-                drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix() * skin->getRootJoint()->getParent()->getWorldMatrix());
-            }
-            else
+            node = findNextVisibleSibling(_nextItr->getNextSibling());
+            if (node == NULL)
             {
-                drawDebugBox(batch, model->getMesh()->getBoundingBox(), node->getWorldMatrix());
+                // Find first parent with a sibling
+                node = _nextItr->getParent();
+                while (node && (!findNextVisibleSibling(node->getNextSibling())))
+                {
+                    node = node->getParent();
+                }
+                if (node)
+                {
+                    node = findNextVisibleSibling(node->getNextSibling());
+                }
             }
         }
-
-        if (node->getTerrain())
-        {
-            drawDebugBox(batch, node->getTerrain()->getBoundingBox(), node->getWorldMatrix());
-        }
+        _nextItr = node;
     }
+    return _nextItr;
+}
 
-    if (debugFlags & Scene::DEBUG_SPHERES)
-    {
-        drawDebugSphere(batch, node->getBoundingSphere());
-    }
 
-    for (Node* child = node->getFirstChild(); child != NULL; child = child->getNextSibling())
+Node* Scene::findNextVisibleSibling(Node* node)
+{
+    while (node != NULL && !isNodeVisible(node))
     {
-        drawDebugNode(scene, batch, child, debugFlags);
+        node = node->getNextSibling();
     }
+    return node;
 }
 
-void Scene::drawDebug(unsigned int debugFlags)
+bool Scene::isNodeVisible(Node* node)
 {
-    if (_debugBatch == NULL)
-    {
-        Material* material = createDebugMaterial();
-
-        VertexFormat::Element elements[] =
-        {
-            VertexFormat::Element(VertexFormat::POSITION, 3),
-            VertexFormat::Element(VertexFormat::COLOR, 4)
-        };
-
-        _debugBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
-
-        SAFE_RELEASE(material);
-    }
-
-    _debugBatch->start();
+    if (!node->isActive())
+        return false;
 
-    for (Node* node = _firstNode; node != NULL; node = node->_nextSibling)
+    if (node->getForm() || node->getParticleEmitter() || node->getTerrain() || node->getLight() || node->getCamera())
     {
-        drawDebugNode(this, _debugBatch, node, debugFlags);
+        return true;
     }
-
-    _debugBatch->finish();
-
-    if (_activeCamera)
+    else
     {
-        GP_ASSERT(_debugBatch->getMaterial());
-        GP_ASSERT(_debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix"));
-        _debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
+        return node->getBoundingSphere().intersects(_activeCamera->getFrustum());
     }
-
-    _debugBatch->draw();
 }
 
 }

+ 38 - 36
gameplay/src/Scene.h

@@ -16,18 +16,9 @@ class Scene : public Ref
 {
 public:
 
-    /**
-     * Enumeration of supported scene debug flags for debug drawing.
-     */
-    enum DebugFlags
-    {
-        DEBUG_BOXES = 1,
-        DEBUG_SPHERES = 2
-    };
-
     /**
      * Creates a new empty scene.
-     * 
+     *
      * @param id ID of the new scene, or NULL to use an empty string for the ID (default).
      *
      * @return The newly created empty scene.
@@ -37,7 +28,7 @@ public:
 
     /**
      * Loads a scene from the given '.scene' or '.gpb' file.
-     * 
+     *
      * @param filePath The path to the '.scene' or '.gpb' file to load from.
      * @return The loaded scene or <code>NULL</code> if the scene
      *      could not be loaded from the given file.
@@ -77,7 +68,7 @@ public:
      * @param recursive true if a recursive search should be performed, false otherwise.
      * @param exactMatch true if only nodes whose ID exactly matches the specified ID are returned,
      *      or false if nodes that start with the given ID are returned.
-     * 
+     *
      * @return The first node found that matches the given ID.
      */
     Node* findNode(const char* id, bool recursive = true, bool exactMatch = true) const;
@@ -90,7 +81,7 @@ public:
      * @param recursive true if a recursive search should be performed, false otherwise.
      * @param exactMatch true if only nodes who's ID exactly matches the specified ID are returned,
      *      or false if nodes that start with the given ID are returned.
-     * 
+     *
      * @return The number of matches found.
      * @script{ignore}
      */
@@ -100,14 +91,14 @@ public:
      * Creates and adds a new node to the scene.
      *
      * @param id An optional node ID.
-     * 
+     *
      * @return The new node.
      */
     Node* addNode(const char* id = NULL);
 
     /**
      * Adds the specified node to the scene.
-     * 
+     *
      * @param node The node to be added to the scene.
      */
     void addNode(Node* node);
@@ -133,7 +124,7 @@ public:
 
     /**
      * Returns the first node in the scene.
-     * 
+     *
      * @return The first node in the scene.
      */
     Node* getFirstNode() const;
@@ -142,20 +133,21 @@ public:
      * Gets the active camera for the scene.
      *
      * @return The active camera for the scene.
+     * @see VisibleSet#getActiveCamera
      */
-    Camera* getActiveCamera() const;
+    Camera* getActiveCamera();
 
     /**
      * Sets the active camera on the scene.
-     * 
+     *
      * @param camera The active camera to be set on the scene.
      */
     void setActiveCamera(Camera* camera);
 
     /**
-     * Sets the audio listener to transform along with the active camera if set to true.  
+     * Sets the audio listener to transform along with the active camera if set to true.
      * If you have a 2D game that doesn't require it, then set to false.  This is on by default for the scene.
-     * 
+     *
      * @param bind true if you want to the audio listener to follow the active camera's transform.
      */
     void bindAudioListenerToCamera(bool bind);
@@ -166,14 +158,14 @@ public:
      * The default ambient light color is black (0,0,0).
      *
      * This value can be bound to materials using the SCENE_LIGHT_AMBIENT_COLOR auto binding.
-     * 
+     *
      * @return The scene's ambient color.
      */
     const Vector3& getAmbientColor() const;
 
     /**
      * Sets the ambient color of the scene.
-     * 
+     *
      * @param red The red channel between 0.0 and 1.0.
      * @param green The green channel between 0.0 and 1.0.
      * @param blue The blue channel between 0.0 and 1.0.
@@ -181,7 +173,7 @@ public:
      * @see getAmbientColor()
      */
     void setAmbientColor(float red, float green, float blue);
-    
+
     /**
      * Visits each node in the scene and calls the specified method pointer.
      *
@@ -206,7 +198,7 @@ public:
      *
      * Calling this method invokes the specified method pointer for each node
      * in the scene hierarchy, passing the Node and the specified cookie value.
-     * 
+     *
      * The visitMethod parameter must be a pointer to a method that has a bool
      * return type and accepts two parameters: a Node pointer and a cookie of a
      * user-specified type.
@@ -229,7 +221,7 @@ public:
      * in the scene hierarchy.
      *
      * The visitMethod parameter must be a string containing the name of a
-     * valid Lua function that has a boolean return type and accepts a 
+     * valid Lua function that has a boolean return type and accepts a
      * single parameter of type Node*.
      *
      * A depth-first traversal of the scene continues while the visit method
@@ -241,19 +233,26 @@ public:
     inline void visit(const char* visitMethod);
 
     /**
-     * Draws debugging information (bounding volumes, etc.) for the scene.
-     *
-     * @param debugFlags Bitwise combination of debug flags from the DebugFlags
-     *        enumeration, specifying which debugging information to draw.
+     * Updates all the active nodes in the scene.
      */
-    void drawDebug(unsigned int debugFlags);
+    void update(float elapsedTime);
+
+    /**
+     * @see VisibleSet#getNext
+     */
+    Node* getNext();
+
+    /**
+     * @see VisibleSet#reset
+     */
+    void reset();
 
 private:
 
     /**
      * Constructor.
      */
-    Scene(const char* id);
+    Scene();
 
     /**
      * Hidden copy constructor.
@@ -287,16 +286,19 @@ private:
      */
     void visitNode(Node* node, const char* visitMethod);
 
+    Node* findNextVisibleSibling(Node* node);
+
+    bool isNodeVisible(Node* node);
+
     std::string _id;
     Camera* _activeCamera;
     Node* _firstNode;
     Node* _lastNode;
     unsigned int _nodeCount;
     Vector3 _ambientColor;
-    Vector3 _lightColor;
-    Vector3 _lightDirection;
     bool _bindAudioListenerToCamera;
-    MeshBatch* _debugBatch;
+    Node* _nextItr;
+    bool _nextReset;
 };
 
 template <class T>
@@ -333,7 +335,7 @@ void Scene::visitNode(Node* node, T* instance, bool (T::*visitMethod)(Node*))
         return;
 
     // If this node has a model with a mesh skin, visit the joint hierarchy within it
-    // since we don't add joint hierarcies directly to the scene. If joints are never
+    // since we don't add joint hierarchies directly to the scene. If joints are never
     // visited, it's possible that nodes embedded within the joint hierarchy that contain
     // models will never get visited (and therefore never get drawn).
     if (node->_model && node->_model->_skin && node->_model->_skin->_rootNode)
@@ -356,7 +358,7 @@ void Scene::visitNode(Node* node, T* instance, bool (T::*visitMethod)(Node*,C),
         return;
 
     // If this node has a model with a mesh skin, visit the joint hierarchy within it
-    // since we don't add joint hierarcies directly to the scene. If joints are never
+    // since we don't add joint hierarchies directly to the scene. If joints are never
     // visited, it's possible that nodes embedded within the joint hierarchy that contain
     // models will never get visited (and therefore never get drawn).
     if (node->_model && node->_model->_skin && node->_model->_skin->_rootNode)

+ 5 - 5
gameplay/src/SceneLoader.cpp

@@ -65,7 +65,7 @@ Scene* SceneLoader::loadInternal(const char* url)
         _scene = loadMainSceneData(sceneProperties);
         if (!_scene)
         {
-            GP_ERROR("Failed to load main scene from bundle.");
+            GP_WARN("Failed to load main scene from bundle.");
             SAFE_DELETE(properties);
             return NULL;
         }
@@ -919,7 +919,7 @@ Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
     Bundle* bundle = Bundle::create(_gpbPath.c_str());
     if (!bundle)
     {
-        GP_ERROR("Failed to load scene GPB file '%s'.", _gpbPath.c_str());
+        GP_WARN("Failed to load scene GPB file '%s'.", _gpbPath.c_str());
         return NULL;
     }
 
@@ -927,7 +927,7 @@ Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
     Scene* scene = bundle->loadScene(NULL);
     if (!scene)
     {
-        GP_ERROR("Failed to load scene from '%s'.", _gpbPath.c_str());
+        GP_WARN("Failed to load scene from '%s'.", _gpbPath.c_str());
         SAFE_RELEASE(bundle);
         return NULL;
     }
@@ -1068,7 +1068,7 @@ void SceneLoader::loadReferencedFiles()
                 properties = Properties::create(fileString.c_str());
                 if (properties == NULL)
                 {
-                    GP_ERROR("Failed to load referenced properties file '%s'.", fileString.c_str());
+                    GP_WARN("Failed to load referenced properties file '%s'.", fileString.c_str());
                     continue;
                 }
 
@@ -1079,7 +1079,7 @@ void SceneLoader::loadReferencedFiles()
             Properties* p = getPropertiesFromNamespacePath(properties, namespacePath);
             if (!p)
             {
-                GP_ERROR("Failed to load referenced properties from url '%s'.", iter->first.c_str());
+                GP_WARN("Failed to load referenced properties from url '%s'.", iter->first.c_str());
                 continue;
             }
             iter->second = p;

+ 0 - 26
gameplay/src/SceneRenderer.cpp

@@ -1,26 +0,0 @@
-#include "Base.h"
-#include "SceneRenderer.h"
-
-namespace gameplay
-{
-
-SceneRenderer::SceneRenderer()
-    : _wireframe(false)
-{
-}
-
-SceneRenderer::~SceneRenderer()
-{
-}
-
-void SceneRenderer::setWireframe(bool wireframe)
-{
-    _wireframe = wireframe;
-}
-
-bool SceneRenderer::isWireframe() const
-{
-    return _wireframe;
-}
-
-}

+ 0 - 62
gameplay/src/SceneRenderer.h

@@ -1,62 +0,0 @@
-#ifndef SCENERENDERER_H_
-#define SCENERENDERER_H_
-
-#include "Scene.h"
-#include "VisibleSet.h"
-
-namespace gameplay
-{
-
-/**
- * Represents a class that support rendering of the active models in a scene 
- * and that are visible to the camera. 
- */
-class SceneRenderer
-{
-public:
-
-    /**
-     * Constructor.
-     *
-     * @param scene The scene to render.
-     * @param lighting The type of lighting system to use.
-     */
-    SceneRenderer();
-
-    /**
-     * Destructor.
-     */
-    virtual ~SceneRenderer();
-
-    /**
-     * Sets if the scene should be rendered in wireframe mode.
-     *
-     * @param wireframe if the scene should be rendered in wireframe mode.
-     */
-    void setWireframe(bool wireframe);
-
-    /**
-     * Determines if the scene should be rendered in wireframe mode.
-     *
-     * @return if the scene should be rendered in wireframe mode.
-     */
-    bool isWireframe() const;
-
-    /**
-     * Renders the scene with all the nodes visible from the active camera in the scene.
-     *
-     * @param scene
-     * param
-     * @return The number of nodes visited.
-     */
-    virtual unsigned int render(VisibleSet* set) = 0;
-
-protected:
-
-    bool _wireframe;
-
-};
-
-}
-
-#endif

+ 0 - 73
gameplay/src/SceneRendererForward.cpp

@@ -1,73 +0,0 @@
-#include "Base.h"
-#include "SceneRendererForward.h"
-#include "Terrain.h"
-#include "Model.h"
-#include "ParticleEmitter.h"
-#include "Form.h"
-
-namespace gameplay
-{
-
-SceneRendererForward::SceneRendererForward()
-    : SceneRenderer()
-{
-}
-
-SceneRendererForward::SceneRendererForward(const SceneRendererForward& copy)
-{
-}
-
-SceneRendererForward::~SceneRendererForward()
-{
-}
-
-SceneRendererForward* SceneRendererForward::create()
-{
-    return new SceneRendererForward();
-}
-
-unsigned int SceneRendererForward::render(VisibleSet* set)
-{
-    set->reset();
-    unsigned int drawCalls = 0;
-    Node* next = set->getNext();
-    do
-    {
-        drawCalls += drawNode(next);
-        next = set->getNext();
-
-    } while ( next != NULL);
-
-    return drawCalls;
-}
-
-unsigned int SceneRendererForward::drawNode(Node* node)
-{
-    unsigned int drawCalls = 0;
-
-    // Draw Terrain
-    Terrain* terrain = node->getTerrain();
-    if (terrain)
-        drawCalls += terrain->draw(isWireframe());
-
-    // Draw Models (Shadows) TODO:
-
-    // Draw Modes
-    Model* model = node->getModel();
-    if (model)
-        drawCalls += model->draw(isWireframe());
-
-    // Draw particles
-    ParticleEmitter* emitter = node->getParticleEmitter();
-    if (emitter)
-        drawCalls += emitter->draw();
-
-    // Draw forms
-    Form* form = node->getForm();
-    if (form)
-        drawCalls += form->draw();
-
-    return drawCalls;
-}
-
-}

+ 0 - 49
gameplay/src/SceneRendererForward.h

@@ -1,49 +0,0 @@
-#ifndef SCENERENDERERFORWARD_H_
-#define SCENERENDERERFORWARD_H_
-
-#include "SceneRenderer.h"
-
-namespace gameplay
-{
-
-/**
- * Represents a class that support rendering of the active models in a scene 
- * and that are visible to the camera. 
- */
-class SceneRendererForward : public SceneRenderer
-{
-public:
-
-    /**
-     * Creates a forward scene renderer
-     */
-    static SceneRendererForward* create();
-
-    /**
-     * @see SceneRenderer#render
-     */
-    unsigned int render(VisibleSet* set);
-
-private:
-
-    /**
-     * Constructor.
-     */
-    SceneRendererForward();
-
-    /**
-     * Constructor.
-     */
-    SceneRendererForward(const SceneRendererForward& copy);
-
-    /**
-     * Destructor.
-     */
-    ~SceneRendererForward();
-
-    unsigned int drawNode(Node* node);
-};
-
-}
-
-#endif

+ 489 - 621
gameplay/src/Slider.cpp

@@ -1,621 +1,489 @@
-#include "Slider.h"
-#include "Game.h"
-
-namespace gameplay
-{
-
-// Fraction of slider to scroll when mouse scrollwheel is used.
-static const float SCROLLWHEEL_FRACTION = 0.1f;
-// Fraction of slider to scroll for a delta of 1.0f when a gamepad is used.
-static const float GAMEPAD_FRACTION = 0.005f;
-// Distance that a slider must be moved before it starts consuming input events,
-// e.g. to prevent its parent container from scrolling at the same time.
-static const float SLIDER_THRESHOLD = 5.0f;
-
-Slider::Slider() : _min(0.0f), _max(0.0f), _step(0.0f), _value(0.0f), _delta(0.0f), _minImage(NULL),
-    _maxImage(NULL), _trackImage(NULL), _markerImage(NULL), _valueTextVisible(false),
-    _valueTextAlignment(Font::ALIGN_BOTTOM_HCENTER), _valueTextPrecision(0), _valueText(""),
-    _selectButtonDown(false), _directionButtonDown(false), _gamepadValue(0.0f)
-{
-}
-
-Slider::~Slider()
-{
-}
-
-Slider* Slider::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    Slider* slider = new Slider();
-    if (id)
-        slider->_id = id;
-    slider->setStyle(style);
-
-    return slider;
-}
-
-Control* Slider::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    GP_ASSERT(properties);
-
-    Slider* slider = new Slider();
-    slider->initialize(style, properties);
-
-    slider->_min = properties->getFloat("min");
-    slider->_max = properties->getFloat("max");
-    slider->_value = properties->getFloat("value");
-    slider->_step = properties->getFloat("step");
-    slider->_valueTextVisible = properties->getBool("valueTextVisible");
-    slider->_valueTextPrecision = properties->getInt("valueTextPrecision");
-
-    if (properties->exists("valueTextAlignment"))
-    {
-        slider->_valueTextAlignment = Font::getJustify(properties->getString("valueTextAlignment"));
-    }
-
-    return slider;
-}
-
-void Slider::setMin(float min)
-{
-    if (_min != _min)
-    {
-        _dirty = true;
-    }
-    _min = min;
-}
-
-float Slider::getMin() const
-{
-    return _min;
-}
-
-void Slider::setMax(float max)
-{
-    if (max != _max)
-    {
-        _dirty = true;
-    }
-    _max = max;
-}
-
-float Slider::getMax() const
-{
-    return _max;
-}
-
-void Slider::setStep(float step)
-{
-    _step = step;
-}
-
-float Slider::getStep() const
-{
-    return _step;
-}
-
-float Slider::getValue() const
-{
-    return _value;
-}
-
-void Slider::setValue(float value)
-{
-    float oldValue = _value;
-    _value = MATH_CLAMP(value, _min, _max);
-    if (_value != value)
-    {
-        _dirty = true;
-    }
-}
-
-void Slider::setValueTextVisible(bool valueTextVisible)
-{
-    if (valueTextVisible != _valueTextVisible)
-    {
-        _dirty = true;
-    }
-    _valueTextVisible = valueTextVisible;
-}
-
-bool Slider::isValueTextVisible() const
-{
-    return _valueTextVisible;
-}
-
-void Slider::setValueTextAlignment(Font::Justify alignment)
-{
-    if (alignment != _valueTextAlignment)
-    {
-        _dirty = true;
-    }
-    _valueTextAlignment = alignment;
-}
-
-Font::Justify Slider::getValueTextAlignment() const
-{
-    return _valueTextAlignment;
-}
-
-void Slider::setValueTextPrecision(unsigned int precision)
-{
-    if (precision != _valueTextPrecision)
-    {
-        _dirty = true;
-    }
-    _valueTextPrecision = precision;
-}
-
-unsigned int Slider::getValueTextPrecision() const
-{
-    return _valueTextPrecision;
-}
-
-void Slider::addListener(Control::Listener* listener, int eventFlags)
-{
-    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
-    {
-        GP_ERROR("TEXT_CHANGED event is not applicable to Slider.");
-    }
-
-    Control::addListener(listener, eventFlags);
-}
-
-bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{
-    switch (evt)
-    {
-    case Touch::TOUCH_PRESS:
-        if (_contactIndex != INVALID_CONTACT_INDEX)
-            return false;
-        else if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-        {
-            _state = Control::ACTIVE;
-            _originalX = x;
-            _originalValue = _value;
-            _originalConsumeInputEvents = _consumeInputEvents;
-            _moveCancelled = false;
-            // Fall through to calculate new value.
-        }
-        else
-        {
-            _state = NORMAL;
-            _dirty = true;
-            break;
-        }
-    case Touch::TOUCH_MOVE:
-    
-        if (evt != Touch::TOUCH_PRESS && _contactIndex != (int)contactIndex)
-            return false;
-
-        if (_moveCancelled)
-        {
-            break;
-        }
-        else if (abs(x - _originalX) > SLIDER_THRESHOLD)
-        {
-            // Start consuming input events once we've passed the slider's threshold.
-            _consumeInputEvents = true;
-        }
-        else if (_parent->isScrolling())
-        {
-            // Cancel the change in slider value if we pass the parent container's scrolling threshold.
-            float oldValue = _value;
-            _value = _originalValue;
-            if (_value != oldValue)
-            {
-                notifyListeners(Control::Listener::VALUE_CHANGED);
-            }
-
-            _dirty = true;
-            _moveCancelled = true;
-            _state = NORMAL;
-            _contactIndex = INVALID_CONTACT_INDEX;
-            _consumeInputEvents = _originalConsumeInputEvents;
-            break;
-        }
-
-        if (_state == ACTIVE &&
-            x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-        {
-            // Horizontal case.
-            const Theme::Border& border = getBorder(_state);
-            const Theme::Padding& padding = getPadding();
-            const Rectangle& minCapRegion = _minImage->getRegion();
-            const Rectangle& maxCapRegion = _maxImage->getRegion();
-
-            float markerPosition = ((float)x - maxCapRegion.width - border.left - padding.left) /
-                (_bounds.width - border.left - border.right - padding.left - padding.right - minCapRegion.width - maxCapRegion.width);
-            
-            if (markerPosition > 1.0f)
-            {
-                markerPosition = 1.0f;
-            }
-            else if (markerPosition < 0.0f)
-            {
-                markerPosition = 0.0f;
-            }
-
-            float oldValue = _value;
-            _value = (markerPosition * (_max - _min)) + _min;
-            if (_step > 0.0f)
-            {            
-                int numSteps = round(_value / _step);
-                _value = _step * numSteps;
-            }
-
-            // Call the callback if our value changed.
-            if (_value != oldValue)
-            {
-                notifyListeners(Control::Listener::VALUE_CHANGED);
-            }
-            _dirty = true;
-        }
-        break;
-    case Touch::TOUCH_RELEASE:
-        _consumeInputEvents = _originalConsumeInputEvents;
-
-        if (_contactIndex != (int) contactIndex)
-            return false;
-
-        _dirty = true;
-        _state = FOCUS;
-        break;
-    }
-    
-    if (evt == Touch::TOUCH_MOVE)
-        return _consumeInputEvents;
-    else
-        return Control::touchEvent(evt, x, y, contactIndex);
-}
-
-bool Slider::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
-{
-    switch (evt)
-    {
-        case Mouse::MOUSE_PRESS_LEFT_BUTTON:
-            return touchEvent(Touch::TOUCH_PRESS, x, y, 0);
-
-        case Mouse::MOUSE_MOVE:
-            return Control::mouseEvent(evt, x, y, 0);
-
-        case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
-            return touchEvent(Touch::TOUCH_RELEASE, x, y, 0);
-
-        case Mouse::MOUSE_WHEEL:
-        {
-            if ((hasFocus() && _state == HOVER) || _state == ACTIVE)
-            {
-                float total = _max - _min;
-                float oldValue = _value;
-                _value += (total * SCROLLWHEEL_FRACTION) * wheelDelta;
-            
-                if (_value > _max)
-                    _value = _max;
-                else if (_value < _min)
-                    _value = _min;
-
-                if (_step > 0.0f)
-                {            
-                    int numSteps = round(_value / _step);
-                    _value = _step * numSteps;
-                }
-
-                if (_value != oldValue)
-                {
-                    notifyListeners(Control::Listener::VALUE_CHANGED);
-                }
-
-                _dirty = true;
-                return true;
-            }
-            break;
-        }
-
-        default:
-            break;
-    }
-
-    return false;
-}
-
-bool Slider::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
-{
-    bool eventConsumed = false;
-
-    if (_state == ACTIVE)
-    {
-        switch (evt)
-        {
-            case Gamepad::BUTTON_EVENT:
-            {
-                if (gamepad->isButtonDown(Gamepad::BUTTON_LEFT))
-                {
-                    _delta = -1.0f;
-                    _directionButtonDown = true;
-                }
-                else if (gamepad->isButtonDown(Gamepad::BUTTON_RIGHT))
-                {
-                    _delta = 1.0f;
-                    _directionButtonDown = true;
-                }
-                else if (_delta != 0.0f && _directionButtonDown)
-                {
-                    _delta = 0.0f;
-                    _directionButtonDown = false;
-                }
-
-                if (_step > 0.0f && _delta != 0.0f)
-                {
-                    _value += _step * _delta;
-                    _gamepadValue = _value - (_step * _delta * 0.49f);
-                    _delta *= 0.2f;
-                }
-
-                // A slider consumes all button events until it is no longer active.
-                eventConsumed = true;
-                _dirty = true;
-                break;
-            }
-            case Gamepad::JOYSTICK_EVENT:
-            {
-                // The left analog stick can be used to change a slider's value.
-                if (analogIndex == 0)
-                {
-                    Vector2 joy;
-                    gamepad->getJoystickValues(analogIndex, &joy);
-                    _gamepadValue = _value;
-                    _delta = joy.x;
-                    _dirty = true;
-                    eventConsumed = true;
-                }
-                break;
-            }
-        }
-    }
-
-    if (evt == Gamepad::BUTTON_EVENT && _delta == 0.0f)
-    {
-        if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
-            gamepad->isButtonDown(Gamepad::BUTTON_X))
-        {
-            _selectButtonDown = true;
-            eventConsumed |= _consumeInputEvents;
-        }
-        else if (_selectButtonDown && 
-                 !gamepad->isButtonDown(Gamepad::BUTTON_A) &&
-                 !gamepad->isButtonDown(Gamepad::BUTTON_X))
-        {
-            _selectButtonDown = false;
-
-            if (hasFocus())
-                setState(ACTIVE);
-            else if (_state == ACTIVE)
-                setState(FOCUS);
-
-            eventConsumed |= _consumeInputEvents;
-        }
-    }    
-
-    return eventConsumed;
-}
-
-bool Slider::keyEvent(Keyboard::KeyEvent evt, int key)
-{
-    if (_state == ACTIVE)
-    {
-        switch (evt)
-        {
-        case Keyboard::KEY_PRESS:
-            switch (key)
-            {
-            case Keyboard::KEY_LEFT_ARROW:
-                _delta = -1.0f;
-                _directionButtonDown = true;
-                _dirty = true;
-                _gamepadValue = _value;
-                return true;
-
-            case Keyboard::KEY_RIGHT_ARROW:
-                _delta = 1.0f;
-                _directionButtonDown = true;
-                _dirty = true;
-                _gamepadValue = _value;
-                return true;
-            }
-            break;
-
-        case Keyboard::KEY_RELEASE:
-            switch (key)
-            {
-            case Keyboard::KEY_LEFT_ARROW:
-                if (_delta == -1.0f)
-                {
-                    _directionButtonDown = false;
-                    _dirty = true;
-                    _delta = 0.0f;
-                    return true;
-                }
-                break;
-
-            case Keyboard::KEY_RIGHT_ARROW:
-                if (_delta == 1.0f)
-                {
-                    _directionButtonDown = false;
-                    _dirty = true;
-                    _delta = 0.0f;
-                    return true;
-                }
-                break;
-            }
-        }
-    }
-
-    if (evt == Keyboard::KEY_PRESS && key == Keyboard::KEY_RETURN)
-    {
-        if (hasFocus())
-            setState(ACTIVE);
-        else if (_state == ACTIVE)
-            setState(FOCUS);
-
-        return _consumeInputEvents;
-    }
-
-    return Control::keyEvent(evt, key);
-}
-
-void Slider::update(const Control* container, const Vector2& offset)
-{
-    Label::update(container, offset);
-
-    _minImage = getImage("minCap", _state);
-    _maxImage = getImage("maxCap", _state);
-    _markerImage = getImage("marker", _state);
-    _trackImage = getImage("track", _state);
-
-    char s[32];
-    sprintf(s, "%.*f", _valueTextPrecision, _value);
-    _valueText = s;
-
-    if (_delta != 0.0f)
-    {
-        float oldValue = _value;
-        float total = _max - _min;
-
-        if (_step > 0.0f)
-        {
-            _gamepadValue += (total * GAMEPAD_FRACTION) * _delta;
-            int numSteps = round(_gamepadValue / _step);
-            _value = _step * numSteps;
-        }
-        else
-        {
-            _value += (total * GAMEPAD_FRACTION) * _delta;
-        }
-
-        if (_value > _max)
-            _value = _max;
-        else if (_value < _min)
-            _value = _min;
-
-        if (_value != oldValue)
-        {
-            notifyListeners(Control::Listener::VALUE_CHANGED);
-        }
-    }
-
-    if (_autoHeight == Control::AUTO_SIZE_FIT)
-    {
-        float height = _minImage->getRegion().height;
-        height = std::max(height, _maxImage->getRegion().height);
-        height = std::max(height, _markerImage->getRegion().height);
-        height = std::max(height, _trackImage->getRegion().height);
-        height += _bounds.height;
-        if (_valueTextVisible && _font)
-            height += getFontSize(_state);
-        setHeight(height);
-    }
-}
-
-void Slider::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
-{
-    if (needsClear)
-    {
-        GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
-        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height, _clearBounds.width, _clearBounds.height) );
-        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
-        GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
-    }
-
-    if (!_visible)
-    {
-        _dirty = false;
-        return;
-    }
-
-    spriteBatch->start();
-    drawBorder(spriteBatch, clip);
-    drawImages(spriteBatch, clip);
-    spriteBatch->finish();
-
-    drawText(clip);
-    if (_delta == 0.0f)
-    {
-        _dirty = false;
-    }
-}
-
-void Slider::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
-{
-    GP_ASSERT(spriteBatch);
-    GP_ASSERT(_minImage);
-    GP_ASSERT(_maxImage);
-    GP_ASSERT(_markerImage);
-    GP_ASSERT(_trackImage);
-
-    // TODO: Vertical slider.
-
-    // The slider is drawn in the center of the control (perpendicular to orientation).
-    // The track is stretched according to orientation.
-    // Caps and marker are not stretched.
-    const Rectangle& minCapRegion = _minImage->getRegion();
-    const Rectangle& maxCapRegion = _maxImage->getRegion();
-    const Rectangle& markerRegion = _markerImage->getRegion();
-    const Rectangle& trackRegion = _trackImage->getRegion();
-
-    const Theme::UVs& minCap = _minImage->getUVs();
-    const Theme::UVs& maxCap = _maxImage->getUVs();
-    const Theme::UVs& marker = _markerImage->getUVs();
-    const Theme::UVs& track = _trackImage->getUVs();
-
-    Vector4 minCapColor = _minImage->getColor();
-    Vector4 maxCapColor = _maxImage->getColor();
-    Vector4 markerColor = _markerImage->getColor();
-    Vector4 trackColor = _trackImage->getColor();
-
-    minCapColor.w *= _opacity;
-    maxCapColor.w *= _opacity;
-    markerColor.w *= _opacity;
-    trackColor.w *= _opacity;
-
-    // Draw order: track, caps, marker.
-    float midY = _viewportBounds.y + (_viewportBounds.height) * 0.5f;
-    Vector2 pos(_viewportBounds.x, midY - trackRegion.height * 0.5f);
-    spriteBatch->draw(pos.x, pos.y, _viewportBounds.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _viewportClipBounds);
-
-    pos.y = midY - minCapRegion.height * 0.5f;
-    pos.x -= minCapRegion.width * 0.5f;
-    spriteBatch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _viewportClipBounds);
-        
-    pos.x = _viewportBounds.x + _viewportBounds.width - maxCapRegion.width * 0.5f;
-    spriteBatch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _viewportClipBounds);
-
-    // Percent across.
-    float markerPosition = (_value - _min) / (_max - _min);
-    markerPosition *= _viewportBounds.width - minCapRegion.width * 0.5f - maxCapRegion.width * 0.5f - markerRegion.width;
-    pos.x = _viewportBounds.x + minCapRegion.width * 0.5f + markerPosition;
-    pos.y = midY - markerRegion.height / 2.0f;
-    spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _viewportClipBounds);
-}
-
-void Slider::drawText(const Rectangle& clip)
-{
-    Label::drawText(clip);
-
-    if (_valueTextVisible && _font)
-    {
-        _font->start();
-        _font->drawText(_valueText.c_str(), _textBounds, _textColor, getFontSize(_state), _valueTextAlignment, true, getTextRightToLeft(_state), &_viewportClipBounds);
-        _font->finish();
-    }
-}
-
-const char* Slider::getType() const
-{
-    return "slider";
-}
-
-}
+#include "Slider.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+// Fraction of slider to scroll when mouse scrollwheel is used.
+static const float SCROLLWHEEL_FRACTION = 0.1f;
+// Fraction of slider to scroll for a delta of 1.0f when a gamepad or keyboard is used.
+static const float MOVE_FRACTION = 0.005f;
+// Distance that a slider must be moved before it starts consuming input events,
+// e.g. to prevent its parent container from scrolling at the same time.
+static const float SLIDER_THRESHOLD = 5.0f;
+
+Slider::Slider() : _min(0.0f), _max(0.0f), _step(0.0f), _value(0.0f), _delta(0.0f), _minImage(NULL),
+    _maxImage(NULL), _trackImage(NULL), _markerImage(NULL), _valueTextVisible(false),
+    _valueTextAlignment(Font::ALIGN_BOTTOM_HCENTER), _valueTextPrecision(0), _valueText(""),
+    _selectButtonDown(false), _directionButtonDown(false), _gamepadValue(0.0f)
+{
+    _canFocus = true;
+}
+
+Slider::~Slider()
+{
+}
+
+Slider* Slider::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    Slider* slider = new Slider();
+    if (id)
+        slider->_id = id;
+    slider->setStyle(style);
+
+    return slider;
+}
+
+Control* Slider::create(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Slider* slider = new Slider();
+    slider->initialize(style, properties);
+
+    slider->_min = properties->getFloat("min");
+    slider->_max = properties->getFloat("max");
+    slider->_value = properties->getFloat("value");
+    slider->_step = properties->getFloat("step");
+    slider->_valueTextVisible = properties->getBool("valueTextVisible");
+    slider->_valueTextPrecision = properties->getInt("valueTextPrecision");
+
+    if (properties->exists("valueTextAlignment"))
+    {
+        slider->_valueTextAlignment = Font::getJustify(properties->getString("valueTextAlignment"));
+    }
+
+    return slider;
+}
+
+void Slider::setMin(float min)
+{
+    if (_min != _min)
+    {
+        _dirty = true;
+    }
+    _min = min;
+}
+
+float Slider::getMin() const
+{
+    return _min;
+}
+
+void Slider::setMax(float max)
+{
+    if (max != _max)
+    {
+        _dirty = true;
+    }
+    _max = max;
+}
+
+float Slider::getMax() const
+{
+    return _max;
+}
+
+void Slider::setStep(float step)
+{
+    _step = step;
+}
+
+float Slider::getStep() const
+{
+    return _step;
+}
+
+float Slider::getValue() const
+{
+    return _value;
+}
+
+void Slider::setValue(float value)
+{
+    float oldValue = _value;
+    _value = MATH_CLAMP(value, _min, _max);
+    if (_value != value)
+    {
+        _dirty = true;
+    }
+}
+
+void Slider::setValueTextVisible(bool valueTextVisible)
+{
+    if (valueTextVisible != _valueTextVisible)
+    {
+        _dirty = true;
+    }
+    _valueTextVisible = valueTextVisible;
+}
+
+bool Slider::isValueTextVisible() const
+{
+    return _valueTextVisible;
+}
+
+void Slider::setValueTextAlignment(Font::Justify alignment)
+{
+    if (alignment != _valueTextAlignment)
+    {
+        _dirty = true;
+    }
+    _valueTextAlignment = alignment;
+}
+
+Font::Justify Slider::getValueTextAlignment() const
+{
+    return _valueTextAlignment;
+}
+
+void Slider::setValueTextPrecision(unsigned int precision)
+{
+    if (precision != _valueTextPrecision)
+    {
+        _dirty = true;
+    }
+    _valueTextPrecision = precision;
+}
+
+unsigned int Slider::getValueTextPrecision() const
+{
+    return _valueTextPrecision;
+}
+
+void Slider::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Control::Listener::TEXT_CHANGED) == Control::Listener::TEXT_CHANGED)
+    {
+        GP_ERROR("TEXT_CHANGED event is not applicable to Slider.");
+    }
+
+    Control::addListener(listener, eventFlags);
+}
+
+void Slider::updateValue(int x, int y)
+{
+    State state = getState();
+
+    // If the point lies within this slider, update the value of the slider accordingly
+    if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
+        y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
+    {
+        // Horizontal case.
+        const Theme::Border& border = getBorder(state);
+        const Theme::Padding& padding = getPadding();
+        const Rectangle& minCapRegion = _minImage->getRegion();
+        const Rectangle& maxCapRegion = _maxImage->getRegion();
+
+        float markerPosition = ((float)x - maxCapRegion.width - border.left - padding.left) /
+            (_bounds.width - border.left - border.right - padding.left - padding.right - minCapRegion.width - maxCapRegion.width);
+            
+        if (markerPosition > 1.0f)
+        {
+            markerPosition = 1.0f;
+        }
+        else if (markerPosition < 0.0f)
+        {
+            markerPosition = 0.0f;
+        }
+
+        float oldValue = _value;
+        _value = (markerPosition * (_max - _min)) + _min;
+        if (_step > 0.0f)
+        {            
+            int numSteps = round(_value / _step);
+            _value = _step * numSteps;
+        }
+
+        // Call the callback if our value changed.
+        if (_value != oldValue)
+        {
+            notifyListeners(Control::Listener::VALUE_CHANGED);
+        }
+        _dirty = true;
+    }
+}
+
+bool Slider::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    State state = getState();
+
+    switch (evt)
+    {
+    case Touch::TOUCH_PRESS:
+        updateValue(x, y);
+        return true;
+
+    case Touch::TOUCH_MOVE:
+        if (state == ACTIVE)
+        {
+            updateValue(x, y);
+            return true;
+        }
+        break;
+    }
+
+    return Control::touchEvent(evt, x, y, contactIndex);
+}
+
+bool Slider::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
+{
+    switch (evt)
+    {
+        case Mouse::MOUSE_WHEEL:
+        {
+            if (hasFocus())
+            {
+                float total = _max - _min;
+                float oldValue = _value;
+                _value += (total * SCROLLWHEEL_FRACTION) * wheelDelta;
+            
+                if (_value > _max)
+                    _value = _max;
+                else if (_value < _min)
+                    _value = _min;
+
+                if (_step > 0.0f)
+                {            
+                    int numSteps = round(_value / _step);
+                    _value = _step * numSteps;
+                }
+
+                if (_value != oldValue)
+                {
+                    notifyListeners(Control::Listener::VALUE_CHANGED);
+                }
+
+                _dirty = true;
+                return true;
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    // Return false to fall through to touch handling
+    return false;
+}
+
+bool Slider::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
+{
+    bool eventConsumed = false;
+
+    switch (evt)
+    {
+        case Gamepad::JOYSTICK_EVENT:
+        {
+            // The right analog stick can be used to change a slider's value.
+            if (analogIndex == 1)
+            {
+                Vector2 joy;
+                gamepad->getJoystickValues(analogIndex, &joy);
+                _gamepadValue = _value;
+                _delta = joy.x;
+                _dirty = true;
+                return true;
+            }
+            break;
+        }
+    }
+
+    return Label::gamepadEvent(evt, gamepad, analogIndex);
+}
+
+bool Slider::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+    switch (evt)
+    {
+    case Keyboard::KEY_PRESS:
+        switch (key)
+        {
+        case Keyboard::KEY_LEFT_ARROW:
+            if (_step > 0.0f)
+            {
+                _value = std::max(_value - _step, _min);
+            }
+            else
+            {
+                _value = std::max(_value - (_max - _min) * MOVE_FRACTION, _min);
+            }
+            _dirty = true;
+            return true;
+
+        case Keyboard::KEY_RIGHT_ARROW:
+            if (_step > 0.0f)
+            {
+                _value = std::min(_value + _step, _max);
+            }
+            else
+            {
+                _value = std::min(_value + (_max - _min) * MOVE_FRACTION, _max);
+            }
+            _dirty = true;
+            return true;
+        }
+        break;
+    }
+
+    return Control::keyEvent(evt, key);
+}
+
+void Slider::update(const Control* container, const Vector2& offset)
+{
+    Label::update(container, offset);
+
+    Control::State state = getState();
+
+    _minImage = getImage("minCap", state);
+    _maxImage = getImage("maxCap", state);
+    _markerImage = getImage("marker", state);
+    _trackImage = getImage("track", state);
+
+    char s[32];
+    sprintf(s, "%.*f", _valueTextPrecision, _value);
+    _valueText = s;
+
+    if (_delta != 0.0f)
+    {
+        float oldValue = _value;
+        float total = _max - _min;
+
+        if (_step > 0.0f)
+        {
+            _gamepadValue += (total * MOVE_FRACTION) * _delta;
+            int numSteps = round(_gamepadValue / _step);
+            _value = _step * numSteps;
+        }
+        else
+        {
+            _value += (total * MOVE_FRACTION) * _delta;
+        }
+
+        if (_value > _max)
+            _value = _max;
+        else if (_value < _min)
+            _value = _min;
+
+        if (_value != oldValue)
+        {
+            notifyListeners(Control::Listener::VALUE_CHANGED);
+        }
+    }
+
+    if (_autoHeight == Control::AUTO_SIZE_FIT)
+    {
+        float height = _minImage->getRegion().height;
+        height = std::max(height, _maxImage->getRegion().height);
+        height = std::max(height, _markerImage->getRegion().height);
+        height = std::max(height, _trackImage->getRegion().height);
+        height += _bounds.height;
+        if (_valueTextVisible && _font)
+            height += getFontSize(state);
+        setHeight(height);
+    }
+}
+
+void Slider::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
+{
+    if (needsClear)
+    {
+        GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
+        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height, _clearBounds.width, _clearBounds.height) );
+        Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
+        GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
+    }
+
+    if (!_visible)
+    {
+        _dirty = false;
+        return;
+    }
+
+    spriteBatch->start();
+    drawBorder(spriteBatch, clip);
+    drawImages(spriteBatch, clip);
+    spriteBatch->finish();
+
+    drawText(clip);
+    if (_delta == 0.0f)
+    {
+        _dirty = false;
+    }
+}
+
+void Slider::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    GP_ASSERT(spriteBatch);
+    GP_ASSERT(_minImage);
+    GP_ASSERT(_maxImage);
+    GP_ASSERT(_markerImage);
+    GP_ASSERT(_trackImage);
+
+    // TODO: Vertical slider.
+
+    // The slider is drawn in the center of the control (perpendicular to orientation).
+    // The track is stretched according to orientation.
+    // Caps and marker are not stretched.
+    const Rectangle& minCapRegion = _minImage->getRegion();
+    const Rectangle& maxCapRegion = _maxImage->getRegion();
+    const Rectangle& markerRegion = _markerImage->getRegion();
+    const Rectangle& trackRegion = _trackImage->getRegion();
+
+    const Theme::UVs& minCap = _minImage->getUVs();
+    const Theme::UVs& maxCap = _maxImage->getUVs();
+    const Theme::UVs& marker = _markerImage->getUVs();
+    const Theme::UVs& track = _trackImage->getUVs();
+
+    Vector4 minCapColor = _minImage->getColor();
+    Vector4 maxCapColor = _maxImage->getColor();
+    Vector4 markerColor = _markerImage->getColor();
+    Vector4 trackColor = _trackImage->getColor();
+
+    minCapColor.w *= _opacity;
+    maxCapColor.w *= _opacity;
+    markerColor.w *= _opacity;
+    trackColor.w *= _opacity;
+
+    // Draw order: track, caps, marker.
+    float midY = _viewportBounds.y + (_viewportBounds.height) * 0.5f;
+    Vector2 pos(_viewportBounds.x, midY - trackRegion.height * 0.5f);
+    spriteBatch->draw(pos.x, pos.y, _viewportBounds.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _viewportClipBounds);
+
+    pos.y = midY - minCapRegion.height * 0.5f;
+    pos.x -= minCapRegion.width * 0.5f;
+    spriteBatch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _viewportClipBounds);
+
+    pos.x = _viewportBounds.x + _viewportBounds.width - maxCapRegion.width * 0.5f;
+    spriteBatch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _viewportClipBounds);
+
+    // Percent across.
+    float markerPosition = (_value - _min) / (_max - _min);
+    markerPosition *= _viewportBounds.width - minCapRegion.width * 0.5f - maxCapRegion.width * 0.5f - markerRegion.width;
+    pos.x = _viewportBounds.x + minCapRegion.width * 0.5f + markerPosition;
+    pos.y = midY - markerRegion.height / 2.0f;
+    spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _viewportClipBounds);
+}
+
+void Slider::drawText(const Rectangle& clip)
+{
+    Label::drawText(clip);
+
+    if (_valueTextVisible && _font)
+    {
+        Control::State state = getState();
+        _font->start();
+        _font->drawText(_valueText.c_str(), _textBounds, _textColor, getFontSize(state), _valueTextAlignment, true, getTextRightToLeft(state), &_viewportClipBounds);
+        _font->finish();
+    }
+}
+
+const char* Slider::getType() const
+{
+    return "slider";
+}
+
+}

+ 368 - 366
gameplay/src/Slider.h

@@ -1,366 +1,368 @@
-#ifndef SLIDER_H_
-#define SLIDER_H_
-
-#include "Base.h"
-#include "Theme.h"
-#include "Properties.h"
-#include "Button.h"
-#include "Touch.h"
-
-namespace gameplay
-{
-
-/**
- * A slider consists of a marker that can slide along a track between two end-caps.
- * The following properties are available for sliders:
-
- @verbatim
-    slider
-    {
-        style       = <styleID>                 // A Style from the Theme.
-        position    = <x, y>                    // Position of the Control on-screen, measured in pixels.
-        size        = <width, height>           // Size of the Control, measured in pixels.
-        min         = <float>                   // The value of the left- / bottom-most point on the slider.
-        max         = <float>                   // The value of the right- / top-most point on the slider.
-        value       = <float>                   // The default position of the marker.
-        step        = <float>                   // If greater than 0, force the marker to snap to discrete multiples of 'step'.
-        text        = <string>                  // Text to display above, below or alongside the slider (depending on the style).
-        consumeEvents = <bool>                  // Whether the slider propagates input events to the Game's input event handler. Default is true.
-        // TODO: orientation = <HORIZONTAL or VERTICAL>  // Determines whether a slider is stretched along its width or its height
-    }
- @endverbatim
- */
-class Slider : public Label
-{
-    friend class Container;
-	friend class ControlFactory;
-
-public:
-
-    /**
-     * Create a new slider control.
-     *
-     * @param id The control's ID.
-     * @param style The control's style.
-     *
-     * @return The new slider.
-     * @script{create}
-     */
-    static Slider* create(const char* id, Theme::Style* style);
-
-    /**
-     * Set the minimum value that can be set on this slider.
-     *
-     * @param min The new minimum.
-     */
-    void setMin(float min);
-
-    /**
-     * Get the minimum value that can be set on this slider.
-     *
-     * @return The minimum value that can be set on this slider.
-     */
-    float getMin() const;
-
-    /**
-     * Set the maximum value that can be set on this slider.
-     *
-     * @param max The new maximum.
-     */
-    void setMax(float max);
-
-    /**
-     * Get the maximum value that can be set on this slider.
-     *
-     * @return The maximum value that can be set on this slider.
-     */
-    float getMax() const;
-
-    /**
-     * Set this slider's step size.  If this is greater than zero, the marker
-     * will snap to discrete multiples of the step size.
-     *
-     * @param step The new step size.
-     */
-    void setStep(float step);
-
-    /**
-     * Get this slider's step size.
-     *
-     * @return This slider's step size.
-     */
-    float getStep() const;
-
-    /**
-     * Set this slider's value.  The new value will be clamped to fit within
-     * the slider's minimum and maximum values.
-     *
-     * @param value The new value.
-     */
-    void setValue(float value);
-
-    /**
-     * Get this slider's current value.
-     *
-     * @return This slider's current value.
-     */
-    float getValue() const;
-
-    /**
-     * @see Control::getType
-     */
-    const char* getType() const;
-
-    /**
-     * Sets if the slider value text is rendered below the control.
-     * 
-     * @param visible If the slider value text is rendered below the control. 
-     */
-    void setValueTextVisible(bool visible);
-
-    /**
-     * Gets if the slider value text is rendered below the control.
-     *
-     * @return true if the slider value text is rendered below the control, false if otherwise.
-     */
-    bool isValueTextVisible() const;
-
-    /**
-     * Sets the slider value text alignment.
-     * 
-     * @param alignment the slider value text alignment. 
-     */
-    void setValueTextAlignment(Font::Justify alignment);
-
-    /**
-     * Gets the slider value text alignment.
-     *
-     * @return The slider value text alignment. 
-     */
-    Font::Justify getValueTextAlignment() const;
-
-    /**
-     * Sets the precision, which is the number floating point digits after the decimal.
-     *
-     * @param precision The number floating point precision/digits after the decimal.
-     */
-    void setValueTextPrecision(unsigned int precision);
-
-    /**
-     * Gets the precision, which is the number floating point digits after the decimal.
-     *
-     * @return The number floating point precision/digits after the decimal.
-     */
-    unsigned int getValueTextPrecision() const;
-
-    /**
-     * Add a listener to be notified of specific events affecting
-     * this control.  Event types can be OR'ed together.
-     * E.g. To listen to touch-press and touch-release events,
-     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
-     * as the second parameter.
-     *
-     * @param listener The listener to add.
-     * @param eventFlags The events to listen for.
-     */
-    void addListener(Control::Listener* listener, int eventFlags);
-
-protected:
-
-    /**
-     * Constructor.
-     */
-    Slider();
-
-    /**
-     * Destructor.
-     */
-    ~Slider();
-
-    /**
-     * Create a slider with a given style and properties.
-     *
-     * @param style The style to apply to this slider.
-     * @param properties The properties to set on this slider.
-     * @param theme The theme to set on this control if needed
-	 *
-     * @return The new slider.
-     */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
-
-    /**
-     * Touch callback on touch events.  Controls return true if they consume the touch event.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by the control.
-     *
-     * @see Touch::TouchEvent
-     */
-    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-
-    /**
-     * Mouse callback on mouse events.
-     *
-     * @param evt The mouse event that occurred.
-     * @param x The x position of the mouse in pixels. Left edge is zero.
-     * @param y The y position of the mouse in pixels. Top edge is zero.
-     * @param wheelDelta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
-     *
-     * @return True if the mouse event is consumed or false if it is not consumed.
-     *
-     * @see Mouse::MouseEvent
-     */
-    bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
-
-    /**
-     * Gamepad callback on gamepad events.
-     *
-     * @see Control::gamepadEvent
-     */
-    bool gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
-
-    /**
-     * Keyboard callback on key events.
-     *
-     * @see Keyboard::KeyEvent
-     * @see Keyboard::Key
-     */
-    bool keyEvent(Keyboard::KeyEvent evt, int key);
-
-    /**
-     * Slider overrides draw() so that it can avoid resetting the _dirty flag
-     * when a joystick is being used to change its value.
-     */
-    void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight);
-
-    /**
-     * Draw the images associated with this control.
-     *
-     * @param spriteBatch The sprite batch containing this control's icons.
-     * @param clip The clipping rectangle of this control's parent container.
-     */
-    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-    /**
-     * Draw this slider's text.
-     *
-     * @param clip The clipping rectangle of this slider's parent container.
-     */
-    void drawText(const Rectangle& clip);
-
-    /**
-     * Called when a slider's properties change. Updates this slider's internal rendering
-     * properties, such as its text viewport.
-     *
-     * @param container This slider's parent container.
-     * @param offset The scroll offset of this slider's parent container.
-     */
-    void update(const Control* container, const Vector2& offset);
-
-    /**
-     * The minimum value for the Slider.
-     */
-    float _min;
-    
-    /**
-     * The maximum value for the Slider
-     */
-    float _max;
-    
-    /**
-     * The Slider's step size.
-     */
-    float _step;
-    
-    /**
-     * The Slider's current value.
-     */
-    float _value;
-
-    /**
-     * When a gamepad is in use, this stores how much to move the slider's value.
-     */
-    float _delta;
-
-    /**
-     * The X coordinate of the first touch event in a sequence.
-     */
-    float _originalX;
-
-    /**
-     * The Slider's original value at the start of a sequence of touch events.
-     */
-    float _originalValue;
-
-    /**
-     * The Slider's original setting of _consumeInputEvents at the start of a sequence of touch events.
-     */
-    bool _originalConsumeInputEvents;
-
-    /**
-     * Whether the Slider's current movement has been cancelled, e.g. because the user is scrolling the parent container.
-     */
-    bool _moveCancelled;
-
-    /**
-     * The image for the minimum slider value.
-     */
-    Theme::ThemeImage* _minImage;
-    
-    /**
-     * The image for the maximum slider value.
-     */
-    Theme::ThemeImage* _maxImage;
-    
-    /**
-     * The image for the slider track.
-     */
-    Theme::ThemeImage* _trackImage;
-    
-    /**
-     * The image for the slider marker.
-     */
-    Theme::ThemeImage* _markerImage;
-
-    /**
-     * Whether to display this slider's value.
-     */
-    bool _valueTextVisible;
-
-    /**
-     * Alignment of value text.
-     */
-    Font::Justify _valueTextAlignment;
-
-    /**
-     * Number of digits after the decimal to draw for value text.
-     */
-    unsigned int _valueTextPrecision;
-
-    /**
-     * The text displayed by this slider if set to display its value.
-     */
-    std::string _valueText;
-
-    // Used by gamepads to toggle Slider state between FOCUS and ACTIVE.
-    bool _selectButtonDown;
-
-    bool _directionButtonDown;
-
-    float _gamepadValue;
-
-private:
-
-    /**
-     * Constructor.
-     */
-    Slider(const Slider& copy);
-};
-
-}
-
-#endif
+#ifndef SLIDER_H_
+#define SLIDER_H_
+
+#include "Base.h"
+#include "Theme.h"
+#include "Properties.h"
+#include "Button.h"
+#include "Touch.h"
+
+namespace gameplay
+{
+
+/**
+ * A slider consists of a marker that can slide along a track between two end-caps.
+ * The following properties are available for sliders:
+
+ @verbatim
+    slider
+    {
+        style       = <styleID>                 // A Style from the Theme.
+        position    = <x, y>                    // Position of the Control on-screen, measured in pixels.
+        size        = <width, height>           // Size of the Control, measured in pixels.
+        min         = <float>                   // The value of the left- / bottom-most point on the slider.
+        max         = <float>                   // The value of the right- / top-most point on the slider.
+        value       = <float>                   // The default position of the marker.
+        step        = <float>                   // If greater than 0, force the marker to snap to discrete multiples of 'step'.
+        text        = <string>                  // Text to display above, below or alongside the slider (depending on the style).
+        consumeEvents = <bool>                  // Whether the slider propagates input events to the Game's input event handler. Default is true.
+        // TODO: orientation = <HORIZONTAL or VERTICAL>  // Determines whether a slider is stretched along its width or its height
+    }
+ @endverbatim
+ */
+class Slider : public Label
+{
+    friend class Container;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Create a new slider control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new slider.
+     * @script{create}
+     */
+    static Slider* create(const char* id, Theme::Style* style);
+
+    /**
+     * Set the minimum value that can be set on this slider.
+     *
+     * @param min The new minimum.
+     */
+    void setMin(float min);
+
+    /**
+     * Get the minimum value that can be set on this slider.
+     *
+     * @return The minimum value that can be set on this slider.
+     */
+    float getMin() const;
+
+    /**
+     * Set the maximum value that can be set on this slider.
+     *
+     * @param max The new maximum.
+     */
+    void setMax(float max);
+
+    /**
+     * Get the maximum value that can be set on this slider.
+     *
+     * @return The maximum value that can be set on this slider.
+     */
+    float getMax() const;
+
+    /**
+     * Set this slider's step size.  If this is greater than zero, the marker
+     * will snap to discrete multiples of the step size.
+     *
+     * @param step The new step size.
+     */
+    void setStep(float step);
+
+    /**
+     * Get this slider's step size.
+     *
+     * @return This slider's step size.
+     */
+    float getStep() const;
+
+    /**
+     * Set this slider's value.  The new value will be clamped to fit within
+     * the slider's minimum and maximum values.
+     *
+     * @param value The new value.
+     */
+    void setValue(float value);
+
+    /**
+     * Get this slider's current value.
+     *
+     * @return This slider's current value.
+     */
+    float getValue() const;
+
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
+    /**
+     * Sets if the slider value text is rendered below the control.
+     * 
+     * @param visible If the slider value text is rendered below the control. 
+     */
+    void setValueTextVisible(bool visible);
+
+    /**
+     * Gets if the slider value text is rendered below the control.
+     *
+     * @return true if the slider value text is rendered below the control, false if otherwise.
+     */
+    bool isValueTextVisible() const;
+
+    /**
+     * Sets the slider value text alignment.
+     * 
+     * @param alignment the slider value text alignment. 
+     */
+    void setValueTextAlignment(Font::Justify alignment);
+
+    /**
+     * Gets the slider value text alignment.
+     *
+     * @return The slider value text alignment. 
+     */
+    Font::Justify getValueTextAlignment() const;
+
+    /**
+     * Sets the precision, which is the number floating point digits after the decimal.
+     *
+     * @param precision The number floating point precision/digits after the decimal.
+     */
+    void setValueTextPrecision(unsigned int precision);
+
+    /**
+     * Gets the precision, which is the number floating point digits after the decimal.
+     *
+     * @return The number floating point precision/digits after the decimal.
+     */
+    unsigned int getValueTextPrecision() const;
+
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
+    void addListener(Control::Listener* listener, int eventFlags);
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    Slider();
+
+    /**
+     * Destructor.
+     */
+    ~Slider();
+
+    /**
+     * Create a slider with a given style and properties.
+     *
+     * @param style The style to apply to this slider.
+     * @param properties The properties to set on this slider.
+     *
+     * @return The new slider.
+     */
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
+    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
+
+    /**
+     * Mouse callback on mouse events.
+     *
+     * @param evt The mouse event that occurred.
+     * @param x The x position of the mouse in pixels. Left edge is zero.
+     * @param y The y position of the mouse in pixels. Top edge is zero.
+     * @param wheelDelta The number of mouse wheel ticks. Positive is up (forward), negative is down (backward).
+     *
+     * @return True if the mouse event is consumed or false if it is not consumed.
+     *
+     * @see Mouse::MouseEvent
+     */
+    bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
+
+    /**
+     * Gamepad callback on gamepad events.
+     *
+     * @see Control::gamepadEvent
+     */
+    bool gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex);
+
+    /**
+     * Keyboard callback on key events.
+     *
+     * @see Keyboard::KeyEvent
+     * @see Keyboard::Key
+     */
+    bool keyEvent(Keyboard::KeyEvent evt, int key);
+
+    /**
+     * Slider overrides draw() so that it can avoid resetting the _dirty flag
+     * when a joystick is being used to change its value.
+     */
+    void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight);
+
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
+    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    /**
+     * Draw this slider's text.
+     *
+     * @param clip The clipping rectangle of this slider's parent container.
+     */
+    void drawText(const Rectangle& clip);
+
+    /**
+     * Called when a slider's properties change. Updates this slider's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param container This slider's parent container.
+     * @param offset The scroll offset of this slider's parent container.
+     */
+    void update(const Control* container, const Vector2& offset);
+
+    /**
+     * The minimum value for the Slider.
+     */
+    float _min;
+    
+    /**
+     * The maximum value for the Slider
+     */
+    float _max;
+    
+    /**
+     * The Slider's step size.
+     */
+    float _step;
+    
+    /**
+     * The Slider's current value.
+     */
+    float _value;
+
+    /**
+     * When a gamepad is in use, this stores how much to move the slider's value.
+     */
+    float _delta;
+
+    /**
+     * The X coordinate of the first touch event in a sequence.
+     */
+    float _originalX;
+
+    /**
+     * The Slider's original value at the start of a sequence of touch events.
+     */
+    float _originalValue;
+
+    /**
+     * The Slider's original setting of _consumeInputEvents at the start of a sequence of touch events.
+     */
+    bool _originalConsumeInputEvents;
+
+    /**
+     * Whether the Slider's current movement has been cancelled, e.g. because the user is scrolling the parent container.
+     */
+    bool _moveCancelled;
+
+    /**
+     * The image for the minimum slider value.
+     */
+    Theme::ThemeImage* _minImage;
+    
+    /**
+     * The image for the maximum slider value.
+     */
+    Theme::ThemeImage* _maxImage;
+    
+    /**
+     * The image for the slider track.
+     */
+    Theme::ThemeImage* _trackImage;
+    
+    /**
+     * The image for the slider marker.
+     */
+    Theme::ThemeImage* _markerImage;
+
+    /**
+     * Whether to display this slider's value.
+     */
+    bool _valueTextVisible;
+
+    /**
+     * Alignment of value text.
+     */
+    Font::Justify _valueTextAlignment;
+
+    /**
+     * Number of digits after the decimal to draw for value text.
+     */
+    unsigned int _valueTextPrecision;
+
+    /**
+     * The text displayed by this slider if set to display its value.
+     */
+    std::string _valueText;
+
+    // Used by gamepads to toggle Slider state between FOCUS and ACTIVE.
+    bool _selectButtonDown;
+
+    bool _directionButtonDown;
+
+    float _gamepadValue;
+
+private:
+
+    /**
+     * Constructor.
+     */
+    Slider(const Slider& copy);
+
+    void updateValue(int x, int y);
+
+};
+
+}
+
+#endif

+ 0 - 18
gameplay/src/SocialAchievement.cpp

@@ -1,18 +0,0 @@
-#include "Base.h"
-#include "SocialAchievement.h"
-
-namespace gameplay
-{
-
-SocialAchievement::SocialAchievement()
-    : value(0), total(0), percentCompleted(0.0f)
-{
-}
-
-SocialAchievement::~SocialAchievement()
-{
-}
-
-}
-
-

+ 0 - 65
gameplay/src/SocialAchievement.h

@@ -1,65 +0,0 @@
-#ifndef SOCIALACHIEVEMENT_H_
-#define SOCIALACHIEVEMENT_H_
-
-namespace gameplay
-{
-
-/**
- * Defines a social achievement in a game.
- *
- * @script{ignore}
- */
-class SocialAchievement
-{
-
-public:
-
-    /**
-     * The name of the achievement.
-     */
-    std::string name;
-
-    /**
-     * The title of the achievement.
-     */
-    std::string title;
-
-    /**
-     * The value of progress (0 to getTotal) representing the current unit value of completion.
-     */
-    unsigned int value;
-
-    /**
-     * The total value of progress needed to complete the achievement.
-     */
-    unsigned int total;
-
-    /**
-     * The percent that the achievement is complete. Equivalent to getValue() / getTotal() * 100.0f
-     */
-    float percentCompleted;
-
-    /**
-     * The date/time the achievement was achieved. (UTC string format "2013-06-27T07:40::05")
-     */
-    std::string dateTimeAchieved;
-
-    /**
-     * The provider handle for an achievement.
-     */
-    SocialAchievementHandle handle;
-
-    /**
-     * Constructor.
-     */
-    SocialAchievement();
-
-    /**
-     * Destructor.
-     */
-    ~SocialAchievement();
-};
-
-}
-
-#endif

+ 0 - 16
gameplay/src/SocialChallenge.cpp

@@ -1,16 +0,0 @@
-#include "Base.h"
-#include "SocialChallenge.h"
-
-namespace gameplay
-{
-
-SocialChallenge::SocialChallenge()
-    : state(INVALID), score(0.0f)
-{
-}
-
-SocialChallenge::~SocialChallenge()
-{
-}
-
-}

+ 0 - 86
gameplay/src/SocialChallenge.h

@@ -1,86 +0,0 @@
-#ifndef SOCIALCHALLENGE_H_
-#define SOCIALCHALLENGE_H_
-
-namespace gameplay
-{
-
-/**
- * Defines a social challenge between social players.
- *
- * @script{ignore}
- */
-class SocialChallenge
-{
-
-public:
-
-	/**
-	 * The challenge state.
-	 */
-    enum State
-    {
-        PENDING,
-        COMPLETE,
-        DECLINED,
-        INVALID
-    };
-
-    /**
-     * The name of the challenge.
-     */
-    std::string name;
-
-    /**
-     * The title of the challenge.
-     */
-    std::string title;
-
-    /**
-     * The name of the player issuing the challenge.
-     */
-    std::string issuedPlayerName;
-
-    /**
-     * The name of the player being challenged.
-     */
-    std::string challengedPlayerName;
-
-    /**
-     * The state of the challenge.
-     */
-    State state;
-
-    /**
-     * The score for the challenge.
-     */
-    float score;
-
-    /**
-     * The date/time the challenge was issued. (UTC string format "2013-06-27T07:40::05")
-     */
-    std::string dateTimeIssued;
-
-    /**
-     * The date/time the challenge was completed. (UTC string format "2013-06-27T07:40::05")
-     */
-    std::string dateTimeCompleted;
-
-    /**
-     * The provider handle for an challenge.
-     */
-    SocialChallengeHandle handle;
-
-    /**
-     * Constructor.
-     */
-    SocialChallenge();
-
-    /**
-     * Destructor.
-     */
-    ~SocialChallenge();
-};
-
-}
-
-#endif

+ 0 - 92
gameplay/src/SocialController.cpp

@@ -1,92 +0,0 @@
-#include "Base.h"
-#include "SocialController.h"
-#include "Game.h"
-#include "social/ScoreloopSocialSession.h"
-#include "social/GooglePlaySocialSession.h"
-
-namespace gameplay
-{
-
-SocialController::SocialController()
-    : _session(NULL)
-{
-}
-
-SocialController::~SocialController()
-{
-}
-
-void SocialController::initialize()
-{
-}
-
-void SocialController::finalize()
-{
-	if (_session)
-		_session->synchronizeAchievements();
-}
-
-void SocialController::pause()
-{
-	if (_session)
-		_session->synchronizeAchievements();
-}
-
-void SocialController::resume()
-{
-}
-
-void SocialController::update(float elapsedTime)
-{
-}
-
-bool SocialController::handleEvent(void *event)
-{
-	if (_session)
-		return _session->handleEvent(event);
-
-	return false;
-}
-
-void SocialController::authenticate(SocialSessionListener* listener)
-{
-#ifdef GP_USE_SOCIAL
-#if defined(__QNX__)
-    Properties* socialProperties = Game::getInstance()->getConfig()->getNamespace("social", true);
-    const char* providerStr = "";
-
-    if (socialProperties)
-    {
-    	providerStr = socialProperties->getString("provider");
-    }
-
-    if (strcmp(providerStr, "Scoreloop") == 0)
-    {
-        _session = ScoreloopSocialSession::authenticate(listener, socialProperties);
-    }
-    else
-    {
-        listener->authenticateEvent(SocialSessionListener::ERROR_INITIALIZATION, NULL);
-    }
-#elif defined(__ANDROID__)
-    Properties* socialProperties = Game::getInstance()->getConfig()->getNamespace("social", true);
-    const char* providerStr = "";
-
-    if (socialProperties)
-    {
-    	providerStr = socialProperties->getString("provider");
-    }
-
-    if (strcmp(providerStr, "GooglePlay") == 0)
-    {
-        _session = GooglePlaySocialSession::authenticate(listener, socialProperties);
-    }
-    else
-    {
-        listener->authenticateEvent(SocialSessionListener::ERROR_INITIALIZATION, NULL);
-    }
-#endif
-#endif
-}
-
-}

+ 0 - 102
gameplay/src/SocialController.h

@@ -1,102 +0,0 @@
-#ifndef SOCIALCONTROLLER_H_
-#define SOCIALCONTROLLER_H_
-
-#include "Properties.h"
-#include "SocialSession.h"
-#include "SocialSessionListener.h"
-
-namespace gameplay
-{
-
-/**
- * Defines a class for controlling various back-end support for social capabilities.
- *
- * Back-end social providers include Friends, Leaderboards, Achievements and Multiplayer.
- * Social back-ends supported are Scoreloop, GameCenter and Google Play Game Services and Facebook.
- * Configuration for these are specified in game.config:
-
-  @verbatim
-    social
-    {
-         provider = Scoreloop | GooglePlay
-         id  = d346c484-12aa-49a2-a0a0-de2f87492d72
-         secret = aAa+DehBfyGO/CYaE3nWomgu7SIbWFczUih+Qwf3/n7u0y3nyq5Hag==
-         version = 1.0
-         language = en
-         currency = ASC
-         leaderboard_mappings
-         {
-             // Format: leaderboardId = provider value
-             easy = 0
-             medium = 1
-             hard = 2
-         }
-    }
- *
- * @script{ignore}
- */
-class SocialController
-{
-    friend class Game;
-
-public:
-
-    /**
-     * Asyncrhonously authenticates a new user session.
-     *
-     * @param listener The listener
-     */
-    void authenticate(SocialSessionListener* listener);
-
-    /**
-     * Handle the event from the event loop if needed.
-     */
-    bool handleEvent(void *event);
-
-private:
-
-    /**
-     * Constructor.
-     */
-    SocialController();
-
-    /**
-     * Destructor.
-     */
-    ~SocialController();
-
-    /**
-     * Callback for when the controller is initialized.
-     */
-    void initialize();
-
-    /*
-     * Callback for when the controller is finalized.
-     */
-    void finalize();
-
-    /**
-     * Pauses the controller.
-     */
-    void pause();
-
-    /**
-     * Resumes the controller.
-     */
-    void resume();
-
-    /**
-     * Callback for when the controller receives a frame update event.
-     */
-    void update(float elapsedTime);
-
-private:
-
-    SocialSession* _session;
-
-};
-
-}
-
-#endif
-

+ 0 - 17
gameplay/src/SocialPlayer.cpp

@@ -1,17 +0,0 @@
-#include "Base.h"
-#include "SocialPlayer.h"
-
-namespace gameplay
-{
-
-SocialPlayer::SocialPlayer()
-{
-}
-
-SocialPlayer::~SocialPlayer()
-{
-}
-
-}
-
-

+ 0 - 42
gameplay/src/SocialPlayer.h

@@ -1,42 +0,0 @@
-#ifndef SOCIALPLAYER_H_
-#define SOCIALPLAYER_H_
-
-namespace gameplay
-{
-
-/**
- * Defines a social player.
- *
- * This can either be the authenticated user, friend or community user (not friend yet...).
- *
- * @script{ignore}
- */
-class SocialPlayer
-{
-
-public:
-
-    /**
-     * The players friendly name.
-     */
-    std::string name;
-
-    /**
-     * The provider handle for a player.
-     */
-    SocialPlayerHandle handle;
-
-    /**
-     * Constructor
-     */
-    SocialPlayer();
-
-    /**
-     * Destructor
-     */
-    ~SocialPlayer();
-};
-
-}
-
-#endif

+ 0 - 18
gameplay/src/SocialScore.cpp

@@ -1,18 +0,0 @@
-#include "Base.h"
-#include "SocialScore.h"
-
-namespace gameplay
-{
-
-SocialScore::SocialScore()
-    : value(0.0f), rank(0)
-{
-}
-
-SocialScore::~SocialScore()
-{
-}
-
-}
-
-

+ 0 - 54
gameplay/src/SocialScore.h

@@ -1,54 +0,0 @@
-#ifndef SOCIALSCORE_H_
-#define SOCIALSCORE_H_
-
-namespace gameplay
-{
-
-/**
- * Defines an abstract class for a score that resides in a leaderboard.
- *
- * @script{ignore}
- */
-class SocialScore
-{
-public:
-
-    /**
-     * The value for the score.
-     */
-    float value;
-
-    /**
-     * The formatted value for the score.
-     */
-    std::string valueFormatted;
-
-    /**
-     * The rank index of the score within the leaderboard.
-     */
-    unsigned int rank;
-
-    /**
-     * The handle of the player that achieved the score
-     */
-    std::string playerName;
-
-    /**
-     * The score
-     */
-    SocialScoreHandle handle;
-
-    /**
-     * Constructor
-     */
-    SocialScore();
-
-    /**
-     * Destructor
-     */
-    ~SocialScore();
-};
-
-}
-
-#endif

+ 0 - 113
gameplay/src/SocialSession.h

@@ -1,113 +0,0 @@
-#ifndef SOCIALSESSION_H_
-#define SOCIALSESSION_H_
-
-#include "SocialSessionListener.h"
-#include "SocialPlayer.h"
-#include "SocialAchievement.h"
-#include "SocialScore.h"
-#include "SocialChallenge.h"
-#include "Properties.h"
-
-namespace gameplay
-{
-
-/**
- * Defines an abstract class for typical social game activities running with an authenticated session.
- *
- * @script{ignore}
- */
-class SocialSession
-{
-    friend class SocialController;
-
-public:
-
-    enum CommunityScope
-    {
-        COMMUNITY_SCOPE_FRIENDS,
-        COMMUNITY_SCOPE_ALL
-    };
-
-    enum TimeScope
-    {
-        TIME_SCOPE_TODAY,
-        TIME_SCOPE_WEEK,
-        TIME_SCOPE_ALL,
-    };
-
-    /**
-     * Gets the asynchronous response listener that registered for this session.
-     *
-     * @return The asynchronous response listener that registered for this session.
-     */
-    virtual SocialSessionListener* getListener() = 0;
-
-    virtual const SocialPlayer& getUser() const = 0;
-
-    virtual void loadFriends() = 0;
-
-    virtual void loadAchievements() = 0;
-
-    virtual void submitAchievement(const char* achievementId, unsigned int value, bool achieved=false) = 0;
-
-    virtual void incrementAchievement(const char* achievementId, unsigned int increment=1) = 0;
-
-    virtual void synchronizeAchievements() = 0;
-
-    /**
-     * Asynchronously request the scores for the count where the player is in the middle.
-     *
-     * @param leaderboardId The leaderboard to get populated with the scores.
-     * @param community The community scope to filter the search list.
-     * @param time The time scope to filter teh search list.
-     * @param player The player to narrow the search around.
-     * @param count The number to scores return in the result.
-     */
-    virtual void loadScores(const char* leaderboardId, CommunityScope community, TimeScope time, const SocialPlayer& player, unsigned int count) = 0;
-
-    /**
-     * Asynchronously request the scores for a specified leaderboard for this game.
-     *
-     * @param leaderboardId The leaderboard to get populated with the scores.
-     */
-    virtual void loadScores(const char* leaderboardId, CommunityScope community, TimeScope time, unsigned int start, unsigned int count) = 0;
-
-    virtual void submitScore(const char* leaderboardId, float value) = 0;
-
-    virtual void submitChallenge(const SocialPlayer *player, unsigned int wager, float score, const char* leaderboardId=0) = 0;
-
-    virtual void loadChallenges(bool showOpenChallengesOnly=true) = 0;
-
-    virtual void replyToChallenge(const SocialChallenge *challenge, bool accept) = 0;
-
-    virtual void loadSavedData(const char* key) = 0;
-
-    virtual void submitSavedData(const char* key, std::string data) = 0;
-
-    virtual void displayLeaderboard(const char* leaderboardId) = 0;
-
-    virtual void displayAchievements() = 0;
-
-    virtual void displayChallenges() = 0;
-
-    virtual void displayChallengeSubmit(const SocialChallenge *challenge, float score) = 0;
-
-    virtual bool handleEvent(void *event) { return true; }
-
-protected:
-
-    /**
-     * Contructor
-     */
-    SocialSession() { }
-
-    /**
-     * Destructor
-     */
-    virtual ~SocialSession() { }
-
-};
-
-}
-
-#endif

+ 0 - 92
gameplay/src/SocialSessionListener.cpp

@@ -1,92 +0,0 @@
-#include "Base.h"
-#include "SocialSessionListener.h"
-
-namespace gameplay
-{
-SocialSessionListener::SocialSessionListener()
-{
-}
-
-SocialSessionListener::SocialSessionListener(const SocialSessionListener& copy)
-{
-}
-
-SocialSessionListener::~SocialSessionListener()
-{
-}
-
-void SocialSessionListener::authenticateEvent(ResponseCode code, SocialSession* session)
-{
-}
-
-void SocialSessionListener::loadFriendsEvent(ResponseCode code, std::vector<SocialPlayer> friends)
-{
-}
-
-void SocialSessionListener::loadAchievementsEvent(ResponseCode code, std::vector<SocialAchievement> achievements)
-{
-}
-
-void SocialSessionListener::synchronizeAchievementEvent(ResponseCode code)
-{
-}
-
-void SocialSessionListener::submitAchievementEvent(ResponseCode code)
-{
-}
-
-void SocialSessionListener::awardAchievedEvent(ResponseCode code, const SocialAchievement &achievement)
-{
-}
-
-void SocialSessionListener::loadScoresEvent(ResponseCode code, std::vector<SocialScore> scores)
-{
-}
-
-void SocialSessionListener::submitScoreEvent(ResponseCode code)
-{
-}
-
-void SocialSessionListener::submitChallengeEvent(ResponseCode code, const SocialChallenge &challenge)
-{
-}
-
-void SocialSessionListener::startChallengeEvent(ResponseCode code, const SocialChallenge &challenge)
-{
-}
-
-void SocialSessionListener::replyToChallengeEvent(ResponseCode code)
-{
-}
-
-void SocialSessionListener::loadChallengesEvent(ResponseCode code, std::vector<SocialChallenge> challenges)
-{
-}
-
-void SocialSessionListener::loadSavedDataEvent(ResponseCode code, std::string data)
-{
-}
-
-void SocialSessionListener::submitSavedDataEvent(ResponseCode code)
-{
-}
-
-void SocialSessionListener::uiEvent(ResponseCode code, std::string errorMessage)
-{
-}
-
-void SocialSessionListener::displayedLeaderboardEvent(ResponseCode code, std::string errorMessage)
-{
-}
-
-void SocialSessionListener::displayedAchievementsEvent(ResponseCode code, std::string errorMessage)
-{
-}
-
-void SocialSessionListener::displayedChallengesEvent(ResponseCode code, std::string errorMessage)
-{
-}
-
-}
-
-

+ 0 - 95
gameplay/src/SocialSessionListener.h

@@ -1,95 +0,0 @@
-#ifndef SOCIALSESSIONLISTENER_H_
-#define SOCIALSESSIONLISTENER_H_
-
-#include "SocialPlayer.h"
-#include "SocialAchievement.h"
-#include "SocialScore.h"
-#include "SocialChallenge.h"
-
-namespace gameplay
-{
-
-class SocialSession;
-
-/**
- * Defines a class for handling session responses to various session request.
- *
- * @script{ignore}
- */
-class SocialSessionListener
-{
-public:
-
-    /**
-     * Constructor
-     */
-    SocialSessionListener();
-
-    /**
-     * Constructor
-     */
-    SocialSessionListener(const SocialSessionListener& copy);
-
-    /**
-     * Destructor
-     */
-    virtual ~SocialSessionListener();
-
-    /**
-     * Response codes returned on listener events.
-     */
-    enum ResponseCode
-    {
-        SUCCESS = 0,
-        ERROR_INITIALIZATION,
-        ERROR_PENDING_RESPONSE,
-        ERROR_INVALID_USER,
-        ERROR_INVALID_ARG,
-        ERROR_SERVER,
-        ERROR_CANCELLED,
-        ERROR_NOT_SUPPORTED,
-        ERROR_UNKNOWN
-    };
-
-    virtual void authenticateEvent(ResponseCode code, SocialSession* session);
-
-    virtual void loadFriendsEvent(ResponseCode code, std::vector<SocialPlayer> friends);
-
-    virtual void loadAchievementsEvent(ResponseCode code, std::vector<SocialAchievement> achievements);
-
-    virtual void synchronizeAchievementEvent(ResponseCode code);
-
-    virtual void submitAchievementEvent(ResponseCode code);
-
-    virtual void awardAchievedEvent(ResponseCode code, const SocialAchievement &achievement);
-
-    virtual void loadScoresEvent(ResponseCode code, std::vector<SocialScore> scores);
-
-    virtual void submitScoreEvent(ResponseCode code);
-
-    virtual void submitChallengeEvent(ResponseCode code, const SocialChallenge &challenge);
-
-    virtual void startChallengeEvent(ResponseCode code, const SocialChallenge &challenge);
-
-    virtual void replyToChallengeEvent(ResponseCode code);
-
-    virtual void loadChallengesEvent(ResponseCode code, std::vector<SocialChallenge> challenges);
-
-    virtual void loadSavedDataEvent(ResponseCode code, std::string data);
-
-    virtual void submitSavedDataEvent(ResponseCode code);
-
-    virtual void uiEvent(ResponseCode code, std::string errorMessage="");
-
-    virtual void displayedLeaderboardEvent(ResponseCode code, std::string errorMessage="");
-
-    virtual void displayedAchievementsEvent(ResponseCode code, std::string errorMessage="");
-
-    virtual void displayedChallengesEvent(ResponseCode code, std::string errorMessage="");
-
-};
-
-}
-
-
-#endif

+ 585 - 634
gameplay/src/Terrain.cpp

@@ -1,634 +1,585 @@
-#include "Base.h"
-#include "Terrain.h"
-#include "TerrainPatch.h"
-#include "Node.h"
-#include "FileSystem.h"
-
-namespace gameplay
-{
-
-// The default square size of terrain patches for a terrain that
-// does not have an explicitly specified patch size.
-//
-#define DEFAULT_TERRAIN_PATCH_SIZE 32
-
-// The default height of a terrain that does not have an explicitly
-// specified terrain size, expressed as a ratio of the average
-// of the dimensions of the terrain heightfield:
-//
-//   heightMax = (image.width + image.height) / 2 * DEFAULT_TERRAIN_HEIGHT_RATIO
-//
-#define DEFAULT_TERRAIN_HEIGHT_RATIO 0.3f
-
-// Terrain dirty flag bits
-#define TERRAIN_DIRTY_WORLD_MATRIX 1
-#define TERRAIN_DIRTY_INV_WORLD_MATRIX 2
-#define TERRAIN_DIRTY_NORMAL_MATRIX 4
-
-/**
- * @script{ignore}
- */
-float getDefaultHeight(unsigned int width, unsigned int height);
-
-Terrain::Terrain() :
-    _heightfield(NULL), _node(NULL), _normalMap(NULL), _flags(FRUSTUM_CULLING | LEVEL_OF_DETAIL),
-    _dirtyFlags(TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX)
-{
-}
-
-Terrain::~Terrain()
-{
-    _listeners.clear();
-
-    for (size_t i = 0, count = _patches.size(); i < count; ++i)
-    {
-        SAFE_DELETE(_patches[i]);
-    }
-
-    if (_node)
-        _node->removeListener(this);
-
-    SAFE_RELEASE(_normalMap);
-    SAFE_RELEASE(_heightfield);
-}
-
-Terrain* Terrain::create(const char* path)
-{
-    return create(path, NULL);
-}
-
-Terrain* Terrain::create(Properties* properties)
-{
-    return create(properties->getNamespace(), properties);
-}
-
-Terrain* Terrain::create(const char* path, Properties* properties)
-{
-    // Terrain properties
-    Properties* p = properties;
-    Properties* pTerrain = NULL;
-    bool externalProperties = (p != NULL);
-    HeightField* heightfield = NULL;
-    Vector3 terrainSize;
-    int patchSize = 0;
-    int detailLevels = 1;
-    float skirtScale = 0;
-    const char* normalMap = NULL;
-
-    if (!p && path)
-    {
-        p = Properties::create(path);
-    }
-
-    if (p)
-    {
-        pTerrain = strlen(p->getNamespace()) > 0 ? p : p->getNextNamespace();
-        if (pTerrain == NULL)
-        {
-            GP_WARN("Invalid terrain definition.");
-            if (!externalProperties)
-                SAFE_DELETE(p);
-            return NULL;
-        }
-
-        // Read heightmap info
-        Properties* pHeightmap = pTerrain->getNamespace("heightmap", true);
-        if (pHeightmap)
-        {
-            // Read heightmap path
-            std::string heightmap;
-            if (!pHeightmap->getPath("path", &heightmap))
-            {
-                GP_WARN("No 'path' property supplied in heightmap section of terrain definition: %s", path);
-                if (!externalProperties)
-                    SAFE_DELETE(p);
-                return NULL;
-            }
-
-            std::string ext = FileSystem::getExtension(heightmap.c_str());
-            if (ext == ".PNG")
-            {
-                // Read normalized height values from heightmap image
-                heightfield = HeightField::createFromImage(heightmap.c_str(), 0, 1);
-            }
-            else if (ext == ".RAW" || ext == ".R16")
-            {
-                // Require additional properties to be specified for RAW files
-                Vector2 imageSize;
-                if (!pHeightmap->getVector2("size", &imageSize))
-                {
-                    GP_WARN("Invalid or missing 'size' attribute in heightmap defintion of terrain definition: %s", path);
-                    if (!externalProperties)
-                        SAFE_DELETE(p);
-                    return NULL;
-                }
-
-                // Read normalized height values from RAW file
-                heightfield = HeightField::createFromRAW(heightmap.c_str(), (unsigned int)imageSize.x, (unsigned int)imageSize.y, 0, 1);
-            }
-            else
-            {
-                // Unsupported heightmap format
-                GP_WARN("Unsupported heightmap format ('%s') in terrain definition: %s", heightmap.c_str(), path);
-                if (!externalProperties)
-                    SAFE_DELETE(p);
-                return NULL;
-            }
-        }
-        else
-        {
-            // Try to read 'heightmap' as a simple string property
-            std::string heightmap;
-            if (!pTerrain->getPath("heightmap", &heightmap))
-            {
-                GP_WARN("No 'heightmap' property supplied in terrain definition: %s", path);
-                if (!externalProperties)
-                    SAFE_DELETE(p);
-                return NULL;
-            }
-
-            std::string ext = FileSystem::getExtension(heightmap.c_str());
-            if (ext == ".PNG")
-            {
-                // Read normalized height values from heightmap image
-                heightfield = HeightField::createFromImage(heightmap.c_str(), 0, 1);
-            }
-            else if (ext == ".RAW" || ext == ".R16")
-            {
-                GP_WARN("RAW heightmaps must be specified inside a heightmap block with width and height properties.");
-                if (!externalProperties)
-                    SAFE_DELETE(p);
-                return NULL;
-            }
-            else
-            {
-                GP_WARN("Unsupported 'heightmap' format ('%s') in terrain definition: %s.", heightmap.c_str(), path);
-                if (!externalProperties)
-                    SAFE_DELETE(p);
-                return NULL;
-            }
-        }
-
-        // Read terrain 'size'
-        if (pTerrain->exists("size"))
-        {
-            if (!pTerrain->getVector3("size", &terrainSize))
-            {
-                GP_WARN("Invalid 'size' value ('%s') in terrain definition: %s", pTerrain->getString("size"), path);
-            }
-        }
-
-        // Read terrain 'patch size'
-        if (pTerrain->exists("patchSize"))
-        {
-            patchSize = pTerrain->getInt("patchSize");
-        }
-
-        // Read terrain 'detailLevels'
-        if (pTerrain->exists("detailLevels"))
-        {
-            detailLevels = pTerrain->getInt("detailLevels");
-        }
-
-        // Read 'skirtScale'
-        if (pTerrain->exists("skirtScale"))
-        {
-            skirtScale = pTerrain->getFloat("skirtScale");
-        }
-
-        // Read 'normalMap'
-        normalMap = pTerrain->getString("normalMap");
-    }
-
-    if (heightfield == NULL)
-    {
-        GP_WARN("Failed to read heightfield heights for terrain definition: %s", path);
-        if (!externalProperties)
-            SAFE_DELETE(p);
-        return NULL;
-    }
-
-    if (terrainSize.isZero())
-    {
-        terrainSize.set(heightfield->getColumnCount(), getDefaultHeight(heightfield->getColumnCount(), heightfield->getRowCount()), heightfield->getRowCount());
-    }
-
-    if (patchSize <= 0 || patchSize > (int)heightfield->getColumnCount() || patchSize > (int)heightfield->getRowCount())
-    {
-        patchSize = std::min(heightfield->getRowCount(), std::min(heightfield->getColumnCount(), (unsigned int)DEFAULT_TERRAIN_PATCH_SIZE));
-    }
-
-    if (detailLevels <= 0)
-        detailLevels = 1;
-
-    if (skirtScale < 0)
-        skirtScale = 0;
-
-    // Compute terrain scale
-    Vector3 scale(terrainSize.x / (heightfield->getColumnCount()-1), terrainSize.y, terrainSize.z / (heightfield->getRowCount()-1));
-
-    // Create terrain
-    Terrain* terrain = create(heightfield, scale, (unsigned int)patchSize, (unsigned int)detailLevels, skirtScale, normalMap, pTerrain);
-
-    if (!externalProperties)
-        SAFE_DELETE(p);
-
-    return terrain;
-}
-
-Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath)
-{
-    return create(heightfield, scale, patchSize, detailLevels, skirtScale, normalMapPath, NULL);
-}
-
-Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath, Properties* properties)
-{
-    GP_ASSERT(heightfield);
-
-    unsigned int width = heightfield->getColumnCount();
-    unsigned int height = heightfield->getRowCount();
-
-    // Create the terrain object
-    Terrain* terrain = new Terrain();
-    terrain->_heightfield = heightfield;
-    terrain->_localScale = scale;
-
-    // Store reference to bounding box (it is calculated and updated from TerrainPatch)
-    BoundingBox& bounds = terrain->_boundingBox;
-
-    if (normalMapPath)
-        terrain->_normalMap = Texture::Sampler::create(normalMapPath, true);
-
-    float halfWidth = (width - 1) * 0.5f;
-    float halfHeight = (height - 1) * 0.5f;
-    unsigned int maxStep = (unsigned int)std::pow(2.0, (double)(detailLevels-1));
-
-    // Create terrain patches
-    unsigned int x1, x2, z1, z2;
-    unsigned int row = 0, column = 0;
-    for (unsigned int z = 0; z < height-1; z = z2, ++row)
-    {
-        z1 = z;
-        z2 = std::min(z1 + patchSize, height-1);
-
-        for (unsigned int x = 0; x < width-1; x = x2, ++column)
-        {
-            x1 = x;
-            x2 = std::min(x1 + patchSize, width-1);
-
-            // Create this patch
-            TerrainPatch* patch = TerrainPatch::create(terrain, row, column, heightfield->getArray(), width, height, x1, z1, x2, z2, -halfWidth, -halfHeight, maxStep, skirtScale);
-            terrain->_patches.push_back(patch);
-
-            // Append the new patch's local bounds to the terrain local bounds
-            bounds.merge(patch->getBoundingBox(false));
-        }
-    }
-
-    // Read additional layer information from properties (if specified)
-    if (properties)
-    {
-        // Parse terrain layers
-        Properties* lp;
-        int index = -1;
-        while ((lp = properties->getNextNamespace()) != NULL)
-        {
-            if (strcmp(lp->getNamespace(), "layer") == 0)
-            {
-                // If there is no explicitly specified index for this layer, assume it's the 'next' layer
-                if (lp->exists("index"))
-                    index = lp->getInt("index");
-                else
-                    ++index;
-
-                std::string textureMap;
-                const char* textureMapPtr = NULL;
-                std::string blendMap;
-                const char* blendMapPtr = NULL;
-                Vector2 textureRepeat;
-                int blendChannel = 0;
-                int row = -1, column = -1;
-                Vector4 temp;
-
-                // Read layer textures
-                Properties* t = lp->getNamespace("texture", true);
-                if (t)
-                {
-                    if (t->getPath("path", &textureMap))
-                    {
-                        textureMapPtr = textureMap.c_str();
-                    }
-                    if (!t->getVector2("repeat", &textureRepeat))
-                        textureRepeat.set(1,1);
-                }
-
-                Properties* b = lp->getNamespace("blend", true);
-                if (b)
-                {
-                    if (b->getPath("path", &blendMap))
-                    {
-                        blendMapPtr = blendMap.c_str();
-                    }
-                    const char* channel = b->getString("channel");
-                    if (channel && strlen(channel) > 0)
-                    {
-                        char c = std::toupper(channel[0]);
-                        if (c == 'R' || c == '0')
-                            blendChannel = 0;
-                        else if (c == 'G' || c == '1')
-                            blendChannel = 1;
-                        else if (c == 'B' || c == '2')
-                            blendChannel = 2;
-                        else if (c == 'A' || c == '3')
-                            blendChannel = 3;
-                    }
-                }
-
-                // Get patch row/columns that this layer applies to.
-                if (lp->exists("row"))
-                    row = lp->getInt("row");
-                if (lp->exists("column"))
-                    column = lp->getInt("column");
-
-                if (!terrain->setLayer(index, textureMapPtr, textureRepeat, blendMapPtr, blendChannel, row, column))
-                {
-                    GP_WARN("Failed to load terrain layer: %s", textureMap.c_str());
-                }
-            }
-        }
-    }
-
-    // Load materials for all patches
-    for (size_t i = 0, count = terrain->_patches.size(); i < count; ++i)
-        terrain->_patches[i]->updateMaterial();
-
-    return terrain;
-}
-
-void Terrain::setNode(Node* node)
-{
-    if (_node != node)
-    {
-        if (_node)
-            _node->removeListener(this);
-
-        _node = node;
-
-        if (_node)
-            _node->addListener(this);
-
-        _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
-    }
-}
-
-bool Terrain::setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel, int row, int column)
-{
-    if (!texturePath)
-        return false;
-
-    // Set layer on applicable patches
-    bool result = true;
-    for (size_t i = 0, count = _patches.size(); i < count; ++i)
-    {
-        TerrainPatch* patch = _patches[i];
-
-        if ((row == -1 || (int)patch->_row == row) && (column == -1 || (int)patch->_column == column))
-        {
-            if (!patch->setLayer(index, texturePath, textureRepeat, blendPath, blendChannel))
-                result = false;
-        }
-    }
-
-    return result;
-}
-
-Node* Terrain::getNode() const
-{
-    return _node;
-}
-
-bool Terrain::isFlagSet(Flags flag) const
-{
-    return (_flags & flag) == flag;
-}
-
-void Terrain::setFlag(Flags flag, bool on)
-{
-    bool changed = false;
-
-    if (on)
-    {
-        if ((_flags & flag) == 0)
-        {
-            _flags |= flag;
-            changed = true;
-        }
-    }
-    else
-    {
-        if ((_flags & flag) == flag)
-        {
-            _flags &= ~flag;
-            changed = true;
-        }
-    }
-
-    if (flag == DEBUG_PATCHES && changed)
-    {
-        // Dirty all materials since they need to be updated to support debug drawing
-        for (size_t i = 0, count = _patches.size(); i < count; ++i)
-            _patches[i]->_materialDirty = true;
-    }
-}
-
-unsigned int Terrain::getPatchCount() const
-{
-    return _patches.size();
-}
-
-unsigned int Terrain::getVisiblePatchCount() const
-{
-    unsigned int visibleCount = 0;
-    for (size_t i = 0, count = _patches.size(); i < count; ++i)
-    {
-        if (_patches[i]->isVisible())
-            ++visibleCount;
-    }
-    return visibleCount;
-}
-
-unsigned int Terrain::getTriangleCount() const
-{
-    unsigned int triangleCount = 0;
-    for (size_t i = 0, count = _patches.size(); i < count; ++i)
-    {
-        triangleCount += _patches[i]->getTriangleCount();
-    }
-    return triangleCount;
-}
-
-unsigned int Terrain::getVisibleTriangleCount() const
-{
-    unsigned int triangleCount = 0;
-    for (size_t i = 0, count = _patches.size(); i < count; ++i)
-    {
-        triangleCount += _patches[i]->getVisibleTriangleCount();
-    }
-    return triangleCount;
-}
-
-const BoundingBox& Terrain::getBoundingBox() const
-{
-    return _boundingBox;
-}
-
-float Terrain::getHeight(float x, float z) const
-{
-    // Calculate the correct x, z position relative to the heightfield data.
-    float cols = _heightfield->getColumnCount();
-    float rows = _heightfield->getRowCount();
-
-    GP_ASSERT(cols > 0);
-    GP_ASSERT(rows > 0);
-
-    // Since the specified coordinates are in world space, we need to use the 
-    // inverse of our world matrix to transform the world x,z coords back into
-    // local heightfield coordinates for indexing into the height array.
-    Vector3 v = getInverseWorldMatrix() * Vector3(x, 0.0f, z);
-    x = v.x + (cols - 1) * 0.5f;
-    z = v.z + (rows - 1) * 0.5f;
-
-    // Get the unscaled height value from the HeightField
-    float height = _heightfield->getHeight(x, z);
-
-    // Now apply world scale (this includes local terrain scale) to the heightfield value
-    Vector3 worldScale;
-    getWorldMatrix().getScale(&worldScale);
-    height *= worldScale.y;
-
-    return height;
-}
-
-unsigned int Terrain::draw(bool wireframe)
-{
-    for (size_t i = 0, count = _patches.size(); i < count; ++i)
-    {
-        _patches[i]->draw(wireframe);
-    }
-    return getVisiblePatchCount();
-}
-
-void Terrain::transformChanged(Transform* transform, long cookie)
-{
-    _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
-}
-
-void Terrain::addListener(Terrain::Listener* listener)
-{
-    _listeners.push_back(listener);
-
-    // Fire initial events in case this listener may have missed them
-    for (size_t i = 0, patchCount = _patches.size(); i < patchCount; ++i)
-    {
-        TerrainPatch* patch = _patches[i];
-        for (size_t j = 0, levelCount = patch->_levels.size(); j < levelCount; ++j)
-        {
-            TerrainPatch::Level* level = patch->_levels[j];
-            Material* material = level->model ? level->model->getMaterial() : NULL;
-            if (material)
-            {
-                // Fire materialUpdated event for materials that are already active
-                for (size_t k = 0, lcount = _listeners.size(); k < lcount; ++k)
-                {
-                    _listeners[k]->materialUpdated(this, material);
-                }
-            }
-        }
-    }
-}
-
-void Terrain::removeListener(Terrain::Listener* listener)
-{
-    std::vector<Terrain::Listener*>::iterator itr = std::find(_listeners.begin(), _listeners.end(), listener);
-    if (itr != _listeners.end())
-        _listeners.erase(itr);
-}
-
-const Matrix& Terrain::getWorldMatrix() const
-{
-    if (_dirtyFlags & TERRAIN_DIRTY_WORLD_MATRIX)
-    {
-        _dirtyFlags &= ~TERRAIN_DIRTY_WORLD_MATRIX;
-
-        // Apply our attached node's world matrix
-        if (_node)
-        {
-            _worldMatrix = _node->getWorldMatrix();
-        }
-        else
-        {
-            _worldMatrix.setIdentity();
-        }
-
-        // Factor in our local scaling
-        _worldMatrix.scale(_localScale);
-    }
-
-    return _worldMatrix;
-}
-
-const Matrix& Terrain::getInverseWorldMatrix() const
-{
-    if (_dirtyFlags & TERRAIN_DIRTY_INV_WORLD_MATRIX)
-    {
-        _dirtyFlags &= ~TERRAIN_DIRTY_INV_WORLD_MATRIX;
-
-        getWorldMatrix().invert(&_inverseWorldMatrix);
-    }
-
-    return _inverseWorldMatrix;
-}
-
-const Matrix& Terrain::getNormalMatrix() const
-{
-    if (_dirtyFlags & TERRAIN_DIRTY_NORMAL_MATRIX)
-    {
-        _dirtyFlags &= ~TERRAIN_DIRTY_NORMAL_MATRIX;
-
-        getInverseWorldMatrix().transpose(&_normalMatrix);
-    }
-
-    return _normalMatrix;
-}
-
-const Matrix& Terrain::getWorldViewMatrix() const
-{
-    static Matrix worldView;
-
-    if (_node)
-        Matrix::multiply(_node->getViewMatrix(), getWorldMatrix(), &worldView);
-    else
-        worldView = getWorldMatrix(); // no node, so nothing to get view from
-
-    return worldView;
-}
-
-const Matrix& Terrain::getWorldViewProjectionMatrix() const
-{
-    static Matrix worldViewProj;
-
-    if (_node)
-        Matrix::multiply(_node->getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
-    else
-        worldViewProj = getWorldMatrix(); // no node, so nothing to get viewProjection from
-
-    return worldViewProj;
-}
-
-float getDefaultHeight(unsigned int width, unsigned int height)
-{
-    // When terrain height is not specified, we'll use a default height of ~ 0.3 of the image dimensions
-    return ((width + height) * 0.5f) * DEFAULT_TERRAIN_HEIGHT_RATIO;
-}
-
-}
+#include "Base.h"
+#include "Terrain.h"
+#include "TerrainPatch.h"
+#include "Node.h"
+#include "FileSystem.h"
+
+namespace gameplay
+{
+
+// The default square size of terrain patches for a terrain that
+// does not have an explicitly specified patch size.
+//
+#define DEFAULT_TERRAIN_PATCH_SIZE 32
+
+// The default height of a terrain that does not have an explicitly
+// specified terrain size, expressed as a ratio of the average
+// of the dimensions of the terrain heightfield:
+//
+//   heightMax = (image.width + image.height) / 2 * DEFAULT_TERRAIN_HEIGHT_RATIO
+//
+#define DEFAULT_TERRAIN_HEIGHT_RATIO 0.3f
+
+// Terrain dirty flag bits
+#define TERRAIN_DIRTY_WORLD_MATRIX 1
+#define TERRAIN_DIRTY_INV_WORLD_MATRIX 2
+#define TERRAIN_DIRTY_NORMAL_MATRIX 4
+
+/**
+ * @script{ignore}
+ */
+float getDefaultHeight(unsigned int width, unsigned int height);
+
+Terrain::Terrain() :
+    _heightfield(NULL), _node(NULL), _normalMap(NULL), _flags(FRUSTUM_CULLING | LEVEL_OF_DETAIL),
+    _dirtyFlags(TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX),
+    _directionalLightCount(0), _pointLightCount(0), _spotLightCount(0)
+{
+}
+
+Terrain::~Terrain()
+{
+    for (size_t i = 0, count = _patches.size(); i < count; ++i)
+    {
+        SAFE_DELETE(_patches[i]);
+    }
+    SAFE_RELEASE(_normalMap);
+    SAFE_RELEASE(_heightfield);
+}
+
+Terrain* Terrain::create(const char* path)
+{
+    return create(path, NULL);
+}
+
+Terrain* Terrain::create(Properties* properties)
+{
+    return create(properties->getNamespace(), properties);
+}
+
+Terrain* Terrain::create(const char* path, Properties* properties)
+{
+    // Terrain properties
+    Properties* p = properties;
+    Properties* pTerrain = NULL;
+    bool externalProperties = (p != NULL);
+    HeightField* heightfield = NULL;
+    Vector3 terrainSize;
+    int patchSize = 0;
+    int detailLevels = 1;
+    float skirtScale = 0;
+    const char* normalMap = NULL;
+    unsigned int directionalLightCount = 0;
+    unsigned int pointLightCount = 0;
+    unsigned int spotLightCount = 0;
+
+    if (!p && path)
+    {
+        p = Properties::create(path);
+    }
+
+    if (p)
+    {
+        pTerrain = strlen(p->getNamespace()) > 0 ? p : p->getNextNamespace();
+        if (pTerrain == NULL)
+        {
+            GP_WARN("Invalid terrain definition.");
+            if (!externalProperties)
+                SAFE_DELETE(p);
+            return NULL;
+        }
+
+        // Read heightmap info
+        Properties* pHeightmap = pTerrain->getNamespace("heightmap", true);
+        if (pHeightmap)
+        {
+            // Read heightmap path
+            std::string heightmap;
+            if (!pHeightmap->getPath("path", &heightmap))
+            {
+                GP_WARN("No 'path' property supplied in heightmap section of terrain definition: %s", path);
+                if (!externalProperties)
+                    SAFE_DELETE(p);
+                return NULL;
+            }
+
+            std::string ext = FileSystem::getExtension(heightmap.c_str());
+            if (ext == ".PNG")
+            {
+                // Read normalized height values from heightmap image
+                heightfield = HeightField::createFromImage(heightmap.c_str(), 0, 1);
+            }
+            else if (ext == ".RAW" || ext == ".R16")
+            {
+                // Require additional properties to be specified for RAW files
+                Vector2 imageSize;
+                if (!pHeightmap->getVector2("size", &imageSize))
+                {
+                    GP_WARN("Invalid or missing 'size' attribute in heightmap defintion of terrain definition: %s", path);
+                    if (!externalProperties)
+                        SAFE_DELETE(p);
+                    return NULL;
+                }
+
+                // Read normalized height values from RAW file
+                heightfield = HeightField::createFromRAW(heightmap.c_str(), (unsigned int)imageSize.x, (unsigned int)imageSize.y, 0, 1);
+            }
+            else
+            {
+                // Unsupported heightmap format
+                GP_WARN("Unsupported heightmap format ('%s') in terrain definition: %s", heightmap.c_str(), path);
+                if (!externalProperties)
+                    SAFE_DELETE(p);
+                return NULL;
+            }
+        }
+        else
+        {
+            // Try to read 'heightmap' as a simple string property
+            std::string heightmap;
+            if (!pTerrain->getPath("heightmap", &heightmap))
+            {
+                GP_WARN("No 'heightmap' property supplied in terrain definition: %s", path);
+                if (!externalProperties)
+                    SAFE_DELETE(p);
+                return NULL;
+            }
+
+            std::string ext = FileSystem::getExtension(heightmap.c_str());
+            if (ext == ".PNG")
+            {
+                // Read normalized height values from heightmap image
+                heightfield = HeightField::createFromImage(heightmap.c_str(), 0, 1);
+            }
+            else if (ext == ".RAW" || ext == ".R16")
+            {
+                GP_WARN("RAW heightmaps must be specified inside a heightmap block with width and height properties.");
+                if (!externalProperties)
+                    SAFE_DELETE(p);
+                return NULL;
+            }
+            else
+            {
+                GP_WARN("Unsupported 'heightmap' format ('%s') in terrain definition: %s.", heightmap.c_str(), path);
+                if (!externalProperties)
+                    SAFE_DELETE(p);
+                return NULL;
+            }
+        }
+
+        // Read terrain 'size'
+        if (pTerrain->exists("size"))
+        {
+            if (!pTerrain->getVector3("size", &terrainSize))
+            {
+                GP_WARN("Invalid 'size' value ('%s') in terrain definition: %s", pTerrain->getString("size"), path);
+            }
+        }
+
+        // Read terrain 'patch size'
+        if (pTerrain->exists("patchSize"))
+        {
+            patchSize = pTerrain->getInt("patchSize");
+        }
+
+        // Read terrain 'detailLevels'
+        if (pTerrain->exists("detailLevels"))
+        {
+            detailLevels = pTerrain->getInt("detailLevels");
+        }
+
+        // Read 'skirtScale'
+        if (pTerrain->exists("skirtScale"))
+        {
+            skirtScale = pTerrain->getFloat("skirtScale");
+        }
+
+        // Read 'normalMap'
+        normalMap = pTerrain->getString("normalMap");
+    }
+
+    if (heightfield == NULL)
+    {
+        GP_WARN("Failed to read heightfield heights for terrain definition: %s", path);
+        if (!externalProperties)
+            SAFE_DELETE(p);
+        return NULL;
+    }
+
+    if (terrainSize.isZero())
+    {
+        terrainSize.set(heightfield->getColumnCount(), getDefaultHeight(heightfield->getColumnCount(), heightfield->getRowCount()), heightfield->getRowCount());
+    }
+
+    if (patchSize <= 0 || patchSize > (int)heightfield->getColumnCount() || patchSize > (int)heightfield->getRowCount())
+    {
+        patchSize = std::min(heightfield->getRowCount(), std::min(heightfield->getColumnCount(), (unsigned int)DEFAULT_TERRAIN_PATCH_SIZE));
+    }
+
+    if (detailLevels <= 0)
+        detailLevels = 1;
+
+    if (skirtScale < 0)
+        skirtScale = 0;
+
+    // Compute terrain scale
+    Vector3 scale(terrainSize.x / (heightfield->getColumnCount()-1), terrainSize.y, terrainSize.z / (heightfield->getRowCount()-1));
+
+    // Create terrain
+    Terrain* terrain = create(heightfield, scale, (unsigned int)patchSize, (unsigned int)detailLevels, skirtScale, normalMap, pTerrain);
+
+
+    if (!externalProperties)
+        SAFE_DELETE(p);
+
+    return terrain;
+}
+
+Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath)
+{
+    return create(heightfield, scale, patchSize, detailLevels, skirtScale, normalMapPath, NULL);
+}
+
+Terrain* Terrain::create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath, Properties* properties)
+{
+    GP_ASSERT(heightfield);
+
+    unsigned int width = heightfield->getColumnCount();
+    unsigned int height = heightfield->getRowCount();
+
+    // Create the terrain object
+    Terrain* terrain = new Terrain();
+    terrain->_heightfield = heightfield;
+    terrain->_localScale = scale;
+
+    // Store reference to bounding box (it is calculated and updated from TerrainPatch)
+    BoundingBox& bounds = terrain->_boundingBox;
+
+    if (normalMapPath)
+        terrain->_normalMap = Texture::Sampler::create(normalMapPath, true);
+
+    float halfWidth = (width - 1) * 0.5f;
+    float halfHeight = (height - 1) * 0.5f;
+    unsigned int maxStep = (unsigned int)std::pow(2.0, (double)(detailLevels-1));
+
+    Properties* lightingProps = properties->getNamespace("lighting", true);
+    if (lightingProps)
+    {
+        terrain->_directionalLightCount = lightingProps->getInt("directionalLights");
+        terrain->_pointLightCount = lightingProps->getInt("pointLights");
+        terrain->_spotLightCount = lightingProps->getInt("spotLights");
+    }
+
+    // Create terrain patches
+    unsigned int x1, x2, z1, z2;
+    unsigned int row = 0, column = 0;
+    for (unsigned int z = 0; z < height-1; z = z2, ++row)
+    {
+        z1 = z;
+        z2 = std::min(z1 + patchSize, height-1);
+
+        for (unsigned int x = 0; x < width-1; x = x2, ++column)
+        {
+            x1 = x;
+            x2 = std::min(x1 + patchSize, width-1);
+
+            // Create this patch
+            TerrainPatch* patch = TerrainPatch::create(terrain, row, column, heightfield->getArray(), width, height, x1, z1, x2, z2, -halfWidth, -halfHeight, maxStep, skirtScale);
+            terrain->_patches.push_back(patch);
+
+            // Append the new patch's local bounds to the terrain local bounds
+            bounds.merge(patch->getBoundingBox(false));
+        }
+    }
+
+    // Read additional layer information from properties (if specified)
+    if (properties)
+    {
+        // Parse terrain layers
+        Properties* lp;
+        int index = -1;
+        while ((lp = properties->getNextNamespace()) != NULL)
+        {
+            if (strcmp(lp->getNamespace(), "layer") == 0)
+            {
+                // If there is no explicitly specified index for this layer, assume it's the 'next' layer
+                if (lp->exists("index"))
+                    index = lp->getInt("index");
+                else
+                    ++index;
+
+                std::string textureMap;
+                const char* textureMapPtr = NULL;
+                std::string blendMap;
+                const char* blendMapPtr = NULL;
+                Vector2 textureRepeat;
+                int blendChannel = 0;
+                int row = -1, column = -1;
+                Vector4 temp;
+
+                // Read layer textures
+                Properties* t = lp->getNamespace("texture", true);
+                if (t)
+                {
+                    if (t->getPath("path", &textureMap))
+                    {
+                        textureMapPtr = textureMap.c_str();
+                    }
+                    if (!t->getVector2("repeat", &textureRepeat))
+                        textureRepeat.set(1,1);
+                }
+
+                Properties* b = lp->getNamespace("blend", true);
+                if (b)
+                {
+                    if (b->getPath("path", &blendMap))
+                    {
+                        blendMapPtr = blendMap.c_str();
+                    }
+                    const char* channel = b->getString("channel");
+                    if (channel && strlen(channel) > 0)
+                    {
+                        char c = std::toupper(channel[0]);
+                        if (c == 'R' || c == '0')
+                            blendChannel = 0;
+                        else if (c == 'G' || c == '1')
+                            blendChannel = 1;
+                        else if (c == 'B' || c == '2')
+                            blendChannel = 2;
+                        else if (c == 'A' || c == '3')
+                            blendChannel = 3;
+                    }
+                }
+
+                // Get patch row/columns that this layer applies to.
+                if (lp->exists("row"))
+                    row = lp->getInt("row");
+                if (lp->exists("column"))
+                    column = lp->getInt("column");
+
+                if (!terrain->setLayer(index, textureMapPtr, textureRepeat, blendMapPtr, blendChannel, row, column))
+                {
+                    GP_WARN("Failed to load terrain layer: %s", textureMap.c_str());
+                }
+            }
+        }
+    }
+
+    // Load materials for all patches
+    for (size_t i = 0, count = terrain->_patches.size(); i < count; ++i)
+        terrain->_patches[i]->updateMaterial();
+
+    return terrain;
+}
+
+void Terrain::setNode(Node* node)
+{
+    if (_node != node)
+    {
+        if (_node)
+            _node->removeListener(this);
+
+        _node = node;
+
+        if (_node)
+            _node->addListener(this);
+
+        _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
+    }
+}
+
+bool Terrain::setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel, int row, int column)
+{
+    if (!texturePath)
+        return false;
+
+    // Set layer on applicable patches
+    bool result = true;
+    for (size_t i = 0, count = _patches.size(); i < count; ++i)
+    {
+        TerrainPatch* patch = _patches[i];
+
+        if ((row == -1 || (int)patch->_row == row) && (column == -1 || (int)patch->_column == column))
+        {
+            if (!patch->setLayer(index, texturePath, textureRepeat, blendPath, blendChannel))
+                result = false;
+        }
+    }
+
+    return result;
+}
+
+Node* Terrain::getNode() const
+{
+    return _node;
+}
+
+bool Terrain::isFlagSet(Flags flag) const
+{
+    return (_flags & flag) == flag;
+}
+
+void Terrain::setFlag(Flags flag, bool on)
+{
+    bool changed = false;
+
+    if (on)
+    {
+        if ((_flags & flag) == 0)
+        {
+            _flags |= flag;
+            changed = true;
+        }
+    }
+    else
+    {
+        if ((_flags & flag) == flag)
+        {
+            _flags &= ~flag;
+            changed = true;
+        }
+    }
+
+    if (flag == DEBUG_PATCHES && changed)
+    {
+        // Dirty all materials since they need to be updated to support debug drawing
+        for (size_t i = 0, count = _patches.size(); i < count; ++i)
+            _patches[i]->setMaterialDirty();
+    }
+}
+
+unsigned int Terrain::getPatchCount() const
+{
+    return _patches.size();
+}
+
+TerrainPatch* Terrain::getPatch(unsigned int index) const
+{
+    return _patches[index];
+}
+
+const BoundingBox& Terrain::getBoundingBox() const
+{
+    return _boundingBox;
+}
+
+float Terrain::getHeight(float x, float z) const
+{
+    // Calculate the correct x, z position relative to the heightfield data.
+    float cols = _heightfield->getColumnCount();
+    float rows = _heightfield->getRowCount();
+
+    GP_ASSERT(cols > 0);
+    GP_ASSERT(rows > 0);
+
+    // Since the specified coordinates are in world space, we need to use the 
+    // inverse of our world matrix to transform the world x,z coords back into
+    // local heightfield coordinates for indexing into the height array.
+    Vector3 v = getInverseWorldMatrix() * Vector3(x, 0.0f, z);
+    x = v.x + (cols - 1) * 0.5f;
+    z = v.z + (rows - 1) * 0.5f;
+
+    // Get the unscaled height value from the HeightField
+    float height = _heightfield->getHeight(x, z);
+
+    // Now apply world scale (this includes local terrain scale) to the heightfield value
+    Vector3 worldScale;
+    getWorldMatrix().getScale(&worldScale);
+    height *= worldScale.y;
+
+    return height;
+}
+
+unsigned int Terrain::draw(bool wireframe)
+{
+    size_t visibleCount = 0;
+    for (size_t i = 0, count = _patches.size(); i < count; ++i)
+    {
+        visibleCount += _patches[i]->draw(wireframe);
+    }
+    return visibleCount;
+}
+
+void Terrain::transformChanged(Transform* transform, long cookie)
+{
+    _dirtyFlags |= TERRAIN_DIRTY_WORLD_MATRIX | TERRAIN_DIRTY_INV_WORLD_MATRIX | TERRAIN_DIRTY_NORMAL_MATRIX;
+}
+
+const Matrix& Terrain::getWorldMatrix() const
+{
+    if (_dirtyFlags & TERRAIN_DIRTY_WORLD_MATRIX)
+    {
+        _dirtyFlags &= ~TERRAIN_DIRTY_WORLD_MATRIX;
+
+        // Apply our attached node's world matrix
+        if (_node)
+        {
+            _worldMatrix = _node->getWorldMatrix();
+        }
+        else
+        {
+            _worldMatrix.setIdentity();
+        }
+
+        // Factor in our local scaling
+        _worldMatrix.scale(_localScale);
+    }
+
+    return _worldMatrix;
+}
+
+const Matrix& Terrain::getInverseWorldMatrix() const
+{
+    if (_dirtyFlags & TERRAIN_DIRTY_INV_WORLD_MATRIX)
+    {
+        _dirtyFlags &= ~TERRAIN_DIRTY_INV_WORLD_MATRIX;
+
+        getWorldMatrix().invert(&_inverseWorldMatrix);
+    }
+
+    return _inverseWorldMatrix;
+}
+
+const Matrix& Terrain::getNormalMatrix() const
+{
+    if (_dirtyFlags & TERRAIN_DIRTY_NORMAL_MATRIX)
+    {
+        _dirtyFlags &= ~TERRAIN_DIRTY_NORMAL_MATRIX;
+
+        getInverseWorldMatrix().transpose(&_normalMatrix);
+    }
+
+    return _normalMatrix;
+}
+
+const Matrix& Terrain::getWorldViewMatrix() const
+{
+    static Matrix worldView;
+
+    if (_node)
+        Matrix::multiply(_node->getViewMatrix(), getWorldMatrix(), &worldView);
+    else
+        worldView = getWorldMatrix(); // no node, so nothing to get view from
+
+    return worldView;
+}
+
+const Matrix& Terrain::getWorldViewProjectionMatrix() const
+{
+    static Matrix worldViewProj;
+
+    if (_node)
+        Matrix::multiply(_node->getViewProjectionMatrix(), getWorldMatrix(), &worldViewProj);
+    else
+        worldViewProj = getWorldMatrix(); // no node, so nothing to get viewProjection from
+
+    return worldViewProj;
+}
+
+float getDefaultHeight(unsigned int width, unsigned int height)
+{
+    // When terrain height is not specified, we'll use a default height of ~ 0.3 of the image dimensions
+    return ((width + height) * 0.5f) * DEFAULT_TERRAIN_HEIGHT_RATIO;
+}
+
+}

+ 376 - 429
gameplay/src/Terrain.h

@@ -1,429 +1,376 @@
-#ifndef TERRAIN_H_
-#define TERRAIN_H_
-
-#include "Transform.h"
-#include "Properties.h"
-#include "HeightField.h"
-#include "Texture.h"
-#include "BoundingBox.h"
-#include "TerrainPatch.h"
-
-namespace gameplay
-{
-
-class Node;
-class TerrainPatch;
-
-/**
- * Defines a Terrain that is capable of rendering large landscapes from 2D heightmap images.
- *
- * Terrains can be constructed from several different heightmap sources:
- *
- * 1. Basic intensity image (PNG), where the intensity of pixel represents the height of the
- *    terrain.
- * 2. 24-bit high precision heightmap image (PNG), which can be generated from a mesh using
- *    gameplay-encoder.
- * 3. 8-bit or 16-bit RAW heightmap image using PC byte ordering (little endian), which is
- *    compatible with many external tools such as World Machine, Unity and more. The file
- *    extension must be either .raw or .r16 for RAW files.
- *
- * Physics/collision is supported by setting a rigid body collision object on the Node that
- * the terrain is attached to. The collision shape should be specified using
- * PhysicsCollisionShape::heightfield(), which will utilize the internal height array of the
- * terrain to define the collision shape. Define a collision object in this way will allow
- * the terrain to automatically interact with other rigid bodies, characters and vehicles in
- * the scene.
- *
- * Surface detail is provided via texture splatting, where multiple texture layers can be added
- * along with blend maps to define how different layers blend with each other. These layers
- * can be defined in terrain properties files, as well as with the setLayer method. The number
- * of supported layers depends on the target hardware, although typically 2-3 levels is
- * sufficient. Multiple blend maps for different layers can be packed into different channels
- * of a single texture for more efficient texture utilization. Levels can be applied across
- * the entire terrain, or in more complex cases, for individual patches only.
- *
- * Surface lighting is achieved with either vertex normals or with a normal map. If a
- * normal map is used, it should be an object-space normal map containing normal vectors for
- * the entire terrain, encoded into the red, green and blue channels of the texture. This is
- * useful as a replacement for vertex normals, especially when using level-of-detail, since
- * it allows you to provide high quality normal vectors regardless of the tessellation or 
- * LOD of the terrain. This also eliminates lighting artifacts/popping from LOD changes,
- * which commonly occurs when vertex normals are used. A terrain normal map can only be
- * specified at creation time, since it requires omission of vertex normal information in
- * the generated terrain geometry data.
- *
- * Internally, Terrain is broken into smaller, more managable patches, which can be culled
- * separately for more efficient rendering. The size of the terrain patches can be controlled
- * via the patchSize property. Patches can be previewed by enabling the DEBUG_PATCHES flag
- * via the setFlag method. Other terrain behavior can also be enabled and disabled using terrain
- * flags.
- * 
- * Level of detail (LOD) is supported using a technique that is similar to texture mipmapping.
- * A distance-to-camera based test, using a simple screen-space error metric is used to decide
- * the appropriate LOD for a terrain patch. The number of LOD levels is 1 by default (which
- * means only the base level is used), but can be specified via the detailLevels property.
- * Using too large a number for detailLevels can result in excessive popping in the distance
- * for very hilly terrains, so a smaller number (2-3) often works best in these cases.
- *
- * Finally, when LOD is enabled, cracks can begin to appear between terrain patches of
- * different LOD levels. If the cracks are only minor (depends on your terrain topology
- * and tetures used), an acceptable appraoch might be to simply use a background clear 
- * color that closely matches your terrain to make the cracks much less visible. However,
- * often that is not acceptable, so the Terrain class also supports a simple solution called
- * "vertical skirts". When enabled (via the skirtScale parameter in the terrain file), a vertical
- * edge will extend down along the sides of all terrain patches, which fills in the crack.
- * This is a very fast approach as it adds only a small number of triangles per patch and requires
- * zero extra CPU time or draw calls, which are often needed for more complex stitching 
- * approaches. In practice, the skirts are often not noticable at all unless the LOD variation
- * is very large and the terrain is excessively hilly on the edge of a LOD transition.
- */
-class Terrain : public Ref, public Transform::Listener
-{
-    friend class Node;
-    friend class TerrainPatch;
-    friend class PhysicsController;
-    friend class PhysicsRigidBody;
-
-public:
-
-    /**
-     * Terrain flags.
-     */
-    enum Flags
-    {
-        /**
-         * Draw terrain patches different colors (off by default).
-         */
-        DEBUG_PATCHES = 1,
-
-        /**
-         * Enables view frustum culling (on by default).
-         *
-         * Frustum culling uses the scene's active camera. The terrain must be attached
-         * to a node that is within a scene for this to work.
-         */
-        FRUSTUM_CULLING = 2,
-
-         /**
-          * Enables level of detail (on by default).
-          *
-          * This flag enables or disables level of detail, however it does nothing if
-          * "detailLevels" was not set to a value greater than 1 in the terrain
-          * properties file at creation time.
-          */
-         LEVEL_OF_DETAIL = 8
-    };
-
-    /**
-     * Interface for various terrain-specific events that can be handled.
-     */
-    class Listener
-    {
-    public:
-
-        virtual ~Listener() { }
-
-        /**
-         * Fired when a material is updated for the terrain or a patch within it.
-         *
-         * This method can be handled to override material parameters for the terrain.
-         * Note that this method will usually be fired several times since there are
-         * normally separate materials defined per patch.
-         *
-         * @param terrain The terrain firing the event.
-         * @param material The new material.
-         */
-        virtual void materialUpdated(Terrain* terrain, Material* material) = 0;
-    };
-
-    /**
-     * Loads a Terrain from the given properties file.
-     *
-     * The specified properties file can contain a full terrain definition, including a 
-     * heightmap (PNG, RAW8, RAW16), level of detail information, patch size, layer texture
-     * details and vertical skirt size.
-     *
-     * @param path Path to a properties file describing the terrain.
-     *
-     * @return A new Terrain.
-     * @script{create}
-     */
-    static Terrain* create(const char* path);
-
-    /**
-     * Creates a new terrain definition from the configuration in the specified Properties object.
-     *
-     * @param properties Properties object containing the terrain definition.
-     *
-     * @return A new Terrain.
-     *
-     * @see create(const char*)
-     * @script{create}
-     */
-    static Terrain* create(Properties* properties);
-
-    /**
-     * Creates a terrain from the given heightfield.
-     *
-     * Terrain geometry is loaded from the given height array, using the specified parameters for
-     * size, patch size, detail levels and skirt scale.
-     *
-     * The newly created terrain increases the reference count of the HeightField.
-     *
-     * @param heightfield The heightfield object containing height data for the terrain.
-     * @param scale A scale to apply to the terrain along the X, Y and Z axes. The terrain and any associated
-     *      physics hegihtfield is scaled by this amount. Pass Vector3::one() to use the exact dimensions and heights
-     *      in the supplied height array.
-     * @param patchSize Size of terrain patches (number of quads).
-     * @param detailLevels Number of detail levels to generate for the terrain (a value of one generates only the base
-     *      level, resulting in no LOD at runtime.
-     * @param skirtScale A positive value indicates that vertical skirts should be generated at the specified
-     *      scale, which is relative to the height of the terrain. For example, a value of 0.5f indicates that
-     *      vertical skirts should extend down by half of the maximum height of the terrain. A value of zero
-     *      disables vertical skirts.
-     * @param normalMapPath Path to an object-space normal map to use for terrain lighting, instead of vertex normals.
-     *
-     * @return A new Terrain.
-     * @script{create}
-     */
-    static Terrain* create(HeightField* heightfield, const Vector3& scale = Vector3::one(), unsigned int patchSize = 32,  
-                           unsigned int detailLevels = 1, float skirtScale = 0.0f, const char* normalMapPath = NULL);
-
-    /**
-     * Sets the detail textures information for a terrain layer.
-     *
-     * A detail layer includes a color texture, a repeat count across the terrain for the texture and
-     * a region of the texture to use.
-     *
-     * Optionally, a layer can also include a blend texture, which is used to instruct the terrain how
-     * to blend the new layer with the layer underneath it. Blend maps use only a single channel of a 
-     * texture and are best supplied by packing the blend map for a layer into the alpha channel of
-     * the color texture. Blend maps are always stretched over the entire terrain 
-     *
-     * The lowest/base layer of the terrain should not include a blend map, since there is no lower
-     * level to blend with. All other layers should normally include a blend map. However, since no
-     * blend map will result in the texture completely masking the layer underneath it.
-     *
-     * Detail layers can be applied globally (to the entire terrain), or to one or more specific
-     * patches in the terrain. Patches are specified by row and column number, which is dependent
-     * on the patch size configuration of your terrain. For layers that span the entire terrain, 
-     * the repeat count is relative to the entire terrain. For layers that span only specific
-     * patches, the repeat count is relative to those patches only.
-     *
-     * @param index Layer index number. Layer indexes do not neccessarily need to be sequential and
-     *      are used simply to uinquely identify layers, where higher numbers specificy higher-level
-     *      layers.
-     * @param texturePath Path to the color texture for this layer.
-     * @param textureRepeat Repeat count for the color texture across the terrain or patches.
-     * @param blendPath Path to the blend texture for this layer (optional).
-     * @param blendChannel Channel of the blend texture to sample for the blend map (0 == R, 1 == G, 2 == B, 3 == A).
-     * @param row Specifies the row index of patches to use this layer (optional, -1 means all rows).
-     * @param column Specifies the column index of patches to use this layer (optional, -1 means all columns).
-     *
-     * @return True if the layer was successfully set, false otherwise. The most common reason for failure is an
-     *      invalid texture path.
-     *
-     * @script{ignore}
-     */
-    bool setLayer(int index,
-                  const char* texturePath, const Vector2& textureRepeat = Vector2::one(),
-                  const char* blendPath = NULL, int blendChannel = 0, 
-                  int row = -1, int column = -1);
-
-    /**
-     * Returns the node that this terrain is bound to.
-     *
-     * @return The node this terrain is bound to, or NULL if the terrain is not bound to a node.
-     */
-    Node* getNode() const;
-
-    /**
-     * Determines if the specified terrain flag is currently set.
-     */
-    bool isFlagSet(Flags flag) const;
-
-    /**
-     * Enables or disables the specified terrain flag.
-     *
-     * @param flag The terrain flag to set.
-     * @param on True to turn the flag on, false to turn it off.
-     */
-    void setFlag(Flags flag, bool on);
-
-    /**
-     * Returns the total number of terrain patches.
-     *
-     * @return The number of terrain patches.
-     */
-    unsigned int getPatchCount() const;
-
-    /**
-     * Returns the number of patches that are currently visible from the scene camera's point of view.
-     *
-     * If the terrain is not attached to a scene, or if there is no active scene camera, this method
-     * returns zero.
-     *
-     * This method is not exact - it may return false positives since it only determines if the
-     * bounding box of terrain patches intersect the view frustum. Should be used for debug 
-     * purposes only.
-     *
-     * @return The number of currently visible patches.
-     */
-    unsigned int getVisiblePatchCount() const;
-
-    /**
-     * Returns the total number of triangles for this terrain at the base LOD.
-     *
-     * @return The total triangle count for the terrain at the base LOD.
-     */
-    unsigned int getTriangleCount() const;
-
-    /**
-     * Returns the number of currently visible triangles, taking LOD and view frustum
-     * (if enabled) into consideration.
-     *
-     * @return The current visible triangle count.
-     */
-    unsigned int getVisibleTriangleCount() const;
-
-    /**
-     * Returns the local bounding box for this terrain.
-     *
-     * @return The local bounding box for the terrain.
-     */
-    const BoundingBox& getBoundingBox() const;
-
-    /**
-     * Returns the world-space height of the terrain at the specified position on the X,Z plane.
-     *
-     * The specified X and Z coordinates should be in world units and may fall between height values.
-     * In this case, an interpolated value will be returned between neighboring heightfield heights.
-     * If the specified point lies outside of the terrain, it is clamped to the terrain boundaries.
-     *
-     * @param x The X coordinate, in world space.
-     * @param z The Z coordinate, in world space.
-     *
-     * @return The height at the specified point, clamped to the boundaries of the terrain.
-     */
-    float getHeight(float x, float z) const;
-
-    /**
-     * Draws the terrain.
-     *
-     * @param wireframe True to draw the terrain as wireframe, false to draw it solid (default).
-     * @return The number of draw call taken to drawn the terrain
-     */
-    unsigned int draw(bool wireframe = false);
-
-    /**
-     * @see Transform::Listener::transformChanged.
-     *
-     * Internal use only.
-     *
-     * @script{ignore}
-     */
-    void transformChanged(Transform* transform, long cookie);
-
-    /**
-     * Adds a listener to this terrain.
-     *
-     * @param listener Listener to start receiving terrain events.
-     */
-    void addListener(Terrain::Listener* listener);
-
-    /**
-     * Removes a listener from this terrain.
-     *
-     * @param listener Listener to stop receiving terrain events.
-     */
-    void removeListener(Terrain::Listener* listener);
-
-    /**
-     * Returns the world matrix of the terrain, factoring in terrain local scaling.
-     *
-     * @return The world matrix for the terrain.
-     */
-    const Matrix& getWorldMatrix() const;
-
-    /**
-     * Returns the terrain's inverse world matrix.
-     *
-     * @return The inverse world matrix for the terrain.
-     */
-    const Matrix& getInverseWorldMatrix() const;
-
-    /**
-     * Returns a matrix to be used for transforming normal vectors for the terrain.
-     *
-     * @return The matrix used for normal vector transformation for the terrain.
-     */
-    const Matrix& getNormalMatrix() const;
-
-    /**
-     * Returns the world view matrix for the terrain, factoring in terrain local scaling.
-     *
-     * @return The world-view matrix for the terrain.
-     */
-    const Matrix& getWorldViewMatrix() const;
-
-    /**
-     * Returns the world view projection matrix for the terrain, factoring in terrain local scaling.
-     *
-     * @return The world-view-projection matrix for the terrain.
-     */
-    const Matrix& getWorldViewProjectionMatrix() const;
-
-private:
-
-    /**
-     * Constructor.
-     */
-    Terrain();
-
-    /**
-     * Hidden copy constructor.
-     */
-    Terrain(const Terrain&);
-
-    /**
-     * Hidden copy assignment operator.
-     */
-    Terrain& operator=(const Terrain&);
-
-    /**
-     * Destructor.
-     */
-    ~Terrain();
-
-    /**
-     * Internal method for creating terrain.
-     */
-    static Terrain* create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath, Properties* properties);
-
-    /**
-     * Internal method for creating terrain.
-     */
-    static Terrain* create(const char* path, Properties* properties);
-
-    /**
-     * Sets the node that the terrain is attached to.
-     */
-    void setNode(Node* node);
-
-    HeightField* _heightfield;
-    Node* _node;
-    std::vector<TerrainPatch*> _patches;
-    Vector3 _localScale;
-    Texture::Sampler* _normalMap;
-    unsigned int _flags;
-    mutable Matrix _worldMatrix;
-    mutable Matrix _inverseWorldMatrix;
-    mutable Matrix _normalMatrix;
-    mutable unsigned int _dirtyFlags;
-    BoundingBox _boundingBox;
-    std::vector<Terrain::Listener*> _listeners;
-};
-
-}
-
-#endif
+#ifndef TERRAIN_H_
+#define TERRAIN_H_
+
+#include "Transform.h"
+#include "Properties.h"
+#include "HeightField.h"
+#include "Texture.h"
+#include "BoundingBox.h"
+#include "TerrainPatch.h"
+
+namespace gameplay
+{
+
+class Node;
+class TerrainPatch;
+
+/**
+ * Defines a Terrain that is capable of rendering large landscapes from 2D heightmap images.
+ *
+ * Terrains can be constructed from several different heightmap sources:
+ *
+ * 1. Basic intensity image (PNG), where the intensity of pixel represents the height of the
+ *    terrain.
+ * 2. 24-bit high precision heightmap image (PNG), which can be generated from a mesh using
+ *    gameplay-encoder.
+ * 3. 8-bit or 16-bit RAW heightmap image using PC byte ordering (little endian), which is
+ *    compatible with many external tools such as World Machine, Unity and more. The file
+ *    extension must be either .raw or .r16 for RAW files.
+ *
+ * Physics/collision is supported by setting a rigid body collision object on the Node that
+ * the terrain is attached to. The collision shape should be specified using
+ * PhysicsCollisionShape::heightfield(), which will utilize the internal height array of the
+ * terrain to define the collision shape. Define a collision object in this way will allow
+ * the terrain to automatically interact with other rigid bodies, characters and vehicles in
+ * the scene.
+ *
+ * Surface detail is provided via texture splatting, where multiple texture layers can be added
+ * along with blend maps to define how different layers blend with each other. These layers
+ * can be defined in terrain properties files, as well as with the setLayer method. The number
+ * of supported layers depends on the target hardware, although typically 2-3 levels is
+ * sufficient. Multiple blend maps for different layers can be packed into different channels
+ * of a single texture for more efficient texture utilization. Levels can be applied across
+ * the entire terrain, or in more complex cases, for individual patches only.
+ *
+ * Surface lighting is achieved with either vertex normals or with a normal map. If a
+ * normal map is used, it should be an object-space normal map containing normal vectors for
+ * the entire terrain, encoded into the red, green and blue channels of the texture. This is
+ * useful as a replacement for vertex normals, especially when using level-of-detail, since
+ * it allows you to provide high quality normal vectors regardless of the tessellation or
+ * LOD of the terrain. This also eliminates lighting artifacts/popping from LOD changes,
+ * which commonly occurs when vertex normals are used. A terrain normal map can only be
+ * specified at creation time, since it requires omission of vertex normal information in
+ * the generated terrain geometry data.
+ *
+ * Internally, Terrain is broken into smaller, more manageable patches, which can be culled
+ * separately for more efficient rendering. The size of the terrain patches can be controlled
+ * via the patchSize property. Patches can be previewed by enabling the DEBUG_PATCHES flag
+ * via the setFlag method. Other terrain behavior can also be enabled and disabled using terrain
+ * flags.
+ *
+ * Level of detail (LOD) is supported using a technique that is similar to texture mipmapping.
+ * A distance-to-camera based test, using a simple screen-space error metric is used to decide
+ * the appropriate LOD for a terrain patch. The number of LOD levels is 1 by default (which
+ * means only the base level is used), but can be specified via the detailLevels property.
+ * Using too large a number for detailLevels can result in excessive popping in the distance
+ * for very hilly terrains, so a smaller number (2-3) often works best in these cases.
+ *
+ * Finally, when LOD is enabled, cracks can begin to appear between terrain patches of
+ * different LOD levels. If the cracks are only minor (depends on your terrain topology
+ * and textures used), an acceptable approach might be to simply use a background clear
+ * color that closely matches your terrain to make the cracks much less visible. However,
+ * often that is not acceptable, so the Terrain class also supports a simple solution called
+ * "vertical skirts". When enabled (via the skirtScale parameter in the terrain file), a vertical
+ * edge will extend down along the sides of all terrain patches, which fills in the crack.
+ * This is a very fast approach as it adds only a small number of triangles per patch and requires
+ * zero extra CPU time or draw calls, which are often needed for more complex stitching
+ * approaches. In practice, the skirts are often not noticeable at all unless the LOD variation
+ * is very large and the terrain is excessively hilly on the edge of a LOD transition.
+ */
+class Terrain : public Ref, public Transform::Listener
+{
+    friend class Node;
+    friend class TerrainPatch;
+    friend class PhysicsController;
+    friend class PhysicsRigidBody;
+
+public:
+
+    /**
+     * Terrain flags.
+     */
+    enum Flags
+    {
+        /**
+         * Draw terrain patches different colors (off by default).
+         */
+        DEBUG_PATCHES = 1,
+
+        /**
+         * Enables view frustum culling (on by default).
+         *
+         * Frustum culling uses the scene's active camera. The terrain must be attached
+         * to a node that is within a scene for this to work.
+         */
+        FRUSTUM_CULLING = 2,
+
+         /**
+          * Enables level of detail (on by default).
+          *
+          * This flag enables or disables level of detail, however it does nothing if
+          * "detailLevels" was not set to a value greater than 1 in the terrain
+          * properties file at creation time.
+          */
+         LEVEL_OF_DETAIL = 8
+    };
+
+    /**
+     * Loads a Terrain from the given properties file.
+     *
+     * The specified properties file can contain a full terrain definition, including a
+     * heightmap (PNG, RAW8, RAW16), level of detail information, patch size, layer texture
+     * details and vertical skirt size.
+     *
+     * @param path Path to a properties file describing the terrain.
+     *
+     * @return A new Terrain.
+     * @script{create}
+     */
+    static Terrain* create(const char* path);
+
+    /**
+     * Creates a new terrain definition from the configuration in the specified Properties object.
+     *
+     * @param properties Properties object containing the terrain definition.
+     *
+     * @return A new Terrain.
+     *
+     * @see create(const char*)
+     * @script{create}
+     */
+    static Terrain* create(Properties* properties);
+
+    /**
+     * Creates a terrain from the given heightfield.
+     *
+     * Terrain geometry is loaded from the given height array, using the specified parameters for
+     * size, patch size, detail levels and skirt scale.
+     *
+     * The newly created terrain increases the reference count of the HeightField.
+     *
+     * @param heightfield The heightfield object containing height data for the terrain.
+     * @param scale A scale to apply to the terrain along the X, Y and Z axes. The terrain and any associated
+     *      physics heightfield is scaled by this amount. Pass Vector3::one() to use the exact dimensions and heights
+     *      in the supplied height array.
+     * @param patchSize Size of terrain patches (number of quads).
+     * @param detailLevels Number of detail levels to generate for the terrain (a value of one generates only the base
+     *      level, resulting in no LOD at runtime.
+     * @param skirtScale A positive value indicates that vertical skirts should be generated at the specified
+     *      scale, which is relative to the height of the terrain. For example, a value of 0.5f indicates that
+     *      vertical skirts should extend down by half of the maximum height of the terrain. A value of zero
+     *      disables vertical skirts.
+     * @param normalMapPath Path to an object-space normal map to use for terrain lighting, instead of vertex normals.
+     *
+     * @return A new Terrain.
+     * @script{create}
+     */
+    static Terrain* create(HeightField* heightfield, const Vector3& scale = Vector3::one(), unsigned int patchSize = 32,
+                           unsigned int detailLevels = 1, float skirtScale = 0.0f, const char* normalMapPath = NULL);
+
+    /**
+     * Returns the node that this terrain is bound to.
+     *
+     * @return The node this terrain is bound to, or NULL if the terrain is not bound to a node.
+     */
+    Node* getNode() const;
+
+    /**
+     * Determines if the specified terrain flag is currently set.
+     */
+    bool isFlagSet(Flags flag) const;
+
+    /**
+     * Enables or disables the specified terrain flag.
+     *
+     * @param flag The terrain flag to set.
+     * @param on True to turn the flag on, false to turn it off.
+     */
+    void setFlag(Flags flag, bool on);
+
+    /**
+     * Gets the total number of terrain patches.
+     *
+     * @return The number of terrain patches.
+     */
+    unsigned int getPatchCount() const;
+
+    /**
+     * Gets a terrain patch
+     */
+    TerrainPatch* getPatch(unsigned int index) const;
+
+    /**
+     * Gets the local bounding box for this terrain.
+     *
+     * @return The local bounding box for the terrain.
+     */
+    const BoundingBox& getBoundingBox() const;
+
+    /**
+     * Gets the world-space height of the terrain at the specified position on the X,Z plane.
+     *
+     * The specified X and Z coordinates should be in world units and may fall between height values.
+     * In this case, an interpolated value will be returned between neighboring heightfield heights.
+     * If the specified point lies outside of the terrain, it is clamped to the terrain boundaries.
+     *
+     * @param x The X coordinate, in world space.
+     * @param z The Z coordinate, in world space.
+     *
+     * @return The height at the specified point, clamped to the boundaries of the terrain.
+     */
+    float getHeight(float x, float z) const;
+
+    /**
+     * Draws the terrain.
+     *
+     * @param wireframe True to draw the terrain as wireframe, false to draw it solid (default).
+     * @return The number of draw calls taken to drawn the terrain
+     */
+    unsigned int draw(bool wireframe = false);
+
+    /**
+    * Sets the detail textures information for a terrain layer.
+    *
+    * A detail layer includes a color texture, a repeat count across the terrain for the texture and
+    * a region of the texture to use.
+    *
+    * Optionally, a layer can also include a blend texture, which is used to instruct the terrain how
+    * to blend the new layer with the layer underneath it. Blend maps use only a single channel of a
+    * texture and are best supplied by packing the blend map for a layer into the alpha channel of
+    * the color texture. Blend maps are always stretched over the entire terrain
+    *
+    * The lowest/base layer of the terrain should not include a blend map, since there is no lower
+    * level to blend with. All other layers should normally include a blend map. However, since no
+    * blend map will result in the texture completely masking the layer underneath it.
+    *
+    * Detail layers can be applied globally (to the entire terrain), or to one or more specific
+    * patches in the terrain. Patches are specified by row and column number, which is dependent
+    * on the patch size configuration of your terrain. For layers that span the entire terrain,
+    * the repeat count is relative to the entire terrain. For layers that span only specific
+    * patches, the repeat count is relative to those patches only.
+    *
+    * @param index Layer index number. Layer indexes do not necessarily need to be sequential and
+    *      are used simply to uniquely identify layers, where higher numbers specify higher-level
+    *      layers.
+    * @param texturePath Path to the color texture for this layer.
+    * @param textureRepeat Repeat count for the color texture across the terrain or patches.
+    * @param blendPath Path to the blend texture for this layer (optional).
+    * @param blendChannel Channel of the blend texture to sample for the blend map (0 == R, 1 == G, 2 == B, 3 == A).
+    * @param row Specifies the row index of patches to use this layer (optional, -1 means all rows).
+    * @param column Specifies the column index of patches to use this layer (optional, -1 means all columns).
+    *
+    * @return True if the layer was successfully set, false otherwise. The most common reason for failure is an
+    *      invalid texture path.
+    *
+    * @script{ignore}
+    */
+    bool setLayer(int index,
+        const char* texturePath, const Vector2& textureRepeat = Vector2::one(),
+        const char* blendPath = NULL, int blendChannel = 0,
+        int row = -1, int column = -1);
+
+private:
+
+    /**
+     * Constructor.
+     */
+    Terrain();
+
+    /**
+     * Hidden copy constructor.
+     */
+    Terrain(const Terrain&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    Terrain& operator=(const Terrain&);
+
+    /**
+     * Destructor.
+     */
+    ~Terrain();
+
+    /**
+     * Internal method for creating terrain.
+     */
+    static Terrain* create(HeightField* heightfield, const Vector3& scale, unsigned int patchSize, unsigned int detailLevels, float skirtScale, const char* normalMapPath, Properties* properties);
+
+    /**
+     * Internal method for creating terrain.
+     */
+    static Terrain* create(const char* path, Properties* properties);
+
+    /**
+     * Sets the node that the terrain is attached to.
+     */
+    void setNode(Node* node);
+
+    /**
+    * @see Transform::Listener::transformChanged.
+    *
+    * Internal use only.
+    *
+    * @script{ignore}
+    */
+    void transformChanged(Transform* transform, long cookie);
+
+    /**
+    * Returns the world matrix of the terrain, factoring in terrain local scaling.
+    *
+    * @return The world matrix for the terrain.
+    */
+    const Matrix& getWorldMatrix() const;
+
+    /**
+    * Returns the terrain's inverse world matrix.
+    *
+    * @return The inverse world matrix for the terrain.
+    */
+    const Matrix& getInverseWorldMatrix() const;
+
+    /**
+    * Returns a matrix to be used for transforming normal vectors for the terrain.
+    *
+    * @return The matrix used for normal vector transformation for the terrain.
+    */
+    const Matrix& getNormalMatrix() const;
+
+    /**
+    * Returns the world view matrix for the terrain, factoring in terrain local scaling.
+    *
+    * @return The world-view matrix for the terrain.
+    */
+    const Matrix& getWorldViewMatrix() const;
+
+    /**
+    * Returns the world view projection matrix for the terrain, factoring in terrain local scaling.
+    *
+    * @return The world-view-projection matrix for the terrain.
+    */
+    const Matrix& getWorldViewProjectionMatrix() const;
+
+    /**
+     * Returns the local bounding box for this patch, at the base LOD level.
+     */
+    BoundingBox getBoundingBox(bool worldSpace) const;
+
+    HeightField* _heightfield;
+    Node* _node;
+    std::vector<TerrainPatch*> _patches;
+    Vector3 _localScale;
+    Texture::Sampler* _normalMap;
+    unsigned int _flags;
+    mutable Matrix _worldMatrix;
+    mutable Matrix _inverseWorldMatrix;
+    mutable Matrix _normalMatrix;
+    mutable unsigned int _dirtyFlags;
+    BoundingBox _boundingBox;
+    unsigned int _directionalLightCount;
+    unsigned int _pointLightCount;
+    unsigned int _spotLightCount;
+};
+
+}
+
+#endif

+ 127 - 79
gameplay/src/TerrainPatch.cpp

@@ -22,8 +22,13 @@ float calculateHeight(float* heights, unsigned int width, unsigned int height, u
  */
 template <class T> T clamp(T value, T min, T max) { return value < min ? min : (value > max ? max : value); }
 
+#define TERRAINPATCH_DIRTY_MATERIAL 1
+#define TERRAINPATCH_DIRTY_BOUNDS 2
+#define TERRAINPATCH_DIRTY_LEVEL 4
+#define TERRAINPATCH_DIRTY_ALL (TERRAINPATCH_DIRTY_MATERIAL | TERRAINPATCH_DIRTY_BOUNDS | TERRAINPATCH_DIRTY_LEVEL)
+
 TerrainPatch::TerrainPatch() :
-    _terrain(NULL), _row(0), _column(0), _materialDirty(true)
+_terrain(NULL), _row(0), _column(0), _camera(NULL), _level(0), _bits(TERRAINPATCH_DIRTY_ALL)
 {
 }
 
@@ -44,11 +49,11 @@ TerrainPatch::~TerrainPatch()
 }
 
 TerrainPatch* TerrainPatch::create(Terrain* terrain,
-    unsigned int row, unsigned int column,
-    float* heights, unsigned int width, unsigned int height,
-    unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
-    float xOffset, float zOffset,
-    unsigned int maxStep, float verticalSkirtSize)
+                                   unsigned int row, unsigned int column,
+                                   float* heights, unsigned int width, unsigned int height,
+                                   unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
+                                   float xOffset, float zOffset,
+                                   unsigned int maxStep, float verticalSkirtSize)
 {
     // Create patch
     TerrainPatch* patch = new TerrainPatch();
@@ -73,14 +78,37 @@ TerrainPatch* TerrainPatch::create(Terrain* terrain,
         bounds.min.set(bounds.min.x * localScale.x, bounds.min.y * localScale.y, bounds.min.z * localScale.z);
         bounds.max.set(bounds.max.x * localScale.x, bounds.max.y * localScale.y, bounds.max.z * localScale.z);
     }
-
     return patch;
 }
 
+unsigned int TerrainPatch::getMaterialCount() const
+{
+    return _levels.size();
+}
+
+Material* TerrainPatch::getMaterial(int index) const
+{
+    if (index == -1)
+    {
+        Scene* scene = _terrain->_node ? _terrain->_node->getScene() : NULL;
+        Camera* camera = scene ? scene->getActiveCamera() : NULL;
+        if (!camera)
+        {
+            _level = const_cast<TerrainPatch*>(this)->computeLOD(camera, getBoundingBox(true));
+        }
+        else
+        {
+            _level = 0;
+        }
+        return _levels[_level]->model->getMaterial();
+    }
+    return _levels[index]->model->getMaterial();
+}
+
 void TerrainPatch::addLOD(float* heights, unsigned int width, unsigned int height,
-    unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
-    float xOffset, float zOffset,
-    unsigned int step, float verticalSkirtSize)
+                          unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
+                          float xOffset, float zOffset,
+                          unsigned int step, float verticalSkirtSize)
 {
     // Allocate vertex data for this patch
     unsigned int patchWidth;
@@ -426,17 +454,17 @@ bool TerrainPatch::setLayer(int index, const char* texturePath, const Vector2& t
 
     _layers.insert(layer);
 
-    _materialDirty = true;
+    _bits |= TERRAINPATCH_DIRTY_MATERIAL;
 
     return true;
 }
 
 bool TerrainPatch::updateMaterial()
 {
-    if (!_materialDirty)
+    if (!(_bits & TERRAINPATCH_DIRTY_MATERIAL))
         return true;
 
-    _materialDirty = false;
+    _bits &= ~TERRAINPATCH_DIRTY_MATERIAL;
 
     for (size_t i = 0, count = _levels.size(); i < count; ++i)
     {
@@ -447,6 +475,7 @@ bool TerrainPatch::updateMaterial()
         std::ostringstream defines;
         defines << "LAYER_COUNT " << _layers.size();
         defines << ";SAMPLER_COUNT " << _samplers.size();
+
         if (_terrain->isFlagSet(Terrain::DEBUG_PATCHES))
             defines << ";DEBUG_PATCHES";
         if (_terrain->_normalMap)
@@ -474,23 +503,25 @@ bool TerrainPatch::updateMaterial()
             }
         }
 
+        if (_terrain->_directionalLightCount > 0)
+            defines << ";DIRECTIONAL_LIGHT_COUNT " << _terrain->_directionalLightCount;
+        if (_terrain->_pointLightCount > 0)
+            defines << ";POINT_LIGHT_COUNT " << _terrain->_pointLightCount;
+        if (_terrain->_spotLightCount > 0)
+            defines << ";SPOT_LIGHT_COUNT " << _terrain->_spotLightCount;
+
         Material* material = Material::create(TERRAIN_VSH, TERRAIN_FSH, defines.str().c_str());
         if (!material)
             return false;
+
         material->getStateBlock()->setCullFace(true);
         material->getStateBlock()->setDepthTest(true);
 
         // Set material parameter bindings
         material->getParameter("u_worldViewProjectionMatrix")->bindValue(_terrain, &Terrain::getWorldViewProjectionMatrix);
-        if (_terrain->_normalMap)
-            material->getParameter("u_normalMap")->setValue(_terrain->_normalMap);
-        else
-            material->getParameter("u_normalMatrix")->bindValue(_terrain, &Terrain::getNormalMatrix);
-        material->getParameter("u_ambientColor")->bindValue(this, &TerrainPatch::getAmbientColor);
-        material->getParameter("u_lightColor")->setValue(Vector3::one());
-        material->getParameter("u_lightDirection")->setValue(Vector3(0, -1, 0));
+
         if (_layers.size() > 0)
-            material->getParameter("u_samplers")->setValue((const Texture::Sampler**)&_samplers[0], (unsigned int)_samplers.size());
+            material->getParameter("u_surfaceLayerMaps")->setValue((const Texture::Sampler**)&_samplers[0], (unsigned int)_samplers.size());
 
         if (_terrain->isFlagSet(Terrain::DEBUG_PATCHES))
         {
@@ -498,10 +529,33 @@ bool TerrainPatch::updateMaterial()
             material->getParameter("u_column")->setValue((float)_column);
         }
 
-        // Fire terrain listeners
-        for (size_t j = 0, lcount = _terrain->_listeners.size(); j < lcount; ++j)
+        if (_terrain->_directionalLightCount > 0 || _terrain->_pointLightCount > 0 || _terrain->_spotLightCount > 0)
+        {
+            material->getParameter("u_ambientColor")->bindValue(this, &TerrainPatch::getAmbientColor);
+            if (_terrain->_normalMap)
+                material->getParameter("u_normalMap")->setValue(_terrain->_normalMap);
+            else
+                material->getParameter("u_normalMatrix")->bindValue(_terrain, &Terrain::getNormalMatrix);
+        }
+
+        // Add all the parameters from the old material to the new ones render state
+        Material* prevMaterial = _levels[i]->model->getMaterial();
+        if (prevMaterial)
         {
-            _terrain->_listeners[j]->materialUpdated(_terrain, material);
+            RenderState* prevStates[3] = { prevMaterial, prevMaterial->getTechnique(), prevMaterial->getTechnique()->getPassByIndex(0) };
+            RenderState* newStates[3] = { material, material->getTechnique(), material->getTechnique()->getPassByIndex(0) };
+            for (unsigned int i = 0; i < 3; ++i)
+            {
+                for (unsigned int j = 0; j < prevStates[i]->getParameterCount(); ++j)
+                {
+                    newStates[i]->addParameter(prevStates[i]->getParameterByIndex(j));
+                    if (!_terrain->isFlagSet(Terrain::DEBUG_PATCHES))
+                    {
+                        newStates[i]->removeParameter("u_row");
+                        newStates[i]->removeParameter("u_column");
+                    }
+                }
+            }
         }
 
         // Set material on this lod level
@@ -531,84 +585,65 @@ unsigned int TerrainPatch::draw(bool wireframe)
         return 0;
 
     // Compute the LOD level from the camera's perspective
-    size_t lod = computeLOD(camera, bounds);
+    _level = computeLOD(camera, bounds);
 
     // Draw the model for the current LOD
-    return _levels[lod]->model->draw(wireframe);
+    return _levels[_level]->model->draw(wireframe);
 }
 
-bool TerrainPatch::isVisible() const
-{
-    // If frustum culling is disabled, assume the patch is always visible
-    if ((_terrain->_flags & Terrain::FRUSTUM_CULLING) == 0)
-        return true;
-
-    Scene* scene = _terrain->_node ? _terrain->_node->getScene() : NULL;
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (!camera)
-        return false;
-
-    // Does the current camera view frustum intersect our world bounds?
-    return camera->getFrustum().intersects(getBoundingBox(true));
-}
-
-unsigned int TerrainPatch::getTriangleCount() const
-{
-    // Patches are made up of a single mesh part using triangle strips
-    return _levels[0]->model->getMesh()->getPart(0)->getIndexCount() - 2;
-}
-
-unsigned int TerrainPatch::getVisibleTriangleCount() const
-{
-    Scene* scene = _terrain->_node ? _terrain->_node->getScene() : NULL;
-    Camera* camera = scene ? scene->getActiveCamera() : NULL;
-    if (!camera)
-        return 0;
-
-    // Does the current camera intersect this patch at all?
-    BoundingBox bounds = getBoundingBox(true);
-    if (_terrain->_flags & Terrain::FRUSTUM_CULLING)
-    {
-        if (!camera->getFrustum().intersects(bounds))
-            return 0;
-    }
-
-    // Return the triangle count of the LOD level depending on the camera
-    size_t lod = computeLOD(camera, bounds);
-    return _levels[lod]->model->getMesh()->getPart(0)->getIndexCount() - 2;
-}
-
-BoundingBox TerrainPatch::getBoundingBox(bool worldSpace) const
+const BoundingBox& TerrainPatch::getBoundingBox(bool worldSpace) const
 {
     if (!worldSpace)
         return _boundingBox;
 
+    if (!(_bits & TERRAINPATCH_DIRTY_BOUNDS))
+        return _boundingBoxWorld;
+
+    _bits &= ~TERRAINPATCH_DIRTY_BOUNDS;
+
     // Apply a world-space transformation to our bounding box
-    BoundingBox bounds(_boundingBox);
+    _boundingBoxWorld.set(_boundingBox);
 
     // Transform the bounding box by the terrain node's world transform.
     // We don't use Terrain::getWorldMatrix because that returns a matrix
     // that has terrain->_localScale factored in - and our patche's bounding
     // box already has local scale factored in.
     if (_terrain->_node)
-        bounds.transform(_terrain->_node->getWorldMatrix());
+        _boundingBoxWorld.transform(_terrain->_node->getWorldMatrix());
 
-    return bounds;
+    return _boundingBoxWorld;
 }
 
-const Vector3& TerrainPatch::getAmbientColor() const
+void TerrainPatch::cameraChanged(Camera* camera)
 {
-    Scene* scene = _terrain->_node ? _terrain->_node->getScene() : NULL;
-    return scene ? scene->getAmbientColor() : Vector3::zero();
+    _bits |= TERRAINPATCH_DIRTY_LEVEL;
 }
 
-size_t TerrainPatch::computeLOD(Camera* camera, const BoundingBox& worldBounds) const
+unsigned int TerrainPatch::computeLOD(Camera* camera, const BoundingBox& worldBounds) 
 {
+    if (camera != _camera)
+    {
+        if (_camera != NULL)
+        {
+            _camera->removeListener(this);
+            _camera->release();
+        }
+        _camera = camera;
+        _camera->addRef();
+        _camera->addListener(this);
+        _bits |= TERRAINPATCH_DIRTY_LEVEL;
+    }
+
+    // base level
     if (!_terrain->isFlagSet(Terrain::LEVEL_OF_DETAIL) || _levels.size() == 0)
-        return 0; // base level
+        return 0;
+
+    if (!(_bits & TERRAINPATCH_DIRTY_LEVEL))
+        return _level;
 
-    // Compute LOD to use based on very simple distance metric.
-    // TODO: Optimize this.
+    _bits &= ~TERRAINPATCH_DIRTY_LEVEL;
+
+    // Compute LOD to use based on very simple distance metric. TODO: Optimize me.
     Game* game = Game::getInstance();
     Rectangle vp(0, 0, game->getWidth(), game->getHeight());
     Vector3 corners[8];
@@ -638,7 +673,20 @@ size_t TerrainPatch::computeLOD(Camera* camera, const BoundingBox& worldBounds)
     size_t lod = (size_t)error;
     lod = std::max(lod, (size_t)0);
     lod = std::min(lod, maxLod);
-    return lod;
+    _level = lod;
+
+    return _level;
+}
+
+const Vector3& TerrainPatch::getAmbientColor() const
+{
+    Scene* scene = _terrain->_node ? _terrain->_node->getScene() : NULL;
+    return scene ? scene->getAmbientColor() : Vector3::zero();
+}
+
+void TerrainPatch::setMaterialDirty()
+{
+    _bits |= TERRAINPATCH_DIRTY_MATERIAL;
 }
 
 float calculateHeight(float* heights, unsigned int width, unsigned int height, unsigned int x, unsigned int z)

+ 141 - 154
gameplay/src/TerrainPatch.h

@@ -1,154 +1,141 @@
-#ifndef TERRAINPATCH_H_
-#define TERRAINPATCH_H_
-
-#include "Model.h"
-#include "Camera.h"
-
-namespace gameplay
-{
-
-class Terrain;
-
-/**
- * Represents a single patch for a Terrain.
- *
- * This is an internal class used exclusively by Terrain.
- *
- * @script{ignore}
- */
-class TerrainPatch
-{
-    friend class Terrain;
-
-private:
-
-    struct Layer
-    {
-        Layer();
-        Layer(const Layer&);
-        ~Layer();
-        Layer& operator=(const Layer&);
-
-        int index;
-        int row;
-        int column;
-        int textureIndex;
-        Vector2 textureRepeat;
-        int blendIndex;
-        int blendChannel;
-    };
-
-    struct Level
-    {
-        Model* model;
-
-        Level();
-    };
-
-    struct LayerCompare
-    {
-        bool operator() (const Layer* lhs, const Layer* rhs) const;
-    };
-
-    /**
-     * Constructor.
-     */
-    TerrainPatch();
-
-    /**
-     * Hidden copy constructor.
-     */
-    TerrainPatch(const TerrainPatch&);
-
-    /**
-     * Hidden copy assignment operator.
-     */
-    TerrainPatch& operator=(const TerrainPatch&);
-
-    /**
-     * Destructor.
-     */
-    ~TerrainPatch();
-
-    /**
-     * Internal method to create new terrain patch.
-     */
-    static TerrainPatch* create(Terrain* terrain, 
-                                unsigned int row, unsigned int column,
-                                float* heights, unsigned int width, unsigned int height,
-                                unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
-                                float xOffset, float zOffset, unsigned int maxStep, float verticalSkirtSize);
-
-    /**
-     * Adds a single LOD level to the terrain patch.
-     */
-    void addLOD(float* heights, unsigned int width, unsigned int height,
-                unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
-                float xOffset, float zOffset, unsigned int step, float verticalSkirtSize);
-
-    /**
-     * Sets details for a layer of this patch.
-     */
-    bool setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel);
-
-    /**
-     * Adds a sampler to the patch.
-     */
-    int addSampler(const char* path);
-
-    /**
-     * Deletes the specified layer.
-     */
-    void deleteLayer(Layer* layer);
-
-    /**
-     * Determines whether this patch is current visible by the scene's active camera.
-     */
-    bool isVisible() const;
-
-    /**
-     * Returns the triangle count of the base LOD level of this terrain patch.
-     */
-    unsigned int getTriangleCount() const;
-
-    /**
-     * Returns the currently visible triangle count, taking the current LOD into account.
-     */
-    unsigned int getVisibleTriangleCount() const;
-
-    /**
-     * Draws the terrain patch.
-     */
-    unsigned int draw(bool wireframe);
-
-    /**
-     * Updates the material for the patch.
-     */
-    bool updateMaterial();
-
-    /**
-     * Computes the current LOD for this patch, from the viewpoint of the specified camera.
-     */
-    size_t computeLOD(Camera* camera, const BoundingBox& worldBounds) const;
-
-    /**
-     * Returns the local bounding box for this patch, at the base LOD level.
-     */
-    BoundingBox getBoundingBox(bool worldSpace) const;
-
-    const Vector3& getAmbientColor() const;
-
-    Terrain* _terrain;
-    std::vector<Level*> _levels;
-    unsigned int _row;
-    unsigned int _column;
-    std::set<Layer*, LayerCompare> _layers;
-    std::vector<Texture::Sampler*> _samplers;
-    bool _materialDirty;
-    BoundingBox _boundingBox;
-
-};
-
-}
-
-#endif
+#ifndef TERRAINPATCH_H_
+#define TERRAINPATCH_H_
+
+#include "Model.h"
+#include "Camera.h"
+
+namespace gameplay
+{
+
+class Terrain;
+
+/**
+ * Represents a single patch for a Terrain.
+ */
+class TerrainPatch : public Camera::Listener
+{
+    friend class Terrain;
+
+public:
+
+    /**
+     * Gets the number of material for this patch for all level of details.
+     *
+     * @return The number of material for this patch for all level of details. 
+     */
+    unsigned int getMaterialCount() const;
+
+    /**
+     * Gets the material for the specified level of detail index or -1 for the current level of detail
+     * based on the scene camera.
+     *
+     * @param index The index for the level of detail to get the material for.
+     */
+    Material* getMaterial(int index = -1) const;
+
+    /**
+     * Gets the local bounding box for this patch, at the base LOD level.
+     */
+    const BoundingBox& getBoundingBox(bool worldSpace) const;
+
+    /**
+     * @see Camera::Listener
+     */
+    void cameraChanged(Camera* camera);
+
+private:
+
+    /**
+     * Constructor.
+     */
+    TerrainPatch();
+
+    /**
+     * Hidden copy constructor.
+     */
+    TerrainPatch(const TerrainPatch&);
+
+    /**
+     * Hidden copy assignment operator.
+     */
+    TerrainPatch& operator=(const TerrainPatch&);
+
+    /**
+     * Destructor.
+     */
+    ~TerrainPatch();
+
+    struct Layer
+    {
+        Layer();
+
+        Layer(const Layer&);
+
+        ~Layer();
+
+        Layer& operator=(const Layer&);
+
+        int index;
+        int row;
+        int column;
+        int textureIndex;
+        Vector2 textureRepeat;
+        int blendIndex;
+        int blendChannel;
+    };
+
+    struct Level
+    {
+        Model* model;
+
+        Level();
+    };
+
+    struct LayerCompare
+    {
+        bool operator() (const Layer* lhs, const Layer* rhs) const;
+    };
+
+    static TerrainPatch* create(Terrain* terrain, 
+                                unsigned int row, unsigned int column,
+                                float* heights, unsigned int width, unsigned int height,
+                                unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
+                                float xOffset, float zOffset, unsigned int maxStep, float verticalSkirtSize);
+
+    void addLOD(float* heights, unsigned int width, unsigned int height,
+                unsigned int x1, unsigned int z1, unsigned int x2, unsigned int z2,
+                float xOffset, float zOffset, unsigned int step, float verticalSkirtSize);
+
+
+    bool setLayer(int index, const char* texturePath, const Vector2& textureRepeat, const char* blendPath, int blendChannel);
+
+    void deleteLayer(Layer* layer);
+
+    int addSampler(const char* path);
+
+    unsigned int draw(bool wireframe);
+
+    bool updateMaterial();
+
+    unsigned int computeLOD(Camera* camera, const BoundingBox& worldBounds);
+
+    const Vector3& getAmbientColor() const;
+
+    void setMaterialDirty();
+
+    Terrain* _terrain;
+    unsigned int _row;
+    unsigned int _column;
+    std::vector<Level*> _levels;
+    std::set<Layer*, LayerCompare> _layers;
+    std::vector<Texture::Sampler*> _samplers;
+    mutable BoundingBox _boundingBox;
+    mutable BoundingBox _boundingBoxWorld;
+    mutable Camera* _camera;
+    mutable unsigned int _level;
+    mutable int _bits;
+};
+
+}
+
+#endif

+ 508 - 551
gameplay/src/TextBox.cpp

@@ -1,551 +1,508 @@
-#include "TextBox.h"
-#include "Game.h"
-
-namespace gameplay
-{
-
-static bool space(char c) {
-    return isspace(c);
-}
-
-TextBox::TextBox() : _lastKeypress(0), _fontSize(0), _caretImage(NULL), _passwordChar('*'), _inputMode(TEXT), _ctrlPressed(false)
-{
-}
-
-TextBox::~TextBox()
-{
-}
-
-TextBox* TextBox::create(const char* id, Theme::Style* style)
-{
-    GP_ASSERT(style);
-
-    TextBox* textBox = new TextBox();
-    if (id)
-        textBox->_id = id;
-    textBox->setStyle(style);
-
-    return textBox;
-}
-
-Control* TextBox::create(Theme::Style* style, Properties* properties, Theme *theme)
-{
-    TextBox* textBox = new TextBox();
-    textBox->initialize(style, properties);
-
-    return textBox;
-}
-
-void TextBox::initialize(Theme::Style* style, Properties* properties)
-{
-    GP_ASSERT(properties);
-
-    Label::initialize(style, properties);
-    _inputMode = getInputMode(properties->getString("inputMode"));
-}
-
-int TextBox::getLastKeypress()
-{
-    return _lastKeypress;
-}
-
-void TextBox::addListener(Control::Listener* listener, int eventFlags)
-{
-    if ((eventFlags & Control::Listener::VALUE_CHANGED) == Control::Listener::VALUE_CHANGED)
-    {
-        GP_ERROR("VALUE_CHANGED event is not applicable to TextBox.");
-    }
-
-    Control::addListener(listener, eventFlags);
-}
-
-bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-{   
-    switch (evt)
-    {
-    case Touch::TOUCH_PRESS: 
-        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-                 y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-        {
-            _contactIndex = (int) contactIndex;
-
-            if (_state == NORMAL)
-                Game::getInstance()->displayKeyboard(true);
-
-            setCaretLocation(x, y);
-
-            _state = ACTIVE;
-            _dirty = true;
-        }
-        else
-        {
-            _contactIndex = INVALID_CONTACT_INDEX;
-            _state = NORMAL;
-            Game::getInstance()->displayKeyboard(false);
-            _dirty = true;
-            return false;
-        }
-        break;
-    case Touch::TOUCH_MOVE:
-        if (_state == ACTIVE &&
-            x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-        {
-            setCaretLocation(x, y);
-            _dirty = true;
-        }
-        break;
-    case Touch::TOUCH_RELEASE:
-        if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-            y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-        {
-            setCaretLocation(x, y);
-            _state = FOCUS;
-        }
-        else
-        {
-            _state = NORMAL;
-            Game::getInstance()->displayKeyboard(false);
-        }
-        _contactIndex = INVALID_CONTACT_INDEX;
-        _dirty = true;
-        break;
-    }
-
-    return _consumeInputEvents;
-}
-
-bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
-{
-    switch (evt)
-    {
-        case Keyboard::KEY_PRESS:
-        {
-            switch (key)
-            {
-                case Keyboard::KEY_CTRL:
-                {
-                    _ctrlPressed = true;
-                    break;
-                }
-                case Keyboard::KEY_HOME:
-                {
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-                    font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, 0,
-                        textAlignment, true, rightToLeft);
-                    _dirty = true;
-                    break;
-                }
-                case Keyboard::KEY_END:
-                {
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-                    const std::string displayedText = getDisplayedText();
-                    font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, displayedText.size(),
-                        textAlignment, true, rightToLeft);
-                    _dirty = true;
-                    break;
-                }
-                case Keyboard::KEY_DELETE:
-                {
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-
-                    int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-                        textAlignment, true, rightToLeft);
-                        
-                    _text.erase(textIndex, 1);
-                    font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
-                        textAlignment, true, rightToLeft);
-                    _dirty = true;
-                    notifyListeners(Control::Listener::TEXT_CHANGED);
-                    break;
-                }
-                case Keyboard::KEY_TAB:
-                {
-                    // Allow tab to move the focus forward.
-                    return false;
-                    break;
-                }
-                case Keyboard::KEY_LEFT_ARROW:
-                {
-                    const std::string displayedText = getDisplayedText();
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-
-                    int textIndex = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-                        textAlignment, true, rightToLeft);
-                    if (_ctrlPressed)
-                    {
-                        std::string::const_reverse_iterator it = std::find_if(displayedText.rend() - (textIndex - 1), displayedText.rend(), space);
-                        textIndex = std::distance(displayedText.begin(), it.base());
-                    }
-                    else
-                    {
-                        --textIndex;
-                    }
-                    font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
-                        textAlignment, true, rightToLeft);
-                    _dirty = true;
-                    break;
-                }
-                case Keyboard::KEY_RIGHT_ARROW:
-                {
-                    const std::string displayedText = getDisplayedText();
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-
-                    int textIndex = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-                        textAlignment, true, rightToLeft);
-                    if (_ctrlPressed)
-                    {
-                        std::string::const_iterator it = std::find_if(displayedText.begin() + (textIndex + 1), displayedText.end(), space);
-                        textIndex = std::distance(displayedText.begin(), it);
-                    }
-                    else
-                    {
-                        ++textIndex;
-                    }
-                    font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
-                        textAlignment, true, rightToLeft);
-                    _dirty = true;
-                    break;
-                }
-                case Keyboard::KEY_UP_ARROW:
-                {
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-                    _prevCaretLocation.set(_caretLocation);
-                    _caretLocation.y -= fontSize;
-                    int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-                        textAlignment, true, rightToLeft);
-                    if (textIndex == -1)
-                    {
-                        _caretLocation.set(_prevCaretLocation);
-                    }
-
-                    _dirty = true;
-                    break;
-                }
-                case Keyboard::KEY_DOWN_ARROW:
-                {
-                    Font* font = getFont(_state);
-                    GP_ASSERT(font);
-                    unsigned int fontSize = getFontSize(_state);
-                    Font::Justify textAlignment = getTextAlignment(_state);
-                    bool rightToLeft = getTextRightToLeft(_state);
-                    _prevCaretLocation.set(_caretLocation);
-                    _caretLocation.y += fontSize;
-                    int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-                        textAlignment, true, rightToLeft);
-                    if (textIndex == -1)
-                    {
-                        _caretLocation.set(_prevCaretLocation);
-                    }
-
-                    _dirty = true;
-                    break;
-                }
-            }
-            break;
-        }
-
-        case Keyboard::KEY_CHAR:
-        {
-            Font* font = getFont(_state);
-            GP_ASSERT(font);
-            unsigned int fontSize = getFontSize(_state);
-            Font::Justify textAlignment = getTextAlignment(_state);
-            bool rightToLeft = getTextRightToLeft(_state);
-
-            int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-                textAlignment, true, rightToLeft);
-            if (textIndex == -1)
-            {
-                textIndex = 0;
-                font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, 0,
-                    textAlignment, true, rightToLeft);
-            }
-
-            switch (key)
-            {
-                case Keyboard::KEY_BACKSPACE:
-                {
-                    if (textIndex > 0)
-                    {
-                        --textIndex;
-                        _text.erase(textIndex, 1);
-                        font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
-                            textAlignment, true, rightToLeft);
-
-                        _dirty = true;
-                    }
-                    break;
-                }
-                case Keyboard::KEY_RETURN:
-                    // TODO: Handle line-break insertion correctly.
-                    break;
-                case Keyboard::KEY_ESCAPE:
-                    break;
-                case Keyboard::KEY_TAB:
-                    // Allow tab to move the focus forward.
-                    return false;
-                    break;
-                default:
-                {
-                    // Insert character into string.
-                    _text.insert(textIndex, 1, (char)key);
-
-                    // Get new location of caret.
-                    font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex + 1,
-                        textAlignment, true, rightToLeft);
-
-                    if (key == ' ')
-                    {
-                        // If a space was entered, check that caret is still within bounds.
-                        if (_caretLocation.x >= _textBounds.x + _textBounds.width ||
-                            _caretLocation.y >= _textBounds.y + _textBounds.height)
-                        {
-                            // If not, undo the character insertion.
-                            _text.erase(textIndex, 1);
-                            font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
-                                textAlignment, true, rightToLeft);
-
-                            // No need to check again.
-                            break;
-                        }
-                    }
-
-                    // Always check that the text still fits within the clip region.
-                    Rectangle textBounds;
-                    font->measureText(getDisplayedText().c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
-                    if (textBounds.x < _textBounds.x || textBounds.y < _textBounds.y ||
-                        textBounds.width >= _textBounds.width || textBounds.height >= _textBounds.height)
-                    {
-                        // If not, undo the character insertion.
-                        _text.erase(textIndex, 1);
-                        font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
-                            textAlignment, true, rightToLeft);
-
-                        // TextBox is not dirty.
-                        break;
-                    }
-                
-                    _dirty = true;
-                    break;
-                }
-            
-                break;
-            }
-
-            notifyListeners(Control::Listener::TEXT_CHANGED);
-            break;
-        }
-        case Keyboard::KEY_RELEASE:
-            switch (key)
-            {
-                case Keyboard::KEY_CTRL:
-                {
-                    _ctrlPressed = false;
-                    break;
-                }
-            }
-    }
-
-    _lastKeypress = key;
-
-    return _consumeInputEvents;
-}
-
-void TextBox::update(const Control* container, const Vector2& offset)
-{
-    Label::update(container, offset);
-
-    _fontSize = getFontSize(_state);
-    _caretImage = getImage("textCaret", _state);
-}
-
-void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
-{
-    if (_caretImage && (_state == ACTIVE || hasFocus()))
-    {
-        // Draw the cursor at its current location.
-        const Rectangle& region = _caretImage->getRegion();
-        if (!region.isEmpty())
-        {
-            GP_ASSERT(spriteBatch);
-            const Theme::UVs uvs = _caretImage->getUVs();
-            Vector4 color = _caretImage->getColor();
-            color.w *= _opacity;
-
-            float caretWidth = region.width * _fontSize / region.height;
-            spriteBatch->draw(_caretLocation.x - caretWidth * 0.5f, _caretLocation.y, caretWidth, _fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
-        }
-    }
-
-    _dirty = false;
-}
-
-void TextBox::setCaretLocation(int x, int y)
-{
-    // Get index into string and cursor location from the latest touch location.
-    _prevCaretLocation.set(_caretLocation);
-    _caretLocation.set(x + _absoluteBounds.x,
-                       y + _absoluteBounds.y);
-
-    Font* font = getFont(_state);
-    unsigned int fontSize = getFontSize(_state);
-    Font::Justify textAlignment = getTextAlignment(_state);
-    bool rightToLeft = getTextRightToLeft(_state);
-    const std::string displayedText = getDisplayedText();
-
-    int index = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-            textAlignment, true, rightToLeft);
-
-    if (index == -1)
-    {
-        // Attempt to find the nearest valid caret location.
-        Rectangle textBounds;
-        font->measureText(displayedText.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
-
-        if (_caretLocation.x > textBounds.x + textBounds.width &&
-            _caretLocation.y > textBounds.y + textBounds.height)
-        {
-            font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, (unsigned int)_text.length(),
-                textAlignment, true, rightToLeft);
-            return;
-        }
-
-        if (_caretLocation.x < textBounds.x)
-        {
-            _caretLocation.x = textBounds.x;
-        }
-        else if (_caretLocation.x > textBounds.x + textBounds.width)
-        {
-            _caretLocation.x = textBounds.x + textBounds.width;
-        }
-
-        if (_caretLocation.y < textBounds.y)
-        {
-            _caretLocation.y = textBounds.y;
-        }
-        else if (_caretLocation.y > textBounds.y + textBounds.height)
-        {
-            Font* font = getFont(_state);
-            GP_ASSERT(font);
-            unsigned int fontSize = getFontSize(_state);
-            _caretLocation.y = textBounds.y + textBounds.height - fontSize;
-        }
-
-        index = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
-            textAlignment, true, rightToLeft);
-
-        if (index == -1)
-        {
-            // We failed to find a valid location; just put the caret back to where it was.
-            _caretLocation.set(_prevCaretLocation);
-        }
-    }
-}
-
-const char* TextBox::getType() const
-{
-    return "textBox";
-}
-
-void TextBox::setPasswordChar(char character)
-{
-    _passwordChar = character;
-}
-
-char TextBox::getPasswordChar() const
-{
-    return _passwordChar;
-}
-
-void TextBox::setInputMode(InputMode inputMode)
-{
-    _inputMode = inputMode;
-}
-
-TextBox::InputMode TextBox::getInputMode() const
-{
-    return _inputMode;
-}
-
-void TextBox::drawText(const Rectangle& clip)
-{
-    if (_text.size() <= 0)
-        return;
-
-    // Draw the text.
-    if (_font)
-    {
-        const std::string displayedText = getDisplayedText();
-        _font->start();
-        _font->drawText(displayedText.c_str(), _textBounds, _textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_viewportClipBounds);
-        _font->finish();
-    }
-}
-
-TextBox::InputMode TextBox::getInputMode(const char* inputMode)
-{
-    if (!inputMode)
-    {
-        return TextBox::TEXT;
-    }
-
-    if (strcmp(inputMode, "TEXT") == 0)
-    {
-        return TextBox::TEXT;
-    }
-    else if (strcmp(inputMode, "PASSWORD") == 0)
-    {
-        return TextBox::PASSWORD;
-    }
-    else
-    {
-        GP_ERROR("Failed to get corresponding textbox inputmode for unsupported value '%s'.", inputMode);
-    }
-
-    // Default.
-    return TextBox::TEXT;
-}
-
-std::string TextBox::getDisplayedText() const
-{
-    std::string displayedText;
-    switch (_inputMode) {
-        case PASSWORD:
-            displayedText.insert((size_t)0, _text.length(), _passwordChar);
-            break;
-
-        case TEXT:
-        default:
-            displayedText = _text;
-            break;
-    }
-
-    return displayedText;
-}
-
-}
+#include "TextBox.h"
+#include "Game.h"
+
+namespace gameplay
+{
+
+static bool space(char c)
+{
+    return isspace(c);
+}
+
+TextBox::TextBox() : _caretLocation(0), _lastKeypress(0), _fontSize(0), _caretImage(NULL), _passwordChar('*'), _inputMode(TEXT), _ctrlPressed(false)
+{
+    _canFocus = true;
+}
+
+TextBox::~TextBox()
+{
+}
+
+TextBox* TextBox::create(const char* id, Theme::Style* style)
+{
+    GP_ASSERT(style);
+
+    TextBox* textBox = new TextBox();
+    if (id)
+        textBox->_id = id;
+    textBox->setStyle(style);
+
+    return textBox;
+}
+
+Control* TextBox::create(Theme::Style* style, Properties* properties)
+{
+    TextBox* textBox = new TextBox();
+    textBox->initialize(style, properties);
+
+    return textBox;
+}
+
+void TextBox::initialize(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Label::initialize(style, properties);
+    _inputMode = getInputMode(properties->getString("inputMode"));
+}
+
+int TextBox::getLastKeypress()
+{
+    return _lastKeypress;
+}
+
+unsigned int TextBox::getCaretLocation() const
+{
+    return _caretLocation;
+}
+
+void TextBox::setCaretLocation(unsigned int index)
+{
+    _caretLocation = index;
+    if (_caretLocation > _text.length())
+        _caretLocation = (unsigned int)_text.length();
+}
+
+bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    State state = getState();
+
+    switch (evt)
+    {
+    case Touch::TOUCH_PRESS: 
+        if (state == ACTIVE)
+        {
+            setCaretLocation(x, y);
+            _dirty = true;
+        }
+        break;
+    case Touch::TOUCH_MOVE:
+        if (state == ACTIVE)
+        {
+            setCaretLocation(x, y);
+            _dirty = true;
+        }
+        break;
+    }
+
+    return Label::touchEvent(evt, x, y, contactIndex);
+}
+
+static bool isWhitespace(char c)
+{
+    switch (c)
+    {
+    case ' ':
+    case '\t':
+    case '\r':
+    case '\n':
+        return true;
+
+    default:
+        return false;
+    }
+}
+
+static unsigned int findNextWord(const std::string& text, unsigned int from, bool backwards)
+{
+    int pos = (int)from;
+    if (backwards)
+    {
+        if (pos > 0)
+        {
+            // Moving backwards: skip all consecutive whitespace characters
+            while (pos > 0 && isWhitespace(text.at(pos-1)))
+                --pos;
+            // Now search back to the first whitespace character
+            while (pos > 0 && !isWhitespace(text.at(pos-1)))
+                --pos;
+        }
+    }
+    else
+    {
+        const int len = (const int)text.length();
+        if (pos < len)
+        {
+            // Moving forward: skip all consecutive non-whitespace characters
+            ++pos;
+            while (pos < len && !isWhitespace(text.at(pos)))
+                ++pos;
+            // Now search for the first non-whitespace character
+            while (pos < len && isWhitespace(text.at(pos)))
+                ++pos;
+        }
+    }
+
+    return (unsigned int)pos;
+}
+
+bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+    switch (evt)
+    {
+        case Keyboard::KEY_PRESS:
+        {
+            switch (key)
+            {
+                case Keyboard::KEY_CTRL:
+                {
+                    _ctrlPressed = true;
+                    break;
+                }
+                case Keyboard::KEY_HOME:
+                {
+                    _caretLocation = 0;
+                    _dirty = true;
+                    break;
+                }
+                case Keyboard::KEY_END:
+                {
+                    _caretLocation = _text.length();
+                    _dirty = true;
+                    break;
+                }
+                case Keyboard::KEY_DELETE:
+                {
+                    if (_caretLocation < _text.length())
+                    {
+                        int newCaretLocation;
+                        if (_ctrlPressed)
+                        {
+                            newCaretLocation = findNextWord(getDisplayedText(), _caretLocation, false);
+                        }
+                        else
+                        {
+                            newCaretLocation = _caretLocation + 1;
+                        }
+                        _text.erase(_caretLocation, newCaretLocation - _caretLocation);
+                        _dirty = true;
+                        notifyListeners(Control::Listener::TEXT_CHANGED);
+                    }
+                    break;
+                }
+                case Keyboard::KEY_TAB:
+                {
+                    // Allow tab to move the focus forward.
+                    return false;
+                }
+                case Keyboard::KEY_LEFT_ARROW:
+                {
+                    if (_caretLocation > 0)
+                    {
+                        if (_ctrlPressed)
+                        {
+                            _caretLocation = findNextWord(getDisplayedText(), _caretLocation, true);
+                        }
+                        else
+                        {
+                            --_caretLocation;
+                        }
+                    }
+                    _dirty = true;
+                    break;
+                }
+                case Keyboard::KEY_RIGHT_ARROW:
+                {
+                    if (_caretLocation < _text.length())
+                    {
+                        if (_ctrlPressed)
+                        {
+                            _caretLocation = findNextWord(getDisplayedText(), _caretLocation, false);
+                        }
+                        else
+                        {
+                            ++_caretLocation;
+                        }
+                    }
+                    _dirty = true;
+                    break;
+                }
+                case Keyboard::KEY_UP_ARROW:
+                {
+                    // TODO: Support multiline
+                    break;
+                }
+                case Keyboard::KEY_DOWN_ARROW:
+                {
+                    // TODO: Support multiline
+                    break;
+                }
+                case Keyboard::KEY_BACKSPACE:
+                {
+                    if (_caretLocation > 0)
+                    {
+                        int newCaretLocation;
+                        if (_ctrlPressed)
+                        {
+                            newCaretLocation = findNextWord(getDisplayedText(), _caretLocation, true);
+                        }
+                        else
+                        {
+                            newCaretLocation = _caretLocation - 1;
+                        }
+                        _text.erase(newCaretLocation, _caretLocation - newCaretLocation);
+                        _caretLocation = newCaretLocation;
+                        _dirty = true;
+                        notifyListeners(Control::Listener::TEXT_CHANGED);
+                    }
+                    break;
+                }
+            }
+            break;
+        }
+
+        case Keyboard::KEY_CHAR:
+        {
+            switch (key)
+            {
+                case Keyboard::KEY_RETURN:
+                    // TODO: Support multi-line
+                    break;
+                case Keyboard::KEY_ESCAPE:
+                    break;
+                case Keyboard::KEY_BACKSPACE:
+                    break;
+                case Keyboard::KEY_TAB:
+                    // Allow tab to move the focus forward.
+                    return false;
+                default:
+                {
+                    // Insert character into string, only if our font supports this character
+                    if (_font && _font->isCharacterSupported(key))
+                    {
+                        if (_caretLocation <= _text.length())
+                        {
+                            _text.insert(_caretLocation, 1, (char)key);
+                            ++_caretLocation;
+                        }
+
+                        _dirty = true;
+                        notifyListeners(Control::Listener::TEXT_CHANGED);
+                    }
+                    break;
+                }
+            
+                break;
+            }
+            break;
+        }
+        case Keyboard::KEY_RELEASE:
+            switch (key)
+            {
+                case Keyboard::KEY_CTRL:
+                {
+                    _ctrlPressed = false;
+                    break;
+                }
+            }
+    }
+
+    _lastKeypress = key;
+
+    return Label::keyEvent(evt, key);
+}
+
+void TextBox::controlEvent(Control::Listener::EventType evt)
+{
+    Label::controlEvent(evt);
+
+    switch (evt)
+    {
+    case Control::Listener::FOCUS_GAINED:
+        Game::getInstance()->displayKeyboard(true);
+        break;
+
+    case Control::Listener::FOCUS_LOST:
+        Game::getInstance()->displayKeyboard(false);
+        break;
+    }
+}
+
+void TextBox::update(const Control* container, const Vector2& offset)
+{
+    Label::update(container, offset);
+
+    Control::State state = getState();
+    _fontSize = getFontSize(state);
+    _caretImage = getImage("textCaret", state);
+}
+
+void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    Control::State state = getState();
+
+    if (_caretImage && (state == ACTIVE || hasFocus()))
+    {
+        // Draw the cursor at its current location.
+        const Rectangle& region = _caretImage->getRegion();
+        if (!region.isEmpty())
+        {
+            GP_ASSERT(spriteBatch);
+            const Theme::UVs uvs = _caretImage->getUVs();
+            Vector4 color = _caretImage->getColor();
+            color.w *= _opacity;
+
+            float caretWidth = region.width * _fontSize / region.height;
+
+            Font* font = getFont(state);
+            unsigned int fontSize = getFontSize(state);
+            Vector2 point;
+            font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &point, _caretLocation, 
+                 getTextAlignment(state), true, getTextRightToLeft(state));
+            spriteBatch->draw(point.x - caretWidth * 0.5f, point.y, caretWidth, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
+        }
+    }
+
+    _dirty = false;
+}
+
+void TextBox::setCaretLocation(int x, int y)
+{
+    Control::State state = getState();
+
+    Vector2 point(x + _absoluteBounds.x, y + _absoluteBounds.y);
+
+    // Get index into string and cursor location from the latest touch location.
+    Font* font = getFont(state);
+    unsigned int fontSize = getFontSize(state);
+    Font::Justify textAlignment = getTextAlignment(state);
+    bool rightToLeft = getTextRightToLeft(state);
+    const std::string displayedText = getDisplayedText();
+
+    int index = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, point, &point,
+            textAlignment, true, rightToLeft);
+
+    if (index == -1)
+    {
+        // Attempt to find the nearest valid caret location.
+        Rectangle textBounds;
+        font->measureText(displayedText.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
+
+        if (point.x > textBounds.x + textBounds.width &&
+            point.y > textBounds.y + textBounds.height)
+        {
+            font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &point, (unsigned int)_text.length(),
+                textAlignment, true, rightToLeft);
+            return;
+        }
+
+        if (point.x < textBounds.x)
+        {
+            point.x = textBounds.x;
+        }
+        else if (point.x > textBounds.x + textBounds.width)
+        {
+            point.x = textBounds.x + textBounds.width;
+        }
+
+        if (point.y < textBounds.y)
+        {
+            point.y = textBounds.y;
+        }
+        else if (point.y > textBounds.y + textBounds.height)
+        {
+            Font* font = getFont(state);
+            GP_ASSERT(font);
+            unsigned int fontSize = getFontSize(state);
+            point.y = textBounds.y + textBounds.height - fontSize;
+        }
+
+        index = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, point, &point,
+            textAlignment, true, rightToLeft);
+    }
+
+    if (index != -1)
+        _caretLocation = index;
+}
+
+void TextBox::getCaretLocation(Vector2* p)
+{
+    GP_ASSERT(p);
+
+    State state = getState();
+    getFont(state)->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, getFontSize(state), p, _caretLocation, getTextAlignment(state), true, getTextRightToLeft(state));
+}
+
+const char* TextBox::getType() const
+{
+    return "textBox";
+}
+
+void TextBox::setPasswordChar(char character)
+{
+    _passwordChar = character;
+}
+
+char TextBox::getPasswordChar() const
+{
+    return _passwordChar;
+}
+
+void TextBox::setInputMode(InputMode inputMode)
+{
+    _inputMode = inputMode;
+}
+
+TextBox::InputMode TextBox::getInputMode() const
+{
+    return _inputMode;
+}
+
+void TextBox::drawText(const Rectangle& clip)
+{
+    if (_text.size() <= 0)
+        return;
+
+    // Draw the text.
+    if (_font)
+    {
+        Control::State state = getState();
+        const std::string displayedText = getDisplayedText();
+        _font->start();
+        _font->drawText(displayedText.c_str(), _textBounds, _textColor, getFontSize(state), getTextAlignment(state), true, getTextRightToLeft(state), &_viewportClipBounds);
+        _font->finish();
+    }
+}
+
+TextBox::InputMode TextBox::getInputMode(const char* inputMode)
+{
+    if (!inputMode)
+    {
+        return TextBox::TEXT;
+    }
+
+    if (strcmp(inputMode, "TEXT") == 0)
+    {
+        return TextBox::TEXT;
+    }
+    else if (strcmp(inputMode, "PASSWORD") == 0)
+    {
+        return TextBox::PASSWORD;
+    }
+    else
+    {
+        GP_ERROR("Failed to get corresponding textbox inputmode for unsupported value '%s'.", inputMode);
+    }
+
+    // Default.
+    return TextBox::TEXT;
+}
+
+std::string TextBox::getDisplayedText() const
+{
+    std::string displayedText;
+    switch (_inputMode) {
+        case PASSWORD:
+            displayedText.insert((size_t)0, _text.length(), _passwordChar);
+            break;
+
+        case TEXT:
+        default:
+            displayedText = _text;
+            break;
+    }
+
+    return displayedText;
+}
+
+}

+ 278 - 269
gameplay/src/TextBox.h

@@ -1,269 +1,278 @@
-#ifndef TEXTBOX_H_
-#define TEXTBOX_H_
-
-#include "Base.h"
-#include "Label.h"
-#include "Theme.h"
-#include "Keyboard.h"
-
-namespace gameplay
-{
-
-/**
- * An editable text label.  Tap or click within the text box to bring up the
- * virtual keyboard.
- *
- * Listeners can listen for a TEXT_CHANGED event, and then query the text box
- * for the last keypress it received.
- *
- * The following properties are available for text boxes:
-
- @verbatim
-    textBox <labelID>
-    {
-         style       = <styleID>
-         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
-         position    = <x, y>
-         autoWidth   = <bool>
-         autoHeight  = <bool>
-         size        = <width, height>
-         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
-         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
-         text        = <string>
-         inputMode   = <TextBox::InputMode constant>
-    }
- @endverbatim
- */
-class TextBox : public Label
-{
-    friend class Container;
-	friend class ControlFactory;
-	
-public:
-
-    /**
-     * Input modes. Default is Text.
-     */
-    enum InputMode {
-        /**
-         * Text: Text is displayed directly.
-         */
-        TEXT = 0x01,
-
-        /**
-         * Password: Text is replaced by _passwordChar, which is '*' by default.
-         */
-        PASSWORD = 0x02
-    };
-
-    /**
-     * Create a new text box control.
-     *
-     * @param id The control's ID.
-     * @param style The control's style.
-     *
-     * @return The new text box.
-     * @script{create}
-     */
-    static TextBox* create(const char* id, Theme::Style* style);
-
-    /**
-     * Initialize this textbox.
-     */
-    virtual void initialize(Theme::Style* style, Properties* properties);
-
-    /**
-     * Add a listener to be notified of specific events affecting
-     * this control.  Event types can be OR'ed together.
-     * E.g. To listen to touch-press and touch-release events,
-     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
-     * as the second parameter.
-     *
-     * @param listener The listener to add.
-     * @param eventFlags The events to listen for.
-     */
-    virtual void addListener(Control::Listener* listener, int eventFlags);
-
-    /**
-     * Get the last key pressed within this text box.
-     *
-     * @return The last key pressed within this text box.
-     */
-    int getLastKeypress();
-
-    /**
-     * @see Control::getType
-     */
-    const char* getType() const;
-
-    /**
-     * Set the character displayed in password mode.
-     *
-     * @param character Character to display in password mode.
-     */
-    void setPasswordChar(char character);
-
-    /**
-     * Get the character displayed in password mode.
-     *
-     * @return The character displayed in password mode.
-     */
-    char getPasswordChar() const;
-
-    /**
-     * Set the input mode.
-     *
-     * @param inputMode Input mode to set.
-     */
-    void setInputMode(InputMode inputMode);
-
-    /**
-     * Get the input mode.
-     *
-     * @return The input mode.
-     */
-    InputMode getInputMode() const;
-
-protected:
-
-    /**
-     * Constructor.
-     */
-    TextBox();
-
-    /**
-     * Destructor.
-     */
-    ~TextBox();
-
-    /**
-     * Create a text box with a given style and properties.
-     *
-     * @param style The style to apply to this text box.
-     * @param properties The properties to set on this text box.
-     * @param theme The theme to set on this control if needed
-	 *
-     * @return The new text box.
-     */
-    static Control* create(Theme::Style* style, Properties* properties, Theme *theme = NULL);
-
-    /**
-     * Touch callback on touch events.  Controls return true if they consume the touch event.
-     *
-     * @param evt The touch event that occurred.
-     * @param x The x position of the touch in pixels. Left edge is zero.
-     * @param y The y position of the touch in pixels. Top edge is zero.
-     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
-     *
-     * @return Whether the touch event was consumed by the control.
-     *
-     * @see Touch::TouchEvent
-     */
-    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
-
-    /**
-     * Keyboard callback on key events.
-     *
-     * @param evt The key event that occurred.
-     * @param key If evt is KEY_PRESS or KEY_RELEASE then key is the key code from Keyboard::Key.
-     *            If evt is KEY_CHAR then key is the unicode value of the character.
-     * 
-     * @see Keyboard::KeyEvent
-     * @see Keyboard::Key
-     */
-    bool keyEvent(Keyboard::KeyEvent evt, int key);
-
-    /**
-     * Called when a control's properties change.  Updates this control's internal rendering
-     * properties, such as its text viewport.
-     *
-     * @param container This control's parent container.
-     * @param offset Positioning offset to add to the control's position.
-     */
-    void update(const Control* container, const Vector2& offset);
-
-    /**
-     * Draw the images associated with this control.
-     *
-     * @param spriteBatch The sprite batch containing this control's icons.
-     * @param clip The clipping rectangle of this control's parent container.
-     */
-    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-    /**
-     * Draw this textbox's text.
-     *
-     * @param clip The clipping rectangle of this textbox's
-     * parent container.
-     */
-    virtual void drawText(const Rectangle& clip);
-
-    /**
-     * Gets an InputMode by string.
-     *
-     * @param inputMode The string representation of the InputMode type.
-     * @return The InputMode enum value corresponding to the given string.
-     */
-    static InputMode getInputMode(const char* inputMode);
-
-    /**
-     * Get the text which should be displayed, depending on
-     * _inputMode.
-     *
-     * @return The text to be displayed.
-     */
-    std::string getDisplayedText() const;
-
-    /**
-     * The current position of the TextBox's caret.
-     */
-    Vector2 _caretLocation;
-
-    /**
-     * The previous position of the TextBox's caret.
-     */
-    Vector2 _prevCaretLocation;
-    
-    /**
-     * The last character that was entered into the TextBox.
-     */
-    int _lastKeypress;
-
-    /**
-     * The font size to be used in the TextBox.
-     */
-    unsigned int _fontSize;
-    
-    /**
-     * The Theme::Image for the TextBox's caret.
-     */
-    Theme::ThemeImage* _caretImage;
-
-    /**
-     * The character displayed in password mode.
-     */
-    char _passwordChar;
-
-    /**
-     * The mode used to display the typed text.
-     */
-    InputMode _inputMode;
-
-    /**
-     * Indicate if the CTRL key is currently pressed.
-     */
-    bool _ctrlPressed;
-
-private:
-
-    /**
-     * Constructor.
-     */
-    TextBox(const TextBox& copy);
-
-    void setCaretLocation(int x, int y);
-};
-
-}
-
-#endif
+#ifndef TEXTBOX_H_
+#define TEXTBOX_H_
+
+#include "Base.h"
+#include "Label.h"
+#include "Theme.h"
+#include "Keyboard.h"
+
+namespace gameplay
+{
+
+/**
+ * An editable text label.  Tap or click within the text box to bring up the
+ * virtual keyboard.
+ *
+ * Listeners can listen for a TEXT_CHANGED event, and then query the text box
+ * for the last keypress it received.
+ *
+ * The following properties are available for text boxes:
+
+ @verbatim
+    textBox <labelID>
+    {
+         style       = <styleID>
+         alignment   = <Control::Alignment constant> // Note: 'position' will be ignored.
+         position    = <x, y>
+         autoWidth   = <bool>
+         autoHeight  = <bool>
+         size        = <width, height>
+         width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
+         height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
+         text        = <string>
+         inputMode   = <TextBox::InputMode constant>
+    }
+ @endverbatim
+ */
+class TextBox : public Label
+{
+    friend class Container;
+    friend class ControlFactory;
+
+public:
+
+    /**
+     * Input modes. Default is Text.
+     */
+    enum InputMode
+    {
+        /**
+         * Text: Text is displayed directly.
+         */
+        TEXT = 0x01,
+
+        /**
+         * Password: Text is replaced by _passwordChar, which is '*' by default.
+         */
+        PASSWORD = 0x02
+    };
+
+    /**
+     * Create a new text box control.
+     *
+     * @param id The control's ID.
+     * @param style The control's style.
+     *
+     * @return The new text box.
+     * @script{create}
+     */
+    static TextBox* create(const char* id, Theme::Style* style);
+
+    /**
+     * Initialize this textbox.
+     */
+    virtual void initialize(Theme::Style* style, Properties* properties);
+
+    /**
+     * Returns the current location of the caret with the text of this TextBox.
+     *
+     * @return The current caret location.
+     */
+    unsigned int getCaretLocation() const;
+
+    /**
+     * Sets the location of the caret within this text box.
+     *
+     * @param index The new location of the caret within the text of this TextBox.
+     */
+    void setCaretLocation(unsigned int index);
+
+    /**
+     * Get the last key pressed within this text box.
+     *
+     * @return The last key pressed within this text box.
+     */
+    int getLastKeypress();
+
+    /**
+     * @see Control::getType
+     */
+    const char* getType() const;
+
+    /**
+     * Set the character displayed in password mode.
+     *
+     * @param character Character to display in password mode.
+     */
+    void setPasswordChar(char character);
+
+    /**
+     * Get the character displayed in password mode.
+     *
+     * @return The character displayed in password mode.
+     */
+    char getPasswordChar() const;
+
+    /**
+     * Set the input mode.
+     *
+     * @param inputMode Input mode to set.
+     */
+    void setInputMode(InputMode inputMode);
+
+    /**
+     * Get the input mode.
+     *
+     * @return The input mode.
+     */
+    InputMode getInputMode() const;
+
+protected:
+
+    /**
+     * Constructor.
+     */
+    TextBox();
+
+    /**
+     * Destructor.
+     */
+    ~TextBox();
+
+    /**
+     * Create a text box with a given style and properties.
+     *
+     * @param style The style to apply to this text box.
+     * @param properties The properties to set on this text box.
+     *
+     * @return The new text box.
+     */
+    static Control* create(Theme::Style* style, Properties* properties);
+
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
+    bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
+
+    /**
+     * Keyboard callback on key events.
+     *
+     * @param evt The key event that occurred.
+     * @param key If evt is KEY_PRESS or KEY_RELEASE then key is the key code from Keyboard::Key.
+     *            If evt is KEY_CHAR then key is the unicode value of the character.
+     * 
+     * @see Keyboard::KeyEvent
+     * @see Keyboard::Key
+     */
+    bool keyEvent(Keyboard::KeyEvent evt, int key);
+
+    /**
+     * @see Control#controlEvent
+     */
+    void controlEvent(Control::Listener::EventType evt);
+
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param container This control's parent container.
+     * @param offset Positioning offset to add to the control's position.
+     */
+    void update(const Control* container, const Vector2& offset);
+
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
+    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    /**
+     * Draw this textbox's text.
+     *
+     * @param clip The clipping rectangle of this textbox's
+     * parent container.
+     */
+    virtual void drawText(const Rectangle& clip);
+
+    /**
+     * Gets an InputMode by string.
+     *
+     * @param inputMode The string representation of the InputMode type.
+     * @return The InputMode enum value corresponding to the given string.
+     */
+    static InputMode getInputMode(const char* inputMode);
+
+    /**
+     * Get the text which should be displayed, depending on
+     * _inputMode.
+     *
+     * @return The text to be displayed.
+     */
+    std::string getDisplayedText() const;
+
+    /**
+     * The current location of the TextBox's caret.
+     */
+    unsigned int _caretLocation;
+
+    /**
+     * The previous position of the TextBox's caret.
+     */
+    Vector2 _prevCaretLocation;
+    
+    /**
+     * The last character that was entered into the TextBox.
+     */
+    int _lastKeypress;
+
+    /**
+     * The font size to be used in the TextBox.
+     */
+    unsigned int _fontSize;
+    
+    /**
+     * The Theme::Image for the TextBox's caret.
+     */
+    Theme::ThemeImage* _caretImage;
+
+    /**
+     * The character displayed in password mode.
+     */
+    char _passwordChar;
+
+    /**
+     * The mode used to display the typed text.
+     */
+    InputMode _inputMode;
+
+    /**
+     * Indicate if the CTRL key is currently pressed.
+     */
+    bool _ctrlPressed;
+
+private:
+
+    /**
+     * Constructor.
+     */
+    TextBox(const TextBox& copy);
+
+    void setCaretLocation(int x, int y);
+
+    void getCaretLocation(Vector2* p);
+};
+
+}
+
+#endif

+ 0 - 53
gameplay/src/VisibleSet.h

@@ -1,53 +0,0 @@
-#ifndef VISIBLESET_H_
-#define VISIBLESET_H_
-
-#include "Scene.h"
-
-namespace gameplay
-{
-
-/**
- * Represents a set of nodes that are visible from the
- * scenes active camera. This provides an enumerator
- * to traverse the scene returning only visible nodes.
- */
-class VisibleSet
-{
-public:
-    
-    /**
-     * Destructor.
-     */
-    virtual ~VisibleSet() { }
-
-    /**
-     * Sets the scene to determine the visible set from.
-     *
-     * @param scene The scene to determine the visible set from.
-     */
-    virtual void setScene(Scene* scene) = 0;
-
-    /**
-     * Gets the scene to determine the visible set from.
-     *
-     * @return The scene to determine the visible set from.
-     */
-    virtual Scene* getScene() = 0;
-
-    /**
-     * Resets the enumerator for enumerating the visible set.
-     */
-    virtual void reset() = 0;
-
-    /**
-     * Gets the next visible node in the set or NULL 
-     * onces you have reached the end of the set.
-     * 
-     * @return The next visible node in the set or NULL at end of set.
-     */
-    virtual Node* getNext() = 0;
-};
-
-}
-
-#endif

Some files were not shown because too many files changed in this diff