Просмотр исходного кода

Merge remote-tracking branch 'upstream/next'

Joilnen Leite 13 лет назад
Родитель
Сommit
33cd2ae992
100 измененных файлов с 3382 добавлено и 1192 удалено
  1. 1 0
      .gitignore
  2. 0 1
      .kateconfig
  3. 18 1
      CHANGES.md
  4. 23 15
      README.md
  5. 0 8
      cmake/README.md
  6. 1 1
      gameplay-encoder/src/Scene.h
  7. 2 2
      gameplay-luagen/gameplay-luagen.vcxproj
  8. 31 31
      gameplay-template/android/template.AndroidManifest.xml
  9. 3 4
      gameplay-template/android/template.build.xml
  10. 4 4
      gameplay-template/gameplay-template.vcxproj
  11. 1 1
      gameplay-template/res/box.material
  12. 2 2
      gameplay-template/res/colored.vert
  13. 1 1
      gameplay.doxyfile
  14. 11 7
      gameplay/.cproject
  15. 1 0
      gameplay/gameplay.vcxproj
  16. 3 0
      gameplay/gameplay.vcxproj.filters
  17. 7 1
      gameplay/gameplay.xcodeproj/project.pbxproj
  18. 2 2
      gameplay/res/shaders/colored.vert
  19. 2 2
      gameplay/res/shaders/lib/attributes-skinning.vert
  20. 1 4
      gameplay/res/shaders/lib/lighting-point.vert
  21. 9 5
      gameplay/res/shaders/textured-bumped.frag
  22. 2 2
      gameplay/res/shaders/textured-bumped.vert
  23. 11 7
      gameplay/res/shaders/textured-unlit.frag
  24. 4 0
      gameplay/res/shaders/textured.frag
  25. 2 2
      gameplay/res/shaders/textured.vert
  26. 1 1
      gameplay/src/Animation.cpp
  27. 81 55
      gameplay/src/AudioBuffer.cpp
  28. 3 2
      gameplay/src/AudioBuffer.h
  29. 1 0
      gameplay/src/Base.h
  30. 84 102
      gameplay/src/Bundle.cpp
  31. 1 1
      gameplay/src/Bundle.h
  32. 10 8
      gameplay/src/Container.cpp
  33. 8 8
      gameplay/src/Container.h
  34. 67 13
      gameplay/src/Control.cpp
  35. 42 12
      gameplay/src/Control.h
  36. 106 3
      gameplay/src/DebugNew.h
  37. 8 8
      gameplay/src/Effect.cpp
  38. 441 33
      gameplay/src/FileSystem.cpp
  39. 28 0
      gameplay/src/FileSystem.h
  40. 4 4
      gameplay/src/Font.cpp
  41. 9 5
      gameplay/src/Font.h
  42. 16 7
      gameplay/src/Form.cpp
  43. 5 0
      gameplay/src/Form.h
  44. 1 11
      gameplay/src/FrameBuffer.cpp
  45. 2 2
      gameplay/src/Frustum.h
  46. 12 12
      gameplay/src/Game.cpp
  47. 10 4
      gameplay/src/Game.h
  48. 6 0
      gameplay/src/Game.inl
  49. 3 3
      gameplay/src/Gamepad.h
  50. 13 28
      gameplay/src/Image.cpp
  51. 0 2
      gameplay/src/Joystick.h
  52. 11 2
      gameplay/src/Layout.cpp
  53. 2 3
      gameplay/src/MathUtil.cpp
  54. 72 3
      gameplay/src/Matrix.cpp
  55. 63 31
      gameplay/src/Matrix.h
  56. 78 35
      gameplay/src/Model.cpp
  57. 12 0
      gameplay/src/Node.cpp
  58. 5 5
      gameplay/src/Node.h
  59. 1 2
      gameplay/src/ParticleEmitter.cpp
  60. 0 6
      gameplay/src/Pass.h
  61. 2 2
      gameplay/src/PhysicsCollisionObject.cpp
  62. 1 1
      gameplay/src/PhysicsCollisionObject.h
  63. 15 9
      gameplay/src/PhysicsController.cpp
  64. 1 1
      gameplay/src/PhysicsController.h
  65. 4 4
      gameplay/src/PhysicsGenericConstraint.cpp
  66. 2 2
      gameplay/src/PhysicsHingeConstraint.cpp
  67. 4 4
      gameplay/src/PhysicsSocketConstraint.cpp
  68. 2 2
      gameplay/src/PhysicsSpringConstraint.cpp
  69. 1 1
      gameplay/src/PhysicsVehicle.cpp
  70. 9 0
      gameplay/src/Platform.h
  71. 194 61
      gameplay/src/PlatformAndroid.cpp
  72. 28 20
      gameplay/src/PlatformBlackBerry.cpp
  73. 331 55
      gameplay/src/PlatformLinux.cpp
  74. 205 39
      gameplay/src/PlatformMacOSX.mm
  75. 44 12
      gameplay/src/PlatformWindows.cpp
  76. 141 2
      gameplay/src/PlatformiOS.mm
  77. 48 35
      gameplay/src/Properties.cpp
  78. 5 4
      gameplay/src/Properties.h
  79. 5 5
      gameplay/src/RenderState.h
  80. 2 2
      gameplay/src/Scene.h
  81. 47 23
      gameplay/src/ScriptController.cpp
  82. 107 17
      gameplay/src/ScriptController.h
  83. 8 7
      gameplay/src/SpriteBatch.cpp
  84. 167 0
      gameplay/src/Stream.h
  85. 2 3
      gameplay/src/TextBox.cpp
  86. 21 89
      gameplay/src/Texture.cpp
  87. 3 2
      gameplay/src/Texture.h
  88. 3 1
      gameplay/src/Transform.h
  89. 1 1
      gameplay/src/Vector2.cpp
  90. 1 1
      gameplay/src/Vector2.h
  91. 4 1
      gameplay/src/Vector3.cpp
  92. 1 1
      gameplay/src/Vector4.cpp
  93. 1 1
      gameplay/src/Vector4.h
  94. 153 66
      gameplay/src/lua/lua_Button.cpp
  95. 4 2
      gameplay/src/lua/lua_Button.h
  96. 153 66
      gameplay/src/lua/lua_CheckBox.cpp
  97. 4 2
      gameplay/src/lua/lua_CheckBox.h
  98. 153 66
      gameplay/src/lua/lua_Container.cpp
  99. 4 2
      gameplay/src/lua/lua_Container.h
  100. 153 66
      gameplay/src/lua/lua_Control.cpp

+ 1 - 0
.gitignore

@@ -10,6 +10,7 @@ Thumbs.db
 /.metadata
 /.metadata
 /169.254.0.1
 /169.254.0.1
 /ipch
 /ipch
+/build
 /cmake
 /cmake
 /Debug
 /Debug
 /Release
 /Release

+ 0 - 1
.kateconfig

@@ -1 +0,0 @@
-kate: space-indent on; tab-width 4; indent-width 4; replace-tabs on; show-tabs: on; replace-tabs-save: off; replace-trailing-space-save: off;

+ 18 - 1
CHANGES.md

@@ -1,9 +1,26 @@
+## v1.6.0
+- Adds file Stream interface for reading/writing files instead of using fread/fwrite. 
+- Adds additional gameplay-tests for billboards and forms.
+- Adds support for launching the browser via launchURL(const char*).
+- Adds physics support for setLinearFactor and setAngularFactor  on rigid bodies.
+- Adds option for fullscreen without width/height config to use native desktop resolution.
+- Adds Linux support for OpenAL PulseAudio back-end.
+- Adds support for latest Bullet Physics 2.81 with NEON optimizations for mobile targets.
+- Adds Windows 7 64-bit support.
+- Fixes to external-deps to reduce the size of the libraries on Windows.
+- Fixes for Android to no longer need to copy files to the SD card before reading them. None of the Android samples require an SD card.
+- Fixes for animation of opacity on UI and fonts.
+- Fixes in UI for removing controls and also setVisible(bool)
+- Fixes for UI controls missing on MacOSX.
+- Fixes for setting UI alignment programmatically.
+- Fixes for directional and spotlight shaders.
+
 ## v1.5.0
 ## v1.5.0
 
 
 - Linux support. (tested on Ubuntu 12)
 - Linux support. (tested on Ubuntu 12)
 - CMake support for makefile generation for Linux.
 - CMake support for makefile generation for Linux.
 - CodeBlocks 10 IDE support for Linux.
 - CodeBlocks 10 IDE support for Linux.
-- Gamepad controllers support for desktops.
+- Gamepad API support for desktops.
 - Touch gesture support for tap, swipe and pinch.
 - Touch gesture support for tap, swipe and pinch.
 - Vehicle physics support via new PhysicsVehicle and PhysicsVehicleWheel classes.
 - Vehicle physics support via new PhysicsVehicle and PhysicsVehicleWheel classes.
 - Adds new racer sample (sample06-racer).
 - Adds new racer sample (sample06-racer).

+ 23 - 15
README.md

@@ -1,29 +1,37 @@
-## gameplay v1.5.0
-An open-source, cross-platform 3D native C++ game framework making it easy to learn and write mobile and desktop games. 
+## gameplay v1.6.0
+
+GamePlay3D is an open-source, cross-platform 3D native C++ game framework making it easy to learn and write mobile and desktop games. 
+
+<img align="right" src="https://raw.github.com/wiki/blackberry/GamePlay/img/logo.png" alt="gameplay" />
+
+- [Website](http://www.gameplay3d.org/)
+- [Forums](http://www.gameplay3d.org/forums/)
+- [Wiki](https://github.com/blackberry/GamePlay/wiki)
+- [API Reference](http://www.gameplay3d.org/api.php)
+- [Documentation](http://www.gameplay3d.org/docs.php)
 
 
 ## Supported Mobile Platforms
 ## Supported Mobile Platforms
-- BlackBerry 10 and PlayBook 2.0 (using BlackBerry Native SDK)
-- Apple iOS 5.1 (using Apple XCode 4.3.2)
-- Google Android 2.3+ (using Google Android NDK, SDK API level 9+)
+- BlackBerry 10 and PlayBook (using [BlackBerry Native SDK](http://developer.blackberry.com/native/))
+- Apple iOS 5 (using Apple XCode 4)
+- Google Android 2.3+ (using Google Android NDK)
 
 
 ## Supported Desktop Platforms
 ## Supported Desktop Platforms
 - Microsoft Windows 7 (using Microsoft Visual Studio 2010)
 - Microsoft Windows 7 (using Microsoft Visual Studio 2010)
-- Apple MacOS X (using Apple XCode 4.3.2)
+- Apple MacOS X (using Apple XCode 4)
 - Linux (using CMake or CodeBlocks 10)
 - Linux (using CMake or CodeBlocks 10)
 
 
 ## Roadmap for 'next' branch
 ## Roadmap for 'next' branch
-- AI Pathfinding
-- Terrain and Water
-- Asset Pipeline improvements
+- [Version 1.7.0 Milestone](https://github.com/blackberry/GamePlay/issues?milestone=4)
 
 
 ## License
 ## License
-The project is open sourced under the Apache 2.0 license.
+The project is open sourced under the [Apache 2.0 license](http://www.tldrlegal.com/license/apache-license-2.0-%28apache-2.0%29).
+
+## Bug Reporting
+Please log bugs under [Issues](https://github.com/blackberry/GamePlay/issues) on github.
+If you are unsure if your problem is a bug then post on the [Help Forum](http://www.gameplay3d.org/forums/viewforum.php?f=3).
 
 
-## Bug Reporting and Feature Requests
-If you find a bug in a Sample, or have an enhancement request, simply file an 
-[Issue](https://github.com/blackberry/GamePlay/issues) and send a message (via github messages) 
-to the Committers to the project to let them know that you have filed 
-an [Issue](https://github.com/blackberry/GamePlay/issues).
+## Feature Requests
+Please post feature requests on the [Feature Request Forum](http://www.gameplay3d.org/forums/viewforum.php?f=4). Approved feature requests will be added to the github issues list. 
 
 
 ## Disclaimer
 ## Disclaimer
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 

+ 0 - 8
cmake/README.md

@@ -1,8 +0,0 @@
-## Building with CMake
-Run the following command lines from this directory:
-* cmake ..
-* make
-
-
-
-

+ 1 - 1
gameplay-encoder/src/Scene.h

@@ -59,7 +59,7 @@ private:
 
 
     /**
     /**
      * Recursively calculates the ambient color of the scene starting at the given node.
      * Recursively calculates the ambient color of the scene starting at the given node.
-     * The ambient light color is added to the givne float array.
+     * The ambient light color is added to the given float array.
      * 
      * 
      * @param node The node in this scene to traverse from.
      * @param node The node in this scene to traverse from.
      * @param values Pointer to 3 floats that contains the calculated ambient color.
      * @param values Pointer to 3 floats that contains the calculated ambient color.

+ 2 - 2
gameplay-luagen/gameplay-luagen.vcxproj

@@ -78,7 +78,7 @@
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalLibraryDirectories>..\external-deps\tinyxml2\lib\windows;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\external-deps\tinyxml2\lib\windows\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies>tinyxml2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalDependencies>tinyxml2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     </Link>
     <PreBuildEvent>
     <PreBuildEvent>
@@ -110,7 +110,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalLibraryDirectories>..\external-deps\tinyxml2\lib\windows;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>..\external-deps\tinyxml2\lib\windows\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <AdditionalDependencies>tinyxml2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalDependencies>tinyxml2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     </Link>
     <PreBuildEvent>
     <PreBuildEvent>

+ 31 - 31
gameplay-template/android/template.AndroidManifest.xml

@@ -1,32 +1,32 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="TEMPLATE_UUID"
-        android:versionCode="1"
-        android:versionName="1.0">
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-        
-    <!-- This is the platform API where the app was introduced. -->
-    <uses-sdk android:minSdkVersion="9" />
-	<uses-feature android:glEsVersion="0x00020000"/>
-
-    <application android:icon="@drawable/icon" android:label="@string/app_name" android:hasCode="true">
-
-        <!-- Our activity is the built-in NativeActivity framework class.
-             This will take care of integrating with our NDK code. -->
-        <activity android:name="android.app.NativeActivity"
-                android:label="@string/app_name"
-                android:configChanges="orientation|keyboardHidden"
-				android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
-				android:screenOrientation="landscape">
-            <!-- Tell NativeActivity the name of or .so -->
-            <meta-data android:name="android.app.lib_name"
-                    android:value="TEMPLATE_PROJECT" />
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="TEMPLATE_UUID"
+        android:versionCode="1"
+        android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+        
+    <!-- This is the platform API where the app was introduced. -->
+    <uses-sdk android:minSdkVersion="9" />
+	<uses-feature android:glEsVersion="0x00020000"/>
+
+    <application android:icon="@drawable/icon" android:label="@string/app_name" android:hasCode="true">
+
+        <!-- Our activity is the built-in NativeActivity framework class.
+             This will take care of integrating with our NDK code. -->
+        <activity android:name="android.app.NativeActivity"
+                android:label="@string/app_name"
+                android:configChanges="orientation|keyboardHidden"
+				android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+				android:screenOrientation="landscape">
+            <!-- Tell NativeActivity the name of or .so -->
+            <meta-data android:name="android.app.lib_name"
+                    android:value="TEMPLATE_PROJECT" />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
 </manifest> 
 </manifest> 

+ 3 - 4
gameplay-template/android/template.build.xml

@@ -62,10 +62,9 @@
        If this is not done in place, override ${out.dex.input.absolute.dir} */
        If this is not done in place, override ${out.dex.input.absolute.dir} */
        -->
        -->
     <target name="-post-compile">
     <target name="-post-compile">
-        <copy file="../res/box.gpb" tofile="assets/res/box.gpb"/>
-        <copy file="../res/box.material" tofile="assets/res/box.material"/>
-        <copy file="../res/colored.vert" tofile="assets/res/colored.vert"/>
-        <copy file="../res/colored.frag" tofile="assets/res/colored.frag"/>
+        <copy todir="assets/res">
+            <fileset dir="../res" />
+        </copy>
     </target>
     </target>
 
 
     <!-- Import the actual build file.
     <!-- Import the actual build file.

+ 4 - 4
gameplay-template/gameplay-template.vcxproj

@@ -198,7 +198,7 @@
       <SubSystem>Windows</SubSystem>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows;GAMEPLAY_PATH/external-deps/bullet/lib/windows;GAMEPLAY_PATH/external-deps/openal/lib/windows;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows;GAMEPLAY_PATH/external-deps/glew/lib/windows;GAMEPLAY_PATH/external-deps/libpng/lib/windows;GAMEPLAY_PATH/external-deps/zlib/lib/windows;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows/x86;GAMEPLAY_PATH/external-deps/bullet/lib/windows/x86;GAMEPLAY_PATH/external-deps/openal/lib/windows/x86;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows/x86;GAMEPLAY_PATH/external-deps/glew/lib/windows/x86;GAMEPLAY_PATH/external-deps/libpng/lib/windows/x86;GAMEPLAY_PATH/external-deps/zlib/lib/windows/x86;GAMEPLAY_PATH/gameplay/windows/x86/$(Configuration)</AdditionalLibraryDirectories>
     </Link>
     </Link>
     <PostBuildEvent>
     <PostBuildEvent>
       <Command>
       <Command>
@@ -230,7 +230,7 @@
       <SubSystem>Windows</SubSystem>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows;GAMEPLAY_PATH/external-deps/bullet/lib/windows;GAMEPLAY_PATH/external-deps/openal/lib/windows;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows;GAMEPLAY_PATH/external-deps/glew/lib/windows;GAMEPLAY_PATH/external-deps/libpng/lib/windows;GAMEPLAY_PATH/external-deps/zlib/lib/windows;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows/x64;GAMEPLAY_PATH/external-deps/bullet/lib/windows/x64;GAMEPLAY_PATH/external-deps/openal/lib/windows/x64;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows/x64;GAMEPLAY_PATH/external-deps/glew/lib/windows/x64;GAMEPLAY_PATH/external-deps/libpng/lib/windows/x64;GAMEPLAY_PATH/external-deps/zlib/lib/windows/x64;GAMEPLAY_PATH/gameplay/windows/x64/$(Configuration)</AdditionalLibraryDirectories>
     </Link>
     </Link>
     <PostBuildEvent>
     <PostBuildEvent>
       <Command>
       <Command>
@@ -262,7 +262,7 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows;GAMEPLAY_PATH/external-deps/bullet/lib/windows;GAMEPLAY_PATH/external-deps/openal/lib/windows;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows;GAMEPLAY_PATH/external-deps/glew/lib/windows;GAMEPLAY_PATH/external-deps/libpng/lib/windows;GAMEPLAY_PATH/external-deps/zlib/lib/windows;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows/x86;GAMEPLAY_PATH/external-deps/bullet/lib/windows/x86;GAMEPLAY_PATH/external-deps/openal/lib/windows/x86;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows/x86;GAMEPLAY_PATH/external-deps/glew/lib/windows/x86;GAMEPLAY_PATH/external-deps/libpng/lib/windows/x86;GAMEPLAY_PATH/external-deps/zlib/lib/windows/x86;GAMEPLAY_PATH/gameplay/windows/x86/$(Configuration)</AdditionalLibraryDirectories>
     </Link>
     </Link>
     <PostBuildEvent>
     <PostBuildEvent>
       <Command>
       <Command>
@@ -294,7 +294,7 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalDependencies>lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;%(AdditionalDependencies)</AdditionalDependencies>
-      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows;GAMEPLAY_PATH/external-deps/bullet/lib/windows;GAMEPLAY_PATH/external-deps/openal/lib/windows;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows;GAMEPLAY_PATH/external-deps/glew/lib/windows;GAMEPLAY_PATH/external-deps/libpng/lib/windows;GAMEPLAY_PATH/external-deps/zlib/lib/windows;GAMEPLAY_PATH/gameplay/$(Configuration)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>GAMEPLAY_PATH/external-deps/lua/lib/windows/x64;GAMEPLAY_PATH/external-deps/bullet/lib/windows/x64;GAMEPLAY_PATH/external-deps/openal/lib/windows/x64;GAMEPLAY_PATH/external-deps/oggvorbis/lib/windows/x64;GAMEPLAY_PATH/external-deps/glew/lib/windows/x64;GAMEPLAY_PATH/external-deps/libpng/lib/windows/x64;GAMEPLAY_PATH/external-deps/zlib/lib/windows/x64;GAMEPLAY_PATH/gameplay/windows/x64/$(Configuration)</AdditionalLibraryDirectories>
     </Link>
     </Link>
     <PostBuildEvent>
     <PostBuildEvent>
       <Command>
       <Command>

+ 1 - 1
gameplay-template/res/box.material

@@ -10,7 +10,7 @@ material box
             
             
             // uniforms
             // uniforms
             u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX
             u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX
-            u_inverseTransposeWorldViewMatrix = INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX
+            u_inverseTransposeWorldMatrix = INVERSE_TRANSPOSE_WORLD_MATRIX
             u_diffuseColor = 1.0, 1.0, 1.0, 1.0
             u_diffuseColor = 1.0, 1.0, 1.0, 1.0
 
 
             // render state
             // render state

+ 2 - 2
gameplay-template/res/colored.vert

@@ -4,7 +4,7 @@ attribute vec3 a_normal;                            // Vertex Normal (x, y, z)
 
 
 // Uniforms
 // Uniforms
 uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
 uniform mat4 u_worldViewProjectionMatrix;           // Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;     // Matrix to transform a normal to view space.
+uniform mat4 u_inverseTransposeWorldMatrix;         // Matrix to transform a normal to view space.
 
 
 // Outputs
 // Outputs
 varying vec3 v_normalVector;                        // Normal vector in view space.
 varying vec3 v_normalVector;                        // Normal vector in view space.
@@ -19,6 +19,6 @@ void main()
     gl_Position = u_worldViewProjectionMatrix * position;
     gl_Position = u_worldViewProjectionMatrix * position;
 
 
     // Transform normal to view space.
     // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldMatrix[0].xyz, u_inverseTransposeWorldMatrix[1].xyz, u_inverseTransposeWorldMatrix[2].xyz);
     v_normalVector = inverseTransposeWorldViewMatrix * normal;
     v_normalVector = inverseTransposeWorldViewMatrix * normal;
 }
 }

+ 1 - 1
gameplay.doxyfile

@@ -32,7 +32,7 @@ PROJECT_NAME           = gameplay
 # This could be handy for archiving the generated documentation or 
 # This could be handy for archiving the generated documentation or 
 # if some version control system is used.
 # if some version control system is used.
 
 
-PROJECT_NUMBER         = 1.5.0
+PROJECT_NUMBER         = 1.6.0
 
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description 
 # for a project that appears at the top of each page and should give viewer 
 # for a project that appears at the top of each page and should give viewer 

+ 11 - 7
gameplay/.cproject

@@ -23,6 +23,7 @@
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.defines.1481323494" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 								<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="_FORTIFY_SOURCE=2"/>
+									<listOptionValue builtIn="false" value="BT_USE_NEON"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.2133604142" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 								<option id="com.qnx.qcc.option.compiler.includePath.2133604142" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/lua/include&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/lua/include&quot;"/>
@@ -80,10 +81,11 @@
 							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1117051584" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
 							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1117051584" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
 							<builder buildPath="${workspace_loc:/gameplay/Device-Release}" id="cdt.managedbuild.target.gnu.builder.base.1199322737" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
 							<builder buildPath="${workspace_loc:/gameplay/Device-Release}" id="cdt.managedbuild.target.gnu.builder.base.1199322737" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
 							<tool id="com.qnx.qcc.tool.compiler.1345567866" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
 							<tool id="com.qnx.qcc.tool.compiler.1345567866" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
-								<option id="com.qnx.qcc.option.compiler.optlevel.1056793982" name="Optimization Level" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.2" valueType="enumerated"/>
+								<option id="com.qnx.qcc.option.compiler.optlevel.1056793982" name="Optimization Level" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.1" valueType="enumerated"/>
 								<option id="com.qnx.qcc.option.compiler.security.324540233" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.324540233" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.defines.398688299" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 								<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="_FORTIFY_SOURCE=2"/>
+									<listOptionValue builtIn="false" value="BT_USE_NEON"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1670164593" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 								<option id="com.qnx.qcc.option.compiler.includePath.1670164593" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/bullet/include&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/bullet/include&quot;"/>
@@ -95,7 +97,7 @@
 								<option id="com.qnx.qcc.option.compiler.ccoptions.1122311163" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions" valueType="stringList">
 								<option id="com.qnx.qcc.option.compiler.ccoptions.1122311163" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-mfpu=neon"/>
 									<listOptionValue builtIn="false" value="-mfpu=neon"/>
 								</option>
 								</option>
-								<option id="com.qnx.qcc.option.compiler.qccoptions.1770609643" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
+								<option id="com.qnx.qcc.option.compiler.qccoptions.1770609643" name="QCC Options" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 								</option>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1380846613" superClass="com.qnx.qcc.inputType.compiler"/>
 								<inputType id="com.qnx.qcc.inputType.compiler.1380846613" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -144,6 +146,7 @@
 								<option id="com.qnx.qcc.option.compiler.security.1649809766" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.1649809766" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.defines.276653249" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 								<option id="com.qnx.qcc.option.compiler.defines.276653249" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+									<listOptionValue builtIn="false" value="BY_USE_NEON"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1503059677" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 								<option id="com.qnx.qcc.option.compiler.includePath.1503059677" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/bullet/include&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/bullet/include&quot;"/>
@@ -155,7 +158,7 @@
 								<option id="com.qnx.qcc.option.compiler.ccoptions.1956270067" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions" valueType="stringList">
 								<option id="com.qnx.qcc.option.compiler.ccoptions.1956270067" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-mfpu=neon"/>
 									<listOptionValue builtIn="false" value="-mfpu=neon"/>
 								</option>
 								</option>
-								<option id="com.qnx.qcc.option.compiler.qccoptions.1366354884" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
+								<option id="com.qnx.qcc.option.compiler.qccoptions.1366354884" name="QCC Options" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 								</option>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.81809638" superClass="com.qnx.qcc.inputType.compiler"/>
 								<inputType id="com.qnx.qcc.inputType.compiler.81809638" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -207,6 +210,7 @@
 								<option id="com.qnx.qcc.option.compiler.security.1227516972" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.1227516972" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.defines.374283024" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 								<option id="com.qnx.qcc.option.compiler.defines.374283024" name="Defines (-D)" superClass="com.qnx.qcc.option.compiler.defines" valueType="definedSymbols">
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
 									<listOptionValue builtIn="false" value="_FORTIFY_SOURCE=2"/>
+									<listOptionValue builtIn="false" value="BT_USE_NEON"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.includePath.1769677874" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 								<option id="com.qnx.qcc.option.compiler.includePath.1769677874" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/bullet/include&quot;"/>
 									<listOptionValue builtIn="false" value="&quot;../../external-deps/bullet/include&quot;"/>
@@ -218,7 +222,7 @@
 								<option id="com.qnx.qcc.option.compiler.ccoptions.47607907" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions" valueType="stringList">
 								<option id="com.qnx.qcc.option.compiler.ccoptions.47607907" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-mfpu=neon"/>
 									<listOptionValue builtIn="false" value="-mfpu=neon"/>
 								</option>
 								</option>
-								<option id="com.qnx.qcc.option.compiler.qccoptions.146547607" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
+								<option id="com.qnx.qcc.option.compiler.qccoptions.146547607" name="QCC Options" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 								</option>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.2007171407" superClass="com.qnx.qcc.inputType.compiler"/>
 								<inputType id="com.qnx.qcc.inputType.compiler.2007171407" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -277,7 +281,7 @@
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.ccoptions.1432778691" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions"/>
 								<option id="com.qnx.qcc.option.compiler.ccoptions.1432778691" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions"/>
-								<option id="com.qnx.qcc.option.compiler.qccoptions.245518255" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
+								<option id="com.qnx.qcc.option.compiler.qccoptions.245518255" name="QCC Options" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 								</option>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1038720310" superClass="com.qnx.qcc.inputType.compiler"/>
 								<inputType id="com.qnx.qcc.inputType.compiler.1038720310" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -336,7 +340,7 @@
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.ccoptions.663337616" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions"/>
 								<option id="com.qnx.qcc.option.compiler.ccoptions.663337616" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions"/>
-								<option id="com.qnx.qcc.option.compiler.qccoptions.288926109" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
+								<option id="com.qnx.qcc.option.compiler.qccoptions.288926109" name="QCC Options" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 								</option>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1961855927" superClass="com.qnx.qcc.inputType.compiler"/>
 								<inputType id="com.qnx.qcc.inputType.compiler.1961855927" superClass="com.qnx.qcc.inputType.compiler"/>
@@ -396,7 +400,7 @@
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 									<listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
 								</option>
 								</option>
 								<option id="com.qnx.qcc.option.compiler.ccoptions.346770186" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions"/>
 								<option id="com.qnx.qcc.option.compiler.ccoptions.346770186" name="Compiler Options (-Wc,)" superClass="com.qnx.qcc.option.compiler.ccoptions"/>
-								<option id="com.qnx.qcc.option.compiler.qccoptions.1085566269" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
+								<option id="com.qnx.qcc.option.compiler.qccoptions.1085566269" name="QCC Options" superClass="com.qnx.qcc.option.compiler.qccoptions" valueType="stringList">
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 									<listOptionValue builtIn="false" value="-Wno-psabi"/>
 								</option>
 								</option>
 								<inputType id="com.qnx.qcc.inputType.compiler.1658185881" superClass="com.qnx.qcc.inputType.compiler"/>
 								<inputType id="com.qnx.qcc.inputType.compiler.1658185881" superClass="com.qnx.qcc.inputType.compiler"/>

+ 1 - 0
gameplay/gameplay.vcxproj

@@ -573,6 +573,7 @@
     <ClInclude Include="src\ScriptTarget.h" />
     <ClInclude Include="src\ScriptTarget.h" />
     <ClInclude Include="src\Slider.h" />
     <ClInclude Include="src\Slider.h" />
     <ClInclude Include="src\SpriteBatch.h" />
     <ClInclude Include="src\SpriteBatch.h" />
+    <ClInclude Include="src\Stream.h" />
     <ClInclude Include="src\Technique.h" />
     <ClInclude Include="src\Technique.h" />
     <ClInclude Include="src\TextBox.h" />
     <ClInclude Include="src\TextBox.h" />
     <ClInclude Include="src\Texture.h" />
     <ClInclude Include="src\Texture.h" />

+ 3 - 0
gameplay/gameplay.vcxproj.filters

@@ -1622,6 +1622,9 @@
     <ClInclude Include="src\lua\lua_LoggerLevel.h">
     <ClInclude Include="src\lua\lua_LoggerLevel.h">
       <Filter>lua</Filter>
       <Filter>lua</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="src\Stream.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <None Include="src\Game.inl">
     <None Include="src\Game.inl">

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

@@ -1701,6 +1701,8 @@
 		5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
 		5BD52674150F8258004C9099 /* PhysicsCollisionObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */; };
 		5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
 		5BD52675150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
 		5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
 		5BD52676150F8258004C9099 /* PhysicsCollisionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */; };
+		9FC6EE731665304F00F39955 /* Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FC6EE721665304F00F39955 /* Stream.h */; };
+		9FC6EE741665304F00F39955 /* Stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FC6EE721665304F00F39955 /* Stream.h */; };
 		B67EC8EB161DFC8E000B4D12 /* lua_Logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B67EC8E7161DFC8E000B4D12 /* lua_Logger.cpp */; };
 		B67EC8EB161DFC8E000B4D12 /* lua_Logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B67EC8E7161DFC8E000B4D12 /* lua_Logger.cpp */; };
 		B67EC8EC161DFC8E000B4D12 /* lua_Logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B67EC8E7161DFC8E000B4D12 /* lua_Logger.cpp */; };
 		B67EC8EC161DFC8E000B4D12 /* lua_Logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B67EC8E7161DFC8E000B4D12 /* lua_Logger.cpp */; };
 		B67EC8ED161DFC8E000B4D12 /* lua_Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = B67EC8E8161DFC8E000B4D12 /* lua_Logger.h */; };
 		B67EC8ED161DFC8E000B4D12 /* lua_Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = B67EC8E8161DFC8E000B4D12 /* lua_Logger.h */; };
@@ -1715,7 +1717,7 @@
 		B67EC8F9161DFCA8000B4D12 /* Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = B67EC8F5161DFCA8000B4D12 /* Logger.h */; };
 		B67EC8F9161DFCA8000B4D12 /* Logger.h in Headers */ = {isa = PBXBuildFile; fileRef = B67EC8F5161DFCA8000B4D12 /* Logger.h */; };
 		F1616ABC1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
 		F1616ABC1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
 		F1616ABD1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
 		F1616ABD1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
-		F18024A51627000D001BFF87 /* gameplay-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A31627000D001BFF87 /* gameplay-main-ios.mm */; };
+		F18024A51627000D001BFF87 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A31627000D001BFF87 /* gameplay-main-ios.mm */; };
 		F18024A61627000D001BFF87 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A31627000D001BFF87 /* gameplay-main-ios.mm */; };
 		F18024A61627000D001BFF87 /* gameplay-main-ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A31627000D001BFF87 /* gameplay-main-ios.mm */; };
 		F18024A71627000D001BFF87 /* gameplay-main-macosx.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A41627000D001BFF87 /* gameplay-main-macosx.mm */; };
 		F18024A71627000D001BFF87 /* gameplay-main-macosx.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A41627000D001BFF87 /* gameplay-main-macosx.mm */; };
 		F18024A81627000D001BFF87 /* gameplay-main-macosx.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A41627000D001BFF87 /* gameplay-main-macosx.mm */; };
 		F18024A81627000D001BFF87 /* gameplay-main-macosx.mm in Sources */ = {isa = PBXBuildFile; fileRef = F18024A41627000D001BFF87 /* gameplay-main-macosx.mm */; };
@@ -2610,6 +2612,7 @@
 		5BD5266C150F8257004C9099 /* PhysicsCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCharacter.h; path = src/PhysicsCharacter.h; sourceTree = SOURCE_ROOT; };
 		5BD5266C150F8257004C9099 /* PhysicsCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCharacter.h; path = src/PhysicsCharacter.h; sourceTree = SOURCE_ROOT; };
 		5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionObject.cpp; path = src/PhysicsCollisionObject.cpp; sourceTree = SOURCE_ROOT; };
 		5BD5266D150F8257004C9099 /* PhysicsCollisionObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PhysicsCollisionObject.cpp; path = src/PhysicsCollisionObject.cpp; sourceTree = SOURCE_ROOT; };
 		5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionObject.h; path = src/PhysicsCollisionObject.h; sourceTree = SOURCE_ROOT; };
 		5BD5266E150F8258004C9099 /* PhysicsCollisionObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PhysicsCollisionObject.h; path = src/PhysicsCollisionObject.h; sourceTree = SOURCE_ROOT; };
+		9FC6EE721665304F00F39955 /* Stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Stream.h; path = src/Stream.h; sourceTree = SOURCE_ROOT; };
 		B67EC8E7161DFC8E000B4D12 /* lua_Logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_Logger.cpp; sourceTree = "<group>"; };
 		B67EC8E7161DFC8E000B4D12 /* lua_Logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_Logger.cpp; sourceTree = "<group>"; };
 		B67EC8E8161DFC8E000B4D12 /* lua_Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_Logger.h; sourceTree = "<group>"; };
 		B67EC8E8161DFC8E000B4D12 /* lua_Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_Logger.h; sourceTree = "<group>"; };
 		B67EC8E9161DFC8E000B4D12 /* lua_LoggerLevel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_LoggerLevel.cpp; sourceTree = "<group>"; };
 		B67EC8E9161DFC8E000B4D12 /* lua_LoggerLevel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_LoggerLevel.cpp; sourceTree = "<group>"; };
@@ -2889,6 +2892,7 @@
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
 				42CD0E2F147D8FF50000361E /* SpriteBatch.cpp */,
 				42CD0E30147D8FF50000361E /* SpriteBatch.h */,
 				42CD0E30147D8FF50000361E /* SpriteBatch.h */,
 				42CD0E31147D8FF50000361E /* Technique.cpp */,
 				42CD0E31147D8FF50000361E /* Technique.cpp */,
+				9FC6EE721665304F00F39955 /* Stream.h */,
 				42CD0E32147D8FF50000361E /* Technique.h */,
 				42CD0E32147D8FF50000361E /* Technique.h */,
 				42CD0E33147D8FF50000361E /* Texture.cpp */,
 				42CD0E33147D8FF50000361E /* Texture.cpp */,
 				42CD0E34147D8FF50000361E /* Texture.h */,
 				42CD0E34147D8FF50000361E /* Texture.h */,
@@ -4083,6 +4087,7 @@
 				B67EC8ED161DFC8E000B4D12 /* lua_Logger.h in Headers */,
 				B67EC8ED161DFC8E000B4D12 /* lua_Logger.h in Headers */,
 				B67EC8F1161DFC8E000B4D12 /* lua_LoggerLevel.h in Headers */,
 				B67EC8F1161DFC8E000B4D12 /* lua_LoggerLevel.h in Headers */,
 				B67EC8F8161DFCA8000B4D12 /* Logger.h in Headers */,
 				B67EC8F8161DFCA8000B4D12 /* Logger.h in Headers */,
+				9FC6EE731665304F00F39955 /* Stream.h in Headers */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};
@@ -4513,6 +4518,7 @@
 				B67EC8EE161DFC8E000B4D12 /* lua_Logger.h in Headers */,
 				B67EC8EE161DFC8E000B4D12 /* lua_Logger.h in Headers */,
 				B67EC8F2161DFC8E000B4D12 /* lua_LoggerLevel.h in Headers */,
 				B67EC8F2161DFC8E000B4D12 /* lua_LoggerLevel.h in Headers */,
 				B67EC8F9161DFCA8000B4D12 /* Logger.h in Headers */,
 				B67EC8F9161DFCA8000B4D12 /* Logger.h in Headers */,
+				9FC6EE741665304F00F39955 /* Stream.h in Headers */,
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

+ 2 - 2
gameplay/res/shaders/colored.vert

@@ -14,7 +14,7 @@ varying vec3 v_color;										// Output Vertex Color
 
 
 // Uniforms
 // Uniforms
 uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space.
 uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space.
-uniform mat4 u_inverseTransposeWorldViewMatrix;				// Matrix to transform a normal to view space.
+uniform mat4 u_inverseTransposeWorldMatrix;				    // Matrix to transform a normal to view space.
 #if defined(SKINNING)
 #if defined(SKINNING)
 uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
 uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
 #endif
 #endif
@@ -68,7 +68,7 @@ void main()
     gl_Position = u_worldViewProjectionMatrix * position;
     gl_Position = u_worldViewProjectionMatrix * position;
 
 
     // Transform normal to view space.
     // Transform normal to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldMatrix[0].xyz, u_inverseTransposeWorldMatrix[1].xyz, u_inverseTransposeWorldMatrix[2].xyz);
     v_normalVector = inverseTransposeWorldViewMatrix * normal;
     v_normalVector = inverseTransposeWorldViewMatrix * normal;
 
 
     // Apply light.
     // Apply light.

+ 2 - 2
gameplay/res/shaders/lib/attributes-skinning.vert

@@ -37,6 +37,8 @@ vec4 getPosition()
     return _skinnedPosition;    
     return _skinnedPosition;    
 }
 }
 
 
+#if defined(LIGHTING)
+
 void skinTangentSpaceVector(vec3 vector, float blendWeight, int matrixIndex)
 void skinTangentSpaceVector(vec3 vector, float blendWeight, int matrixIndex)
 {
 {
     vec3 tmp;
     vec3 tmp;
@@ -70,8 +72,6 @@ vec3 getTangentSpaceVector(vec3 vector)
     return _skinnedNormal;
     return _skinnedNormal;
 }
 }
 
 
-#if defined(LIGHTING)
-
 vec3 getNormal()
 vec3 getNormal()
 {
 {
     return getTangentSpaceVector(a_normal);
     return getTangentSpaceVector(a_normal);

+ 1 - 4
gameplay/res/shaders/lib/lighting-point.vert

@@ -34,14 +34,11 @@ void applyLight(vec4 position)
     // Compute the light direction.
     // Compute the light direction.
     vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
     vec3 lightDirection = u_pointLightPosition - positionWorldViewSpace.xyz;
    
    
-    vec4 vertexToPointLightDirection;
-    vertexToPointLightDirection.xyz = lightDirection;
-   
     // Attenuation
     // Attenuation
     v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
     v_pointLightAttenuation = 1.0 - dot(lightDirection * u_pointLightRangeInverse, lightDirection * u_pointLightRangeInverse);
 
 
     // Output light direction.
     // Output light direction.
-    v_vertexToPointLightDirection =  vertexToPointLightDirection;
+    v_vertexToPointLightDirection =  lightDirection;
    
    
     #if defined (SPECULAR)
     #if defined (SPECULAR)
    
    

+ 9 - 5
gameplay/res/shaders/textured-bumped.frag

@@ -56,13 +56,17 @@ void main()
 
 
     // Light the pixel
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.a = _baseColor.a;
+    #if defined(TEXTURE_DISCARD_ALPHA)
+    if (gl_FragColor.a < 0.5)
+        discard;
+    #endif
     gl_FragColor.rgb = getLitPixel();
     gl_FragColor.rgb = getLitPixel();
 
 
-	// Global color modulation
-	#if defined(MODULATE_COLOR)
-	gl_FragColor *= u_modulateColor;
-	#endif
-	#if defined(MODULATE_ALPHA)
+    // Global color modulation
+    #if defined(MODULATE_COLOR)
+    gl_FragColor *= u_modulateColor;
+    #endif
+    #if defined(MODULATE_ALPHA)
     gl_FragColor.a *= u_modulateAlpha;
     gl_FragColor.a *= u_modulateAlpha;
     #endif
     #endif
 }
 }

+ 2 - 2
gameplay/res/shaders/textured-bumped.vert

@@ -14,7 +14,7 @@ attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette
 
 
 // Uniforms
 // Uniforms
 uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
 uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
-uniform mat4 u_inverseTransposeWorldViewMatrix;				// Matrix to transform a normal to view space
+uniform mat4 u_inverseTransposeWorldMatrix;				    // Matrix to transform a normal to view space
 #if defined(SKINNING)
 #if defined(SKINNING)
 uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
 uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
 #endif
 #endif
@@ -80,7 +80,7 @@ void main()
     gl_Position = u_worldViewProjectionMatrix * position;
     gl_Position = u_worldViewProjectionMatrix * position;
 
 
     // Transform the normal, tangent and binormals to view space.
     // Transform the normal, tangent and binormals to view space.
-    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    mat3 inverseTransposeWorldViewMatrix = mat3(u_inverseTransposeWorldMatrix[0].xyz, u_inverseTransposeWorldMatrix[1].xyz, u_inverseTransposeWorldMatrix[2].xyz);
     vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);
     vec3 normalVector = normalize(inverseTransposeWorldViewMatrix * normal);
     
     
     // Create a transform to convert a vector to tangent space.
     // Create a transform to convert a vector to tangent space.

+ 11 - 7
gameplay/res/shaders/textured-unlit.frag

@@ -25,19 +25,23 @@ void main()
 {
 {
     // Sample the texture for the color
     // Sample the texture for the color
     gl_FragColor = texture2D(u_diffuseTexture, v_texCoord0);
     gl_FragColor = texture2D(u_diffuseTexture, v_texCoord0);
-	#if defined(TEXTURE_LIGHTMAP)
+    #if defined(TEXTURE_DISCARD_ALPHA)
+    if (gl_FragColor.a < 0.5)
+        discard;
+    #endif
+    #if defined(TEXTURE_LIGHTMAP)
     #if defined(TEXCOORD1)
     #if defined(TEXCOORD1)
     vec4 lightColor = texture2D(u_lightmapTexture, v_texCoord1);
     vec4 lightColor = texture2D(u_lightmapTexture, v_texCoord1);
     #else
     #else
     vec4 lightColor = texture2D(u_lightmapTexture, v_texCoord0);
     vec4 lightColor = texture2D(u_lightmapTexture, v_texCoord0);
     #endif
     #endif
     gl_FragColor.rgb *= lightColor.rgb;
     gl_FragColor.rgb *= lightColor.rgb;
-	#endif
-	// Global color modulation
-	#if defined(MODULATE_COLOR)
-	gl_FragColor *= u_modulateColor;
-	#endif
-	#if defined(MODULATE_ALPHA)
+    #endif
+    // Global color modulation
+    #if defined(MODULATE_COLOR)
+    gl_FragColor *= u_modulateColor;
+    #endif
+    #if defined(MODULATE_ALPHA)
     gl_FragColor.a *= u_modulateAlpha;
     gl_FragColor.a *= u_modulateAlpha;
     #endif
     #endif
 }
 }

+ 4 - 0
gameplay/res/shaders/textured.frag

@@ -55,6 +55,10 @@ void main()
 
 
     // Light the pixel
     // Light the pixel
     gl_FragColor.a = _baseColor.a;
     gl_FragColor.a = _baseColor.a;
+    #if defined(TEXTURE_DISCARD_ALPHA)
+    if (gl_FragColor.a < 0.5)
+        discard;
+    #endif
     gl_FragColor.rgb = getLitPixel();
     gl_FragColor.rgb = getLitPixel();
 	
 	
 	// Global color modulation
 	// Global color modulation

+ 2 - 2
gameplay/res/shaders/textured.vert

@@ -11,7 +11,7 @@ attribute vec4 a_blendIndices;								// Vertex blend index int u_matrixPalette
 
 
 // Uniforms
 // Uniforms
 uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
 uniform mat4 u_worldViewProjectionMatrix;					// Matrix to transform a position to clip space
-uniform mat4 u_inverseTransposeWorldViewMatrix;				// Matrix to transform a normal to view space
+uniform mat4 u_inverseTransposeWorldMatrix;				    // Matrix to transform a normal to view space
 #if defined(SKINNING)
 #if defined(SKINNING)
 uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
 uniform vec4 u_matrixPalette[SKINNING_JOINT_COUNT * 3];		// Array of 4x3 matrices
 #endif
 #endif
@@ -70,7 +70,7 @@ void main()
     gl_Position = u_worldViewProjectionMatrix * position;
     gl_Position = u_worldViewProjectionMatrix * position;
 
 
     // Transform normal to view space.
     // Transform normal to view space.
-    mat3 normalMatrix = mat3(u_inverseTransposeWorldViewMatrix[0].xyz, u_inverseTransposeWorldViewMatrix[1].xyz, u_inverseTransposeWorldViewMatrix[2].xyz);
+    mat3 normalMatrix = mat3(u_inverseTransposeWorldMatrix[0].xyz, u_inverseTransposeWorldMatrix[1].xyz, u_inverseTransposeWorldMatrix[2].xyz);
     v_normalVector = normalMatrix * normal;
     v_normalVector = normalMatrix * normal;
 
 
     // Apply light.
     // Apply light.

+ 1 - 1
gameplay/src/Animation.cpp

@@ -18,7 +18,7 @@ namespace gameplay
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned int* keyTimes, float* keyValues, unsigned int type)
 Animation::Animation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned int* keyTimes, float* keyValues, unsigned int type)
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0L), _defaultClip(NULL), _clips(NULL)
     : _controller(Game::getInstance()->getAnimationController()), _id(id), _duration(0L), _defaultClip(NULL), _clips(NULL)
 {
 {
-    createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
+    createChannel(target, propertyId, keyCount, keyTimes, keyValues, type);
 
 
     // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
     // Release the animation because a newly created animation has a ref count of 1 and the channels hold the ref to animation.
     release();
     release();

+ 81 - 55
gameplay/src/AudioBuffer.cpp

@@ -8,6 +8,36 @@ namespace gameplay
 // Audio buffer cache
 // Audio buffer cache
 static std::vector<AudioBuffer*> __buffers;
 static std::vector<AudioBuffer*> __buffers;
 
 
+// Callbacks for loading an ogg file using Stream
+static size_t readStream(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    return stream->read(ptr, size, nmemb);
+}
+
+static int seekStream(void *datasource, ogg_int64_t offset, int whence)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    return !stream->seek(offset, whence);
+}
+
+static int closeStream(void *datasource)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    stream->close();
+    return 0;
+}
+
+static long tellStream(void *datasource)
+{
+    GP_ASSERT(datasource);
+    Stream* stream = reinterpret_cast<Stream*>(datasource);
+    return stream->position();
+}
+
 AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
 AudioBuffer::AudioBuffer(const char* path, ALuint buffer)
     : _filePath(path), _alBuffer(buffer)
     : _filePath(path), _alBuffer(buffer)
 {
 {
@@ -63,8 +93,8 @@ AudioBuffer* AudioBuffer::create(const char* path)
     }
     }
     
     
     // Load sound file.
     // Load sound file.
-    FILE* file = FileSystem::openFile(path, "rb");
-    if (!file)
+    std::auto_ptr<Stream> stream(FileSystem::open(path));
+    if (stream.get() == NULL || !stream->canRead())
     {
     {
         GP_ERROR("Failed to load audio file %s.", path);
         GP_ERROR("Failed to load audio file %s.", path);
         goto cleanup;
         goto cleanup;
@@ -72,7 +102,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     
     
     // Read the file header
     // Read the file header
     char header[12];
     char header[12];
-    if (fread(header, 1, 12, file) != 12)
+    if (stream->read(header, 1, 12) != 12)
     {
     {
         GP_ERROR("Invalid header for audio file %s.", path);
         GP_ERROR("Invalid header for audio file %s.", path);
         goto cleanup;
         goto cleanup;
@@ -81,7 +111,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     // Check the file format
     // Check the file format
     if (memcmp(header, "RIFF", 4) == 0)
     if (memcmp(header, "RIFF", 4) == 0)
     {
     {
-        if (!AudioBuffer::loadWav(file, alBuffer))
+        if (!AudioBuffer::loadWav(stream.get(), alBuffer))
         {
         {
             GP_ERROR("Invalid wave file: %s", path);
             GP_ERROR("Invalid wave file: %s", path);
             goto cleanup;
             goto cleanup;
@@ -89,7 +119,7 @@ AudioBuffer* AudioBuffer::create(const char* path)
     }
     }
     else if (memcmp(header, "OggS", 4) == 0)
     else if (memcmp(header, "OggS", 4) == 0)
     {
     {
-        if (!AudioBuffer::loadOgg(file, alBuffer))
+        if (!AudioBuffer::loadOgg(stream.get(), alBuffer))
         {
         {
             GP_ERROR("Invalid ogg file: %s", path);
             GP_ERROR("Invalid ogg file: %s", path);
             goto cleanup;
             goto cleanup;
@@ -101,10 +131,6 @@ AudioBuffer* AudioBuffer::create(const char* path)
         goto cleanup;
         goto cleanup;
     }
     }
 
 
-    //NOTE: loadOgg actually sets this null, so it is expected
-    if (file)    
-        fclose(file);
-
     buffer = new AudioBuffer(path, alBuffer);
     buffer = new AudioBuffer(path, alBuffer);
 
 
     // Add the buffer to the cache.
     // Add the buffer to the cache.
@@ -113,34 +139,32 @@ AudioBuffer* AudioBuffer::create(const char* path)
     return buffer;
     return buffer;
     
     
 cleanup:
 cleanup:
-    
-    if (file)
-        fclose(file);
     if (alBuffer)
     if (alBuffer)
         AL_CHECK( alDeleteBuffers(1, &alBuffer) );
         AL_CHECK( alDeleteBuffers(1, &alBuffer) );
     return NULL;
     return NULL;
 }
 }
 
 
-bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
+bool AudioBuffer::loadWav(Stream* stream, ALuint buffer)
 {
 {
-    GP_ASSERT(file);
-    unsigned char stream[12];
+    GP_ASSERT(stream);
+
+    unsigned char data[12];
     
     
     // Verify the wave fmt magic value meaning format.
     // Verify the wave fmt magic value meaning format.
-    if (fread(stream, 1, 8, file) != 8 || memcmp(stream, "fmt ", 4) != 0 )
+    if (stream->read(data, 1, 8) != 8 || memcmp(data, "fmt ", 4) != 0 )
     {
     {
         GP_ERROR("Failed to verify the magic value for the wave file format.");
         GP_ERROR("Failed to verify the magic value for the wave file format.");
         return false;
         return false;
     }
     }
     
     
     unsigned int section_size;
     unsigned int section_size;
-    section_size  = stream[7]<<24;
-    section_size |= stream[6]<<16;
-    section_size |= stream[5]<<8;
-    section_size |= stream[4];
+    section_size  = data[7]<<24;
+    section_size |= data[6]<<16;
+    section_size |= data[5]<<8;
+    section_size |= data[4];
 
 
     // Check for a valid pcm format.
     // Check for a valid pcm format.
-    if (fread(stream, 1, 2, file) != 2 || stream[1] != 0 || stream[0] != 1)
+    if (stream->read(data, 1, 2) != 2 || data[1] != 0 || data[0] != 1)
     {
     {
         GP_ERROR("Unsupported audio file format (must be a valid PCM format).");
         GP_ERROR("Unsupported audio file format (must be a valid PCM format).");
         return false;
         return false;
@@ -148,31 +172,31 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     
     
     // Get the channel count (16-bit little-endian).
     // Get the channel count (16-bit little-endian).
     int channels;
     int channels;
-    if (fread(stream, 1, 2, file) != 2)
+    if (stream->read(data, 1, 2) != 2)
     {
     {
         GP_ERROR("Failed to read the wave file's channel count.");
         GP_ERROR("Failed to read the wave file's channel count.");
         return false;
         return false;
     }
     }
-    channels  = stream[1]<<8;
-    channels |= stream[0];
+    channels  = data[1]<<8;
+    channels |= data[0];
     
     
     // Get the sample frequency (32-bit little-endian).
     // Get the sample frequency (32-bit little-endian).
     ALuint frequency;
     ALuint frequency;
-    if (fread(stream, 1, 4, file) != 4)
+    if (stream->read(data, 1, 4) != 4)
     {
     {
         GP_ERROR("Failed to read the wave file's sample frequency.");
         GP_ERROR("Failed to read the wave file's sample frequency.");
         return false;
         return false;
     }
     }
 
 
-    frequency  = stream[3]<<24;
-    frequency |= stream[2]<<16;
-    frequency |= stream[1]<<8;
-    frequency |= stream[0];
+    frequency  = data[3]<<24;
+    frequency |= data[2]<<16;
+    frequency |= data[1]<<8;
+    frequency |= data[0];
     
     
     // The next 6 bytes hold the block size and bytes-per-second. 
     // The next 6 bytes hold the block size and bytes-per-second. 
     // We don't need that info, so just read and ignore it. 
     // We don't need that info, so just read and ignore it. 
     // We could use this later if we need to know the duration.
     // We could use this later if we need to know the duration.
-    if (fread(stream, 1, 6, file) != 6)
+    if (stream->read(data, 1, 6) != 6)
     {
     {
         GP_ERROR("Failed to read past the wave file's block size and bytes-per-second.");
         GP_ERROR("Failed to read past the wave file's block size and bytes-per-second.");
         return false;
         return false;
@@ -180,13 +204,13 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     
     
     // Get the bit depth (16-bit little-endian).
     // Get the bit depth (16-bit little-endian).
     int bits;
     int bits;
-    if (fread(stream, 1, 2, file) != 2)
+    if (stream->read(data, 1, 2) != 2)
     {
     {
         GP_ERROR("Failed to read the wave file's bit depth.");
         GP_ERROR("Failed to read the wave file's bit depth.");
         return false;
         return false;
     }
     }
-    bits  = stream[1]<<8;
-    bits |= stream[0];
+    bits  = data[1]<<8;
+    bits |= data[0];
     
     
     // Now convert the given channel count and bit depth into an OpenAL format. 
     // Now convert the given channel count and bit depth into an OpenAL format. 
     ALuint format = 0;
     ALuint format = 0;
@@ -216,7 +240,7 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         unsigned int length = section_size - 16;
         unsigned int length = section_size - 16;
 
 
         // Extension size is 2 bytes.
         // Extension size is 2 bytes.
-        if (fread(stream, 1, length, file) != length)
+        if (stream->read(data, 1, length) != length)
         {
         {
             GP_ERROR("Failed to read extension size from wave file.");
             GP_ERROR("Failed to read extension size from wave file.");
             return false;
             return false;
@@ -227,32 +251,32 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
     while (true)
     while (true)
     {
     {
         // Check if we are at the end of the file without reading the data.
         // Check if we are at the end of the file without reading the data.
-        if (feof(file))
+        if (stream->eof())
         {
         {
             GP_ERROR("Failed to load wave file; file appears to have no data.");
             GP_ERROR("Failed to load wave file; file appears to have no data.");
             return false;
             return false;
         }
         }
 
 
         // Read in the type of the next section of the file.
         // Read in the type of the next section of the file.
-        if (fread(stream, 1, 4, file) != 4)
+        if (stream->read(data, 1, 4) != 4)
         {
         {
             GP_ERROR("Failed to read next section type from wave file.");
             GP_ERROR("Failed to read next section type from wave file.");
             return false;
             return false;
         }
         }
 
 
         // Data chunk.
         // Data chunk.
-        if (memcmp(stream, "data", 4) == 0)
+        if (memcmp(data, "data", 4) == 0)
         {
         {
             // Read how much data is remaining and buffer it up.
             // Read how much data is remaining and buffer it up.
             unsigned int dataSize;
             unsigned int dataSize;
-            if (fread(&dataSize, sizeof(int), 1, file) != 1)
+            if (stream->read(&dataSize, sizeof(int), 1) != 1)
             {
             {
                 GP_ERROR("Failed to read size of data section from wave file.");
                 GP_ERROR("Failed to read size of data section from wave file.");
                 return false;
                 return false;
             }
             }
 
 
             char* data = new char[dataSize];
             char* data = new char[dataSize];
-            if (fread(data, sizeof(char), dataSize, file) != dataSize)
+            if (stream->read(data, sizeof(char), dataSize) != dataSize)
             {
             {
                 GP_ERROR("Failed to load wave file; file is missing data.");
                 GP_ERROR("Failed to load wave file; file is missing data.");
                 SAFE_DELETE_ARRAY(data);
                 SAFE_DELETE_ARRAY(data);
@@ -281,22 +305,22 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         {
         {
             // Store the name of the chunk so we can report errors informatively.
             // Store the name of the chunk so we can report errors informatively.
             char chunk[5] = { 0 };
             char chunk[5] = { 0 };
-            memcpy(chunk, stream, 4);
+            memcpy(chunk, data, 4);
 
 
             // Read the chunk size.
             // Read the chunk size.
-            if (fread(stream, 1, 4, file) != 4)
+            if (stream->read(data, 1, 4) != 4)
             {
             {
                 GP_ERROR("Failed to read size of '%s' chunk from wave file.", chunk);
                 GP_ERROR("Failed to read size of '%s' chunk from wave file.", chunk);
                 return false;
                 return false;
             }
             }
 
 
-            section_size  = stream[3]<<24;
-            section_size |= stream[2]<<16;
-            section_size |= stream[1]<<8;
-            section_size |= stream[0];
+            section_size  = data[3]<<24;
+            section_size |= data[2]<<16;
+            section_size |= data[1]<<8;
+            section_size |= data[0];
 
 
             // Seek past the chunk.
             // Seek past the chunk.
-            if (fseek(file, section_size, SEEK_CUR) != 0)
+            if (stream->seek(section_size, SEEK_CUR) == false)
             {
             {
                 GP_ERROR("Failed to seek past '%s' chunk in wave file.", chunk);
                 GP_ERROR("Failed to seek past '%s' chunk in wave file.", chunk);
                 return false;
                 return false;
@@ -304,10 +328,10 @@ bool AudioBuffer::loadWav(FILE* file, ALuint buffer)
         }
         }
     }
     }
 }
 }
-    
-bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
+
+bool AudioBuffer::loadOgg(Stream* stream, ALuint buffer)
 {
 {
-    GP_ASSERT(file);
+    GP_ASSERT(stream);
 
 
     OggVorbis_File ogg_file;
     OggVorbis_File ogg_file;
     vorbis_info* info;
     vorbis_info* info;
@@ -316,11 +340,16 @@ bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
     int section;
     int section;
     long size = 0;
     long size = 0;
 
 
-    rewind(file);
+    stream->rewind();
 
 
-    if ((result = ov_open(file, &ogg_file, NULL, 0)) < 0)
+    ov_callbacks callbacks;
+    callbacks.read_func = readStream;
+    callbacks.seek_func = seekStream;
+    callbacks.close_func = closeStream;
+    callbacks.tell_func = tellStream;
+
+    if ((result = ov_open_callbacks(stream, &ogg_file, NULL, 0, callbacks)) < 0)
     {
     {
-        fclose(file);
         GP_ERROR("Failed to open ogg file.");
         GP_ERROR("Failed to open ogg file.");
         return false;
         return false;
     }
     }
@@ -367,9 +396,6 @@ bool AudioBuffer::loadOgg(FILE*& file, ALuint buffer)
     SAFE_DELETE_ARRAY(data);
     SAFE_DELETE_ARRAY(data);
     ov_clear(&ogg_file);
     ov_clear(&ogg_file);
 
 
-    // ov_clear actually closes the file pointer as well.
-    file = 0;
-
     return true;
     return true;
 }
 }
 
 

+ 3 - 2
gameplay/src/AudioBuffer.h

@@ -2,6 +2,7 @@
 #define AUDIOBUFFER_H_
 #define AUDIOBUFFER_H_
 
 
 #include "Ref.h"
 #include "Ref.h"
+#include "Stream.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -43,9 +44,9 @@ private:
      */
      */
     static AudioBuffer* create(const char* path);
     static AudioBuffer* create(const char* path);
     
     
-    static bool loadWav(FILE* file, ALuint buffer);
+    static bool loadWav(Stream* stream, ALuint buffer);
     
     
-    static bool loadOgg(FILE*& file, ALuint buffer);
+    static bool loadOgg(Stream* stream, ALuint buffer);
 
 
     std::string _filePath;
     std::string _filePath;
     ALuint _alBuffer;
     ALuint _alBuffer;

+ 1 - 0
gameplay/src/Base.h

@@ -21,6 +21,7 @@
 #include <set>
 #include <set>
 #include <stack>
 #include <stack>
 #include <map>
 #include <map>
+#include <queue>
 #include <algorithm>
 #include <algorithm>
 #include <limits>
 #include <limits>
 #include <functional>
 #include <functional>

+ 84 - 102
gameplay/src/Bundle.cpp

@@ -32,7 +32,7 @@ namespace gameplay
 static std::vector<Bundle*> __bundleCache;
 static std::vector<Bundle*> __bundleCache;
 
 
 Bundle::Bundle(const char* path) :
 Bundle::Bundle(const char* path) :
-    _path(path), _referenceCount(0), _references(NULL), _file(NULL), _trackedNodes(NULL)
+    _path(path), _referenceCount(0), _references(NULL), _stream(NULL), _trackedNodes(NULL)
 {
 {
 }
 }
 
 
@@ -49,10 +49,9 @@ Bundle::~Bundle()
 
 
     SAFE_DELETE_ARRAY(_references);
     SAFE_DELETE_ARRAY(_references);
 
 
-    if (_file)
+    if (_stream)
     {
     {
-        fclose(_file);
-        _file = NULL;
+        SAFE_DELETE(_stream);
     }
     }
 }
 }
 
 
@@ -61,7 +60,7 @@ bool Bundle::readArray(unsigned int* length, T** ptr)
 {
 {
     GP_ASSERT(length);
     GP_ASSERT(length);
     GP_ASSERT(ptr);
     GP_ASSERT(ptr);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     if (!read(length))
     if (!read(length))
     {
     {
@@ -71,7 +70,7 @@ bool Bundle::readArray(unsigned int* length, T** ptr)
     if (*length > 0)
     if (*length > 0)
     {
     {
         *ptr = new T[*length];
         *ptr = new T[*length];
-        if (fread(*ptr, sizeof(T), *length, _file) != *length)
+        if (_stream->read(*ptr, sizeof(T), *length) != *length)
         {
         {
             GP_ERROR("Failed to read an array of data from bundle (into an array).");
             GP_ERROR("Failed to read an array of data from bundle (into an array).");
             SAFE_DELETE_ARRAY(*ptr);
             SAFE_DELETE_ARRAY(*ptr);
@@ -85,7 +84,7 @@ template <class T>
 bool Bundle::readArray(unsigned int* length, std::vector<T>* values)
 bool Bundle::readArray(unsigned int* length, std::vector<T>* values)
 {
 {
     GP_ASSERT(length);
     GP_ASSERT(length);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     if (!read(length))
     if (!read(length))
     {
     {
@@ -95,7 +94,7 @@ bool Bundle::readArray(unsigned int* length, std::vector<T>* values)
     if (*length > 0 && values)
     if (*length > 0 && values)
     {
     {
         values->resize(*length);
         values->resize(*length);
-        if (fread(&(*values)[0], sizeof(T), *length, _file) != *length)
+        if (_stream->read(&(*values)[0], sizeof(T), *length) != *length)
         {
         {
             GP_ERROR("Failed to read an array of data from bundle (into a std::vector).");
             GP_ERROR("Failed to read an array of data from bundle (into a std::vector).");
             return false;
             return false;
@@ -108,7 +107,7 @@ template <class T>
 bool Bundle::readArray(unsigned int* length, std::vector<T>* values, unsigned int readSize)
 bool Bundle::readArray(unsigned int* length, std::vector<T>* values, unsigned int readSize)
 {
 {
     GP_ASSERT(length);
     GP_ASSERT(length);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
     GP_ASSERT(sizeof(T) >= readSize);
     GP_ASSERT(sizeof(T) >= readSize);
 
 
     if (!read(length))
     if (!read(length))
@@ -119,7 +118,7 @@ bool Bundle::readArray(unsigned int* length, std::vector<T>* values, unsigned in
     if (*length > 0 && values)
     if (*length > 0 && values)
     {
     {
         values->resize(*length);
         values->resize(*length);
-        if (fread(&(*values)[0], readSize, *length, _file) != *length)
+        if (_stream->read(&(*values)[0], readSize, *length) != *length)
         {
         {
             GP_ERROR("Failed to read an array of data from bundle (into a std::vector with a specified single element read size).");
             GP_ERROR("Failed to read an array of data from bundle (into a std::vector with a specified single element read size).");
             return false;
             return false;
@@ -128,12 +127,12 @@ bool Bundle::readArray(unsigned int* length, std::vector<T>* values, unsigned in
     return true;
     return true;
 }
 }
 
 
-static std::string readString(FILE* fp)
+static std::string readString(Stream* stream)
 {
 {
-    GP_ASSERT(fp);
+    GP_ASSERT(stream);
 
 
     unsigned int length;
     unsigned int length;
-    if (fread(&length, 4, 1, fp) != 1)
+    if (stream->read(&length, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read the length of a string from a bundle.");
         GP_ERROR("Failed to read the length of a string from a bundle.");
         return std::string();
         return std::string();
@@ -146,7 +145,7 @@ static std::string readString(FILE* fp)
     if (length > 0)
     if (length > 0)
     {
     {
         str.resize(length);
         str.resize(length);
-        if (fread(&str[0], 1, length, fp) != length)
+        if (stream->read(&str[0], 1, length) != length)
         {
         {
             GP_ERROR("Failed to read string from bundle.");
             GP_ERROR("Failed to read string from bundle.");
             return std::string();
             return std::string();
@@ -173,8 +172,8 @@ Bundle* Bundle::create(const char* path)
     }
     }
 
 
     // Open the bundle.
     // Open the bundle.
-    FILE* fp = FileSystem::openFile(path, "rb");
-    if (!fp)
+    Stream* stream = FileSystem::open(path);
+    if (!stream)
     {
     {
         GP_ERROR("Failed to open file '%s'.", path);
         GP_ERROR("Failed to open file '%s'.", path);
         return NULL;
         return NULL;
@@ -182,46 +181,34 @@ Bundle* Bundle::create(const char* path)
 
 
     // Read the GPB header info.
     // Read the GPB header info.
     char sig[9];
     char sig[9];
-    if (fread(sig, 1, 9, fp) != 9 || memcmp(sig, "\xABGPB\xBB\r\n\x1A\n", 9) != 0)
+    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_ERROR("Invalid GPB header for bundle '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
     // Read version.
     // Read version.
     unsigned char ver[2];
     unsigned char ver[2];
-    if (fread(ver, 1, 2, fp) != 2)
+    if (stream->read(ver, 1, 2) != 2)
     {
     {
+        SAFE_DELETE(stream);
         GP_ERROR("Failed to read GPB version for bundle '%s'.", path);
         GP_ERROR("Failed to read GPB version for bundle '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
     if (ver[0] != BUNDLE_VERSION_MAJOR || ver[1] != BUNDLE_VERSION_MINOR)
     if (ver[0] != BUNDLE_VERSION_MAJOR || ver[1] != BUNDLE_VERSION_MINOR)
     {
     {
+        SAFE_DELETE(stream);
         GP_ERROR("Unsupported version (%d.%d) for bundle '%s' (expected %d.%d).", (int)ver[0], (int)ver[1], path, BUNDLE_VERSION_MAJOR, BUNDLE_VERSION_MINOR);
         GP_ERROR("Unsupported version (%d.%d) for bundle '%s' (expected %d.%d).", (int)ver[0], (int)ver[1], path, BUNDLE_VERSION_MAJOR, BUNDLE_VERSION_MINOR);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
     // Read ref table.
     // Read ref table.
     unsigned int refCount;
     unsigned int refCount;
-    if (fread(&refCount, 4, 1, fp) != 1)
+    if (stream->read(&refCount, 4, 1) != 1)
     {
     {
+        SAFE_DELETE(stream);
         GP_ERROR("Failed to read ref table for bundle '%s'.", path);
         GP_ERROR("Failed to read ref table for bundle '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -229,15 +216,12 @@ Bundle* Bundle::create(const char* path)
     Reference* refs = new Reference[refCount];
     Reference* refs = new Reference[refCount];
     for (unsigned int i = 0; i < refCount; ++i)
     for (unsigned int i = 0; i < refCount; ++i)
     {
     {
-        if ((refs[i].id = readString(fp)).empty() ||
-            fread(&refs[i].type, 4, 1, fp) != 1 ||
-            fread(&refs[i].offset, 4, 1, fp) != 1)
+        if ((refs[i].id = readString(stream)).empty() ||
+            stream->read(&refs[i].type, 4, 1) != 1 ||
+            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_ERROR("Failed to read ref number %d for bundle '%s'.", i, path);
-            if (fclose(fp) != 0)
-            {
-                GP_ERROR("Failed to close file '%s'.", path);
-            }
             SAFE_DELETE_ARRAY(refs);
             SAFE_DELETE_ARRAY(refs);
             return NULL;
             return NULL;
         }
         }
@@ -247,7 +231,7 @@ Bundle* Bundle::create(const char* path)
     Bundle* bundle = new Bundle(path);
     Bundle* bundle = new Bundle(path);
     bundle->_referenceCount = refCount;
     bundle->_referenceCount = refCount;
     bundle->_references = refs;
     bundle->_references = refs;
-    bundle->_file = fp;
+    bundle->_stream = stream;
 
 
     return bundle;
     return bundle;
 }
 }
@@ -281,8 +265,8 @@ void Bundle::clearLoadSession()
 
 
 const char* Bundle::getIdFromOffset() const
 const char* Bundle::getIdFromOffset() const
 {
 {
-    GP_ASSERT(_file);
-    return getIdFromOffset((unsigned int) ftell(_file));
+    GP_ASSERT(_stream);
+    return getIdFromOffset((unsigned int) _stream->position());
 }
 }
 
 
 const char* Bundle::getIdFromOffset(unsigned int offset) const
 const char* Bundle::getIdFromOffset(unsigned int offset) const
@@ -318,8 +302,8 @@ Bundle::Reference* Bundle::seekTo(const char* id, unsigned int type)
     }
     }
 
 
     // Seek to the offset of this object.
     // Seek to the offset of this object.
-    GP_ASSERT(_file);
-    if (fseek(_file, ref->offset, SEEK_SET) != 0)
+    GP_ASSERT(_stream);
+    if (_stream->seek(ref->offset, SEEK_SET) == false)
     {
     {
         GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", id, _path.c_str());
         GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", id, _path.c_str());
         return NULL;
         return NULL;
@@ -331,7 +315,7 @@ Bundle::Reference* Bundle::seekTo(const char* id, unsigned int type)
 Bundle::Reference* Bundle::seekToFirstType(unsigned int type)
 Bundle::Reference* Bundle::seekToFirstType(unsigned int type)
 {
 {
     GP_ASSERT(_references);
     GP_ASSERT(_references);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     for (unsigned int i = 0; i < _referenceCount; ++i)
     for (unsigned int i = 0; i < _referenceCount; ++i)
     {
     {
@@ -339,7 +323,7 @@ Bundle::Reference* Bundle::seekToFirstType(unsigned int type)
         if (ref->type == type)
         if (ref->type == type)
         {
         {
             // Found a match.
             // Found a match.
-            if (fseek(_file, ref->offset, SEEK_SET) != 0)
+            if (_stream->seek(ref->offset, SEEK_SET) == false)
             {
             {
                 GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 return NULL;
                 return NULL;
@@ -352,22 +336,22 @@ Bundle::Reference* Bundle::seekToFirstType(unsigned int type)
 
 
 bool Bundle::read(unsigned int* ptr)
 bool Bundle::read(unsigned int* ptr)
 {
 {
-    return fread(ptr, sizeof(unsigned int), 1, _file) == 1;
+    return _stream->read(ptr, sizeof(unsigned int), 1) == 1;
 }
 }
 
 
 bool Bundle::read(unsigned char* ptr)
 bool Bundle::read(unsigned char* ptr)
 {
 {
-    return fread(ptr, sizeof(unsigned char), 1, _file) == 1;
+    return _stream->read(ptr, sizeof(unsigned char), 1) == 1;
 }
 }
 
 
 bool Bundle::read(float* ptr)
 bool Bundle::read(float* ptr)
 {
 {
-    return fread(ptr, sizeof(float), 1, _file) == 1;
+    return _stream->read(ptr, sizeof(float), 1) == 1;
 }
 }
 
 
 bool Bundle::readMatrix(float* m)
 bool Bundle::readMatrix(float* m)
 {
 {
-    return fread(m, sizeof(float), 16, _file) == 16;
+    return _stream->read(m, sizeof(float), 16) == 16;
 }
 }
 
 
 Scene* Bundle::loadScene(const char* id)
 Scene* Bundle::loadScene(const char* id)
@@ -419,7 +403,7 @@ Scene* Bundle::loadScene(const char* id)
         }
         }
     }
     }
     // Read active camera.
     // Read active camera.
-    std::string xref = readString(_file);
+    std::string xref = readString(_stream);
     if (xref.length() > 1 && xref[0] == '#') // TODO: Handle full xrefs
     if (xref.length() > 1 && xref[0] == '#') // TODO: Handle full xrefs
     {
     {
         Node* node = scene->findNode(xref.c_str() + 1, true);
         Node* node = scene->findNode(xref.c_str() + 1, true);
@@ -453,14 +437,14 @@ Scene* Bundle::loadScene(const char* id)
 
 
     // Parse animations.
     // Parse animations.
     GP_ASSERT(_references);
     GP_ASSERT(_references);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
     for (unsigned int i = 0; i < _referenceCount; ++i)
     for (unsigned int i = 0; i < _referenceCount; ++i)
     {
     {
         Reference* ref = &_references[i];
         Reference* ref = &_references[i];
         if (ref->type == BUNDLE_TYPE_ANIMATIONS)
         if (ref->type == BUNDLE_TYPE_ANIMATIONS)
         {
         {
             // Found a match.
             // Found a match.
-            if (fseek(_file, ref->offset, SEEK_SET) != 0)
+            if (_stream->seek(ref->offset, SEEK_SET) == false)
             {
             {
                 GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 return NULL;
                 return NULL;
@@ -483,7 +467,7 @@ Node* Bundle::loadNode(const char* id, Scene* sceneContext)
 {
 {
     GP_ASSERT(id);
     GP_ASSERT(id);
     GP_ASSERT(_references);
     GP_ASSERT(_references);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     clearLoadSession();
     clearLoadSession();
 
 
@@ -499,7 +483,7 @@ Node* Bundle::loadNode(const char* id, Scene* sceneContext)
         Reference* ref = &_references[i];
         Reference* ref = &_references[i];
         if (ref->type == BUNDLE_TYPE_ANIMATIONS)
         if (ref->type == BUNDLE_TYPE_ANIMATIONS)
         {
         {
-            if (fseek(_file, ref->offset, SEEK_SET) != 0)
+            if (_stream->seek(ref->offset, SEEK_SET) == false)
             {
             {
                 GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 GP_ERROR("Failed to seek to object '%s' in bundle '%s'.", ref->id.c_str(), _path.c_str());
                 SAFE_DELETE(_trackedNodes);
                 SAFE_DELETE(_trackedNodes);
@@ -517,7 +501,7 @@ Node* Bundle::loadNode(const char* id, Scene* sceneContext)
 
 
             for (unsigned int j = 0; j < animationCount; j++)
             for (unsigned int j = 0; j < animationCount; j++)
             {
             {
-                const std::string id = readString(_file);
+                const std::string id = readString(_stream);
 
 
                 // Read the number of animation channels in this animation.
                 // Read the number of animation channels in this animation.
                 unsigned int animationChannelCount;
                 unsigned int animationChannelCount;
@@ -532,7 +516,7 @@ Node* Bundle::loadNode(const char* id, Scene* sceneContext)
                 for (unsigned int k = 0; k < animationChannelCount; k++)
                 for (unsigned int k = 0; k < animationChannelCount; k++)
                 {
                 {
                     // Read target id.
                     // Read target id.
-                    std::string targetId = readString(_file);
+                    std::string targetId = readString(_stream);
                     if (targetId.empty())
                     if (targetId.empty())
                     {
                     {
                         GP_ERROR("Failed to read target id for animation '%s'.", id.c_str());
                         GP_ERROR("Failed to read target id for animation '%s'.", id.c_str());
@@ -627,7 +611,7 @@ bool Bundle::skipNode()
 {
 {
     const char* id = getIdFromOffset();
     const char* id = getIdFromOffset();
     GP_ASSERT(id);
     GP_ASSERT(id);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     // Skip the node's type.
     // Skip the node's type.
     unsigned int nodeType;
     unsigned int nodeType;
@@ -638,12 +622,12 @@ bool Bundle::skipNode()
     }
     }
 
 
     // Skip over the node's transform and parent ID.
     // Skip over the node's transform and parent ID.
-    if (fseek(_file, sizeof(float) * 16, SEEK_CUR) != 0)
+    if (_stream->seek(sizeof(float) * 16, SEEK_CUR) == false)
     {
     {
         GP_ERROR("Failed to skip over node transform for node '%s'.", id);
         GP_ERROR("Failed to skip over node transform for node '%s'.", id);
         return false;
         return false;
     }
     }
-    readString(_file);
+    readString(_stream);
 
 
     // Skip over the node's children.
     // Skip over the node's children.
     unsigned int childrenCount;
     unsigned int childrenCount;
@@ -673,7 +657,7 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
 {
 {
     const char* id = getIdFromOffset();
     const char* id = getIdFromOffset();
     GP_ASSERT(id);
     GP_ASSERT(id);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     // If we are tracking nodes and it's not in the set yet, add it.
     // If we are tracking nodes and it's not in the set yet, add it.
     if (_trackedNodes)
     if (_trackedNodes)
@@ -725,7 +709,7 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
 
 
     // Read transform.
     // Read transform.
     float transform[16];
     float transform[16];
-    if (fread(transform, sizeof(float), 16, _file) != 16)
+    if (_stream->read(transform, sizeof(float), 16) != 16)
     {
     {
         GP_ERROR("Failed to read transform for node '%s'.", id);
         GP_ERROR("Failed to read transform for node '%s'.", id);
         SAFE_RELEASE(node);
         SAFE_RELEASE(node);
@@ -734,7 +718,7 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
     setTransform(transform, node);
     setTransform(transform, node);
 
 
     // Skip the parent ID.
     // Skip the parent ID.
-    readString(_file);
+    readString(_stream);
 
 
     // Read children.
     // Read children.
     unsigned int childrenCount;
     unsigned int childrenCount;
@@ -952,12 +936,10 @@ Light* Bundle::readLight()
 
 
 Model* Bundle::readModel(const char* nodeId)
 Model* Bundle::readModel(const char* nodeId)
 {
 {
-    // Read mesh.
-    Mesh* mesh = NULL;
-    std::string xref = readString(_file);
+    std::string xref = readString(_stream);
     if (xref.length() > 1 && xref[0] == '#') // TODO: Handle full xrefs
     if (xref.length() > 1 && xref[0] == '#') // TODO: Handle full xrefs
     {
     {
-        mesh = loadMesh(xref.c_str() + 1, nodeId);
+        Mesh* mesh = loadMesh(xref.c_str() + 1, nodeId);
         if (mesh)
         if (mesh)
         {
         {
             Model* model = Model::create(mesh);
             Model* model = Model::create(mesh);
@@ -1035,7 +1017,7 @@ MeshSkin* Bundle::readMeshSkin()
     // Read joint xref strings for all joints in the list.
     // Read joint xref strings for all joints in the list.
     for (unsigned int i = 0; i < jointCount; i++)
     for (unsigned int i = 0; i < jointCount; i++)
     {
     {
-        skinData->joints.push_back(readString(_file));
+        skinData->joints.push_back(readString(_stream));
     }
     }
 
 
     // Read bind poses.
     // Read bind poses.
@@ -1072,7 +1054,7 @@ MeshSkin* Bundle::readMeshSkin()
 
 
 void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
 void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
 {
 {
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     for (size_t i = 0, skinCount = _meshSkins.size(); i < skinCount; ++i)
     for (size_t i = 0, skinCount = _meshSkins.size(); i < skinCount; ++i)
     {
     {
@@ -1144,12 +1126,12 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
                         seekTo(nodeId.c_str(), ref->type);
                         seekTo(nodeId.c_str(), ref->type);
 
 
                         // Skip over the node type (1 unsigned int) and transform (16 floats) and read the parent id.
                         // Skip over the node type (1 unsigned int) and transform (16 floats) and read the parent id.
-                        if (fseek(_file, sizeof(unsigned int) + sizeof(float)*16, SEEK_CUR) != 0)
+                        if (_stream->seek(sizeof(unsigned int) + sizeof(float)*16, SEEK_CUR) == false)
                         {
                         {
                             GP_ERROR("Failed to skip over node type and transform for node '%s' in bundle '%s'.", nodeId.c_str(), _path.c_str());
                             GP_ERROR("Failed to skip over node type and transform for node '%s' in bundle '%s'.", nodeId.c_str(), _path.c_str());
                             return;
                             return;
                         }
                         }
-                        std::string parentID = readString(_file);
+                        std::string parentID = readString(_stream);
 
 
                         if (!parentID.empty())
                         if (!parentID.empty())
                             nodeId = parentID;
                             nodeId = parentID;
@@ -1185,7 +1167,7 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
 
 
 void Bundle::readAnimation(Scene* scene)
 void Bundle::readAnimation(Scene* scene)
 {
 {
-    const std::string animationId = readString(_file);
+    const std::string animationId = readString(_stream);
 
 
     // Read the number of animation channels in this animation.
     // Read the number of animation channels in this animation.
     unsigned int animationChannelCount;
     unsigned int animationChannelCount;
@@ -1223,7 +1205,7 @@ Animation* Bundle::readAnimationChannel(Scene* scene, Animation* animation, cons
     GP_ASSERT(animationId);
     GP_ASSERT(animationId);
 
 
     // Read target id.
     // Read target id.
-    std::string targetId = readString(_file);
+    std::string targetId = readString(_stream);
     if (targetId.empty())
     if (targetId.empty())
     {
     {
         GP_ERROR("Failed to read target id for animation '%s'.", animationId);
         GP_ERROR("Failed to read target id for animation '%s'.", animationId);
@@ -1331,11 +1313,11 @@ Mesh* Bundle::loadMesh(const char* id)
 
 
 Mesh* Bundle::loadMesh(const char* id, const char* nodeId)
 Mesh* Bundle::loadMesh(const char* id, const char* nodeId)
 {
 {
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
     GP_ASSERT(id);
     GP_ASSERT(id);
 
 
     // Save the file position.
     // Save the file position.
-    long position = ftell(_file);
+    long position = _stream->position();
     if (position == -1L)
     if (position == -1L)
     {
     {
         GP_ERROR("Failed to save the current file position before loading mesh '%s'.", id);
         GP_ERROR("Failed to save the current file position before loading mesh '%s'.", id);
@@ -1395,7 +1377,7 @@ Mesh* Bundle::loadMesh(const char* id, const char* nodeId)
     SAFE_DELETE(meshData);
     SAFE_DELETE(meshData);
 
 
     // Restore file pointer.
     // Restore file pointer.
-    if (fseek(_file, position, SEEK_SET) != 0)
+    if (_stream->seek(position, SEEK_SET) == false)
     {
     {
         GP_ERROR("Failed to restore file pointer after loading mesh '%s'.", id);
         GP_ERROR("Failed to restore file pointer after loading mesh '%s'.", id);
         return NULL;
         return NULL;
@@ -1408,7 +1390,7 @@ Bundle::MeshData* Bundle::readMeshData()
 {
 {
     // Read vertex format/elements.
     // Read vertex format/elements.
     unsigned int vertexElementCount;
     unsigned int vertexElementCount;
-    if (fread(&vertexElementCount, 4, 1, _file) != 1)
+    if (_stream->read(&vertexElementCount, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to load vertex element count.");
         GP_ERROR("Failed to load vertex element count.");
         return NULL;
         return NULL;
@@ -1423,13 +1405,13 @@ Bundle::MeshData* Bundle::readMeshData()
     for (unsigned int i = 0; i < vertexElementCount; ++i)
     for (unsigned int i = 0; i < vertexElementCount; ++i)
     {
     {
         unsigned int vUsage, vSize;
         unsigned int vUsage, vSize;
-        if (fread(&vUsage, 4, 1, _file) != 1)
+        if (_stream->read(&vUsage, 4, 1) != 1)
         {
         {
             GP_ERROR("Failed to load vertex usage.");
             GP_ERROR("Failed to load vertex usage.");
             SAFE_DELETE_ARRAY(vertexElements);
             SAFE_DELETE_ARRAY(vertexElements);
             return NULL;
             return NULL;
         }
         }
-        if (fread(&vSize, 4, 1, _file) != 1)
+        if (_stream->read(&vSize, 4, 1) != 1)
         {
         {
             GP_ERROR("Failed to load vertex size.");
             GP_ERROR("Failed to load vertex size.");
             SAFE_DELETE_ARRAY(vertexElements);
             SAFE_DELETE_ARRAY(vertexElements);
@@ -1445,7 +1427,7 @@ Bundle::MeshData* Bundle::readMeshData()
 
 
     // Read vertex data.
     // Read vertex data.
     unsigned int vertexByteCount;
     unsigned int vertexByteCount;
-    if (fread(&vertexByteCount, 4, 1, _file) != 1)
+    if (_stream->read(&vertexByteCount, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to load vertex byte count.");
         GP_ERROR("Failed to load vertex byte count.");
         SAFE_DELETE(meshData);
         SAFE_DELETE(meshData);
@@ -1461,7 +1443,7 @@ Bundle::MeshData* Bundle::readMeshData()
     GP_ASSERT(meshData->vertexFormat.getVertexSize());
     GP_ASSERT(meshData->vertexFormat.getVertexSize());
     meshData->vertexCount = vertexByteCount / meshData->vertexFormat.getVertexSize();
     meshData->vertexCount = vertexByteCount / meshData->vertexFormat.getVertexSize();
     meshData->vertexData = new unsigned char[vertexByteCount];
     meshData->vertexData = new unsigned char[vertexByteCount];
-    if (fread(meshData->vertexData, 1, vertexByteCount, _file) != vertexByteCount)
+    if (_stream->read(meshData->vertexData, 1, vertexByteCount) != vertexByteCount)
     {
     {
         GP_ERROR("Failed to load vertex data.");
         GP_ERROR("Failed to load vertex data.");
         SAFE_DELETE(meshData);
         SAFE_DELETE(meshData);
@@ -1469,13 +1451,13 @@ Bundle::MeshData* Bundle::readMeshData()
     }
     }
 
 
     // Read mesh bounds (bounding box and bounding sphere).
     // Read mesh bounds (bounding box and bounding sphere).
-    if (fread(&meshData->boundingBox.min.x, 4, 3, _file) != 3 || fread(&meshData->boundingBox.max.x, 4, 3, _file) != 3)
+    if (_stream->read(&meshData->boundingBox.min.x, 4, 3) != 3 || _stream->read(&meshData->boundingBox.max.x, 4, 3) != 3)
     {
     {
         GP_ERROR("Failed to load mesh bounding box.");
         GP_ERROR("Failed to load mesh bounding box.");
         SAFE_DELETE(meshData);
         SAFE_DELETE(meshData);
         return NULL;
         return NULL;
     }
     }
-    if (fread(&meshData->boundingSphere.center.x, 4, 3, _file) != 3 || fread(&meshData->boundingSphere.radius, 4, 1, _file) != 1)
+    if (_stream->read(&meshData->boundingSphere.center.x, 4, 3) != 3 || _stream->read(&meshData->boundingSphere.radius, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to load mesh bounding sphere.");
         GP_ERROR("Failed to load mesh bounding sphere.");
         SAFE_DELETE(meshData);
         SAFE_DELETE(meshData);
@@ -1484,7 +1466,7 @@ Bundle::MeshData* Bundle::readMeshData()
 
 
     // Read mesh parts.
     // Read mesh parts.
     unsigned int meshPartCount;
     unsigned int meshPartCount;
-    if (fread(&meshPartCount, 4, 1, _file) != 1)
+    if (_stream->read(&meshPartCount, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to load mesh part count.");
         GP_ERROR("Failed to load mesh part count.");
         SAFE_DELETE(meshData);
         SAFE_DELETE(meshData);
@@ -1494,19 +1476,19 @@ Bundle::MeshData* Bundle::readMeshData()
     {
     {
         // Read primitive type, index format and index count.
         // Read primitive type, index format and index count.
         unsigned int pType, iFormat, iByteCount;
         unsigned int pType, iFormat, iByteCount;
-        if (fread(&pType, 4, 1, _file) != 1)
+        if (_stream->read(&pType, 4, 1) != 1)
         {
         {
             GP_ERROR("Failed to load primitive type for mesh part with index %d.", i);
             GP_ERROR("Failed to load primitive type for mesh part with index %d.", i);
             SAFE_DELETE(meshData);
             SAFE_DELETE(meshData);
             return NULL;
             return NULL;
         }
         }
-        if (fread(&iFormat, 4, 1, _file) != 1)
+        if (_stream->read(&iFormat, 4, 1) != 1)
         {
         {
             GP_ERROR("Failed to load index format for mesh part with index %d.", i);
             GP_ERROR("Failed to load index format for mesh part with index %d.", i);
             SAFE_DELETE(meshData);
             SAFE_DELETE(meshData);
             return NULL;
             return NULL;
         }
         }
-        if (fread(&iByteCount, 4, 1, _file) != 1)
+        if (_stream->read(&iByteCount, 4, 1) != 1)
         {
         {
             GP_ERROR("Failed to load index byte count for mesh part with index %d.", i);
             GP_ERROR("Failed to load index byte count for mesh part with index %d.", i);
             SAFE_DELETE(meshData);
             SAFE_DELETE(meshData);
@@ -1540,7 +1522,7 @@ Bundle::MeshData* Bundle::readMeshData()
         partData->indexCount = iByteCount / indexSize;
         partData->indexCount = iByteCount / indexSize;
 
 
         partData->indexData = new unsigned char[iByteCount];
         partData->indexData = new unsigned char[iByteCount];
-        if (fread(partData->indexData, 1, iByteCount, _file) != iByteCount)
+        if (_stream->read(partData->indexData, 1, iByteCount) != iByteCount)
         {
         {
             GP_ERROR("Failed to read index data for mesh part with index %d.", i);
             GP_ERROR("Failed to read index data for mesh part with index %d.", i);
             SAFE_DELETE(meshData);
             SAFE_DELETE(meshData);
@@ -1601,7 +1583,7 @@ Bundle::MeshData* Bundle::readMeshData(const char* url)
 Font* Bundle::loadFont(const char* id)
 Font* Bundle::loadFont(const char* id)
 {
 {
     GP_ASSERT(id);
     GP_ASSERT(id);
-    GP_ASSERT(_file);
+    GP_ASSERT(_stream);
 
 
     // Seek to the specified font.
     // Seek to the specified font.
     Reference* ref = seekTo(id, BUNDLE_TYPE_FONT);
     Reference* ref = seekTo(id, BUNDLE_TYPE_FONT);
@@ -1612,7 +1594,7 @@ Font* Bundle::loadFont(const char* id)
     }
     }
 
 
     // Read font family.
     // Read font family.
-    std::string family = readString(_file);
+    std::string family = readString(_stream);
     if (family.empty())
     if (family.empty())
     {
     {
         GP_ERROR("Failed to read font family for font '%s'.", id);
         GP_ERROR("Failed to read font family for font '%s'.", id);
@@ -1621,23 +1603,23 @@ Font* Bundle::loadFont(const char* id)
 
 
     // Read font style and size.
     // Read font style and size.
     unsigned int style, size;
     unsigned int style, size;
-    if (fread(&style, 4, 1, _file) != 1)
+    if (_stream->read(&style, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read style for font '%s'.", id);
         GP_ERROR("Failed to read style for font '%s'.", id);
         return NULL;
         return NULL;
     }
     }
-    if (fread(&size, 4, 1, _file) != 1)
+    if (_stream->read(&size, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read size for font '%s'.", id);
         GP_ERROR("Failed to read size for font '%s'.", id);
         return NULL;
         return NULL;
     }
     }
 
 
     // Read character set.
     // Read character set.
-    std::string charset = readString(_file);
+    std::string charset = readString(_stream);
 
 
     // Read font glyphs.
     // Read font glyphs.
     unsigned int glyphCount;
     unsigned int glyphCount;
-    if (fread(&glyphCount, 4, 1, _file) != 1)
+    if (_stream->read(&glyphCount, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read glyph count for font '%s'.", id);
         GP_ERROR("Failed to read glyph count for font '%s'.", id);
         return NULL;
         return NULL;
@@ -1649,7 +1631,7 @@ Font* Bundle::loadFont(const char* id)
     }
     }
 
 
     Font::Glyph* glyphs = new Font::Glyph[glyphCount];
     Font::Glyph* glyphs = new Font::Glyph[glyphCount];
-    if (fread(glyphs, sizeof(Font::Glyph), glyphCount, _file) != glyphCount)
+    if (_stream->read(glyphs, sizeof(Font::Glyph), glyphCount) != glyphCount)
     {
     {
         GP_ERROR("Failed to read glyphs for font '%s'.", id);
         GP_ERROR("Failed to read glyphs for font '%s'.", id);
         SAFE_DELETE_ARRAY(glyphs);
         SAFE_DELETE_ARRAY(glyphs);
@@ -1658,19 +1640,19 @@ Font* Bundle::loadFont(const char* id)
 
 
     // Read texture attributes.
     // Read texture attributes.
     unsigned int width, height, textureByteCount;
     unsigned int width, height, textureByteCount;
-    if (fread(&width, 4, 1, _file) != 1)
+    if (_stream->read(&width, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read texture width for font '%s'.", id);
         GP_ERROR("Failed to read texture width for font '%s'.", id);
         SAFE_DELETE_ARRAY(glyphs);
         SAFE_DELETE_ARRAY(glyphs);
         return NULL;
         return NULL;
     }
     }
-    if (fread(&height, 4, 1, _file) != 1)
+    if (_stream->read(&height, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read texture height for font '%s'.", id);
         GP_ERROR("Failed to read texture height for font '%s'.", id);
         SAFE_DELETE_ARRAY(glyphs);
         SAFE_DELETE_ARRAY(glyphs);
         return NULL;
         return NULL;
     }
     }
-    if (fread(&textureByteCount, 4, 1, _file) != 1)
+    if (_stream->read(&textureByteCount, 4, 1) != 1)
     {
     {
         GP_ERROR("Failed to read texture byte count for font '%s'.", id);
         GP_ERROR("Failed to read texture byte count for font '%s'.", id);
         SAFE_DELETE_ARRAY(glyphs);
         SAFE_DELETE_ARRAY(glyphs);
@@ -1685,7 +1667,7 @@ Font* Bundle::loadFont(const char* id)
 
 
     // Read texture data.
     // Read texture data.
     unsigned char* textureData = new unsigned char[textureByteCount];
     unsigned char* textureData = new unsigned char[textureByteCount];
-    if (fread(textureData, 1, textureByteCount, _file) != textureByteCount)
+    if (_stream->read(textureData, 1, textureByteCount) != textureByteCount)
     {
     {
         GP_ERROR("Failed to read texture data for font '%s'.", id);
         GP_ERROR("Failed to read texture data for font '%s'.", id);
         SAFE_DELETE_ARRAY(glyphs);
         SAFE_DELETE_ARRAY(glyphs);

+ 1 - 1
gameplay/src/Bundle.h

@@ -429,7 +429,7 @@ private:
     std::string _path;
     std::string _path;
     unsigned int _referenceCount;
     unsigned int _referenceCount;
     Reference* _references;
     Reference* _references;
-    FILE* _file;
+    Stream* _stream;
 
 
     std::vector<MeshSkinData*> _meshSkins;
     std::vector<MeshSkinData*> _meshSkins;
     std::map<std::string, Node*>* _trackedNodes;
     std::map<std::string, Node*>* _trackedNodes;

+ 10 - 8
gameplay/src/Container.cpp

@@ -278,6 +278,7 @@ void Container::removeControl(const char* id)
         Control* c = *it;
         Control* c = *it;
         if (strcmp(id, c->getId()) == 0)
         if (strcmp(id, c->getId()) == 0)
         {
         {
+            c->_parent = NULL;
             SAFE_RELEASE(c);
             SAFE_RELEASE(c);
             _controls.erase(it);
             _controls.erase(it);
             return;
             return;
@@ -293,6 +294,7 @@ void Container::removeControl(Control* control)
     {
     {
         if (*it == control)
         if (*it == control)
         {
         {
+            control->_parent = NULL;
             SAFE_RELEASE(control);
             SAFE_RELEASE(control);
             _controls.erase(it);
             _controls.erase(it);
             return;
             return;
@@ -1107,11 +1109,11 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
         }
         }
         break;
         break;
     case Touch::TOUCH_RELEASE:
     case Touch::TOUCH_RELEASE:
-		if (eventConsumed)
-		{
-			if (_contactIndices > 0)
-				_contactIndices--;
-		}
+        if (eventConsumed)
+        {
+            if (_contactIndices > 0)
+                _contactIndices--;
+        }
         break;
         break;
     }
     }
 
 
@@ -1126,10 +1128,10 @@ bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
 
 
     release();
     release();
     if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
     if (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
-		y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
-    	return (_consumeInputEvents | eventConsumed);
+        y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height)
+        return (_consumeInputEvents | eventConsumed);
     else
     else
-    	return eventConsumed;
+        return eventConsumed;
 }
 }
 
 
 Container::Scroll Container::getScroll(const char* scroll)
 Container::Scroll Container::getScroll(const char* scroll)

+ 8 - 8
gameplay/src/Container.h

@@ -319,7 +319,7 @@ protected:
     void addControls(Theme* theme, Properties* properties);
     void addControls(Theme* theme, Properties* properties);
 
 
     /**
     /**
-     * Draws a sprite batch for the specified clipping rect .
+     * Draws a sprite batch for the specified clipping rect.
      *
      *
      * @param spriteBatch The sprite batch to use.
      * @param spriteBatch The sprite batch to use.
      * @param clip The clipping rectangle.
      * @param clip The clipping rectangle.
@@ -444,13 +444,13 @@ protected:
      */
      */
     bool _scrolling;
     bool _scrolling;
     /** 
     /** 
-	 * First scrolling touch x position
-	 */
-	int _scrollingVeryFirstX;
-	/**
-	 * First scrolling touch y position
-	 */
-	int _scrollingVeryFirstY;
+     * First scrolling touch x position
+     */
+    int _scrollingVeryFirstX;
+    /**
+     * First scrolling touch y position
+     */
+    int _scrollingVeryFirstY;
     /**
     /**
      * First scrolling touch x position since last change in direction.
      * First scrolling touch x position since last change in direction.
      */ 
      */ 

+ 67 - 13
gameplay/src/Control.cpp

@@ -7,7 +7,7 @@ namespace gameplay
 
 
 Control::Control()
 Control::Control()
     : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
     : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
-    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT), _autoWidth(false), _autoHeight(false), _listeners(NULL),
+    _clearBounds(Rectangle::empty()), _dirty(true), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT), _isAlignmentSet(false), _autoWidth(false), _autoHeight(false), _listeners(NULL), _visible(true),
     _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(0), _parent(NULL), _styleOverridden(false), _skin(NULL)
     _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(0), _parent(NULL), _styleOverridden(false), _skin(NULL)
 {
 {
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
@@ -17,7 +17,7 @@ Control::~Control()
 {
 {
     if (_listeners)
     if (_listeners)
     {
     {
-        for (std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
+        for (std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); ++itr)
         {
         {
             std::list<Listener*>* list = itr->second;
             std::list<Listener*>* list = itr->second;
             SAFE_DELETE(list);
             SAFE_DELETE(list);
@@ -208,6 +208,8 @@ float Control::getHeight() const
 void Control::setAlignment(Alignment alignment)
 void Control::setAlignment(Alignment alignment)
 {
 {
     _alignment = alignment;
     _alignment = alignment;
+    _isAlignmentSet = true;
+    _dirty = true;
 }
 }
 
 
 Control::Alignment Control::getAlignment() const
 Control::Alignment Control::getAlignment() const
@@ -243,6 +245,27 @@ bool Control::getAutoHeight() const
     return _autoHeight;
     return _autoHeight;
 }
 }
 
 
+void Control::setVisible(bool visible)
+{
+    if (visible && !_visible)
+    {
+        setEnabled(true);
+        _visible = true;
+        _dirty = true;
+    }
+    else if (!visible && _visible)
+    {
+        setEnabled(false);
+        _visible = false;
+        _dirty = true;
+    }
+}
+
+bool Control::isVisible() const
+{
+    return _visible;
+}
+
 void Control::setOpacity(float opacity, unsigned char states)
 void Control::setOpacity(float opacity, unsigned char states)
 {
 {
     overrideStyle();
     overrideStyle();
@@ -596,19 +619,21 @@ Control::State Control::getState() const
     return _state;
     return _state;
 }
 }
 
 
-void Control::disable()
+void Control::setEnabled(bool enabled)
 {
 {
-    _state = DISABLED;
-    _dirty = true;
-}
-
-void Control::enable()
-{
-    _state = NORMAL;
-    _dirty = true;
+	if (enabled && _state == Control::DISABLED)
+	{
+		_state = Control::NORMAL;
+		_dirty = true;
+	}
+	else if (!enabled && _state != Control::DISABLED)
+	{
+		_state = Control::DISABLED;
+		_dirty = true;
+	}
 }
 }
 
 
-bool Control::isEnabled()
+bool Control::isEnabled() const
 {
 {
     return _state != DISABLED;
     return _state != DISABLED;
 }
 }
@@ -694,6 +719,29 @@ void Control::addListener(Control::Listener* listener, int eventFlags)
     }
     }
 }
 }
 
 
+void Control::removeListener(Control::Listener* listener)
+{
+    if (_listeners == NULL || listener == NULL)
+        return;
+
+    for (std::map<Listener::EventType, std::list<Listener*>*>::iterator itr = _listeners->begin(); itr != _listeners->end();)
+    {
+        itr->second->remove(listener);
+
+        if(itr->second->empty())
+        {
+            std::list<Listener*>* list = itr->second;
+            _listeners->erase(itr++);
+            SAFE_DELETE(list);
+        }
+        else
+            ++itr;
+    }
+
+    if (_listeners->empty())
+        SAFE_DELETE(_listeners);
+}
+
 void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
 void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
 {
 {
     GP_ASSERT(listener);
     GP_ASSERT(listener);
@@ -809,7 +857,7 @@ void Control::notifyListeners(Listener::EventType eventType)
         if (itr != _listeners->end())
         if (itr != _listeners->end())
         {
         {
             std::list<Listener*>* listenerList = itr->second;
             std::list<Listener*>* listenerList = itr->second;
-            for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); listenerItr++)
+            for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); ++listenerItr)
             {
             {
                 GP_ASSERT(*listenerItr);
                 GP_ASSERT(*listenerItr);
                 (*listenerItr)->controlEvent(this, eventType);
                 (*listenerItr)->controlEvent(this, eventType);
@@ -995,6 +1043,9 @@ void Control::drawText(const Rectangle& position)
 
 
 void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
 void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
 {
 {
+    if (!_visible)
+        return;
+
     if (needsClear)
     if (needsClear)
     {
     {
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
@@ -1114,6 +1165,8 @@ void Control::getAnimationPropertyValue(int propertyId, AnimationValue* value)
         value->setFloat(0, _bounds.height);
         value->setFloat(0, _bounds.height);
         break;
         break;
     case ANIMATE_OPACITY:
     case ANIMATE_OPACITY:
+        value->setFloat(0, _opacity);
+        break;
     default:
     default:
         break;
         break;
     }
     }
@@ -1152,6 +1205,7 @@ void Control::setAnimationPropertyValue(int propertyId, AnimationValue* value, f
         _dirty = true;
         _dirty = true;
         break;
         break;
     case ANIMATE_OPACITY:
     case ANIMATE_OPACITY:
+        setOpacity(Curve::lerp(blendWeight, _opacity, value->getFloat(0)));
         _dirty = true;
         _dirty = true;
         break;
         break;
     }
     }

+ 42 - 12
gameplay/src/Control.h

@@ -590,6 +590,22 @@ public:
      */
      */
     bool getTextRightToLeft(State state = NORMAL) const;
     bool getTextRightToLeft(State state = NORMAL) const;
 
 
+    /**
+     * Sets the visibility of a control.
+     *
+     * This is a quick way to hide a control without having to remove it from a form.
+     *
+     * @param visible true if the control is visible and enabled; false if not-visible and disabled.
+     */
+    void setVisible(bool visible);
+
+    /**
+     * Get the visibility of a control.
+     *
+     * @return true if the control is visible; false if not visible.
+     */
+    bool isVisible() const;
+
     /**
     /**
      * Set the opacity of this control.
      * Set the opacity of this control.
      *
      *
@@ -636,22 +652,19 @@ public:
      */
      */
     State getState() const;
     State getState() const;
 
 
-    /**
-     * Disable this control.
-     */
-    void disable();
-
-    /**
-     * Enable this control.
-     */
-    void enable();
+	/**
+	 * Enables/Disables a control. 
+	 *
+	 * @param enabled true if the control is enabled; false if disabled.
+	 */
+	void setEnabled(bool enabled);
 
 
     /**
     /**
      * Get whether this control is currently enabled.
      * Get whether this control is currently enabled.
      *
      *
      * @return Whether this control is currently enabled.
      * @return Whether this control is currently enabled.
      */
      */
-    bool isEnabled();
+    bool isEnabled() const;
 
 
     /**
     /**
      * Set whether this control consumes input events,
      * Set whether this control consumes input events,
@@ -725,7 +738,7 @@ public:
     virtual const char* getType() const;
     virtual const char* getType() const;
 
 
     /**
     /**
-     * Add a listener to be notified of specific events affecting
+     * Adds a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
      * this control.  Event types can be OR'ed together.
      * E.g. To listen to touch-press and touch-release events,
      * E.g. To listen to touch-press and touch-release events,
      * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
      * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
@@ -736,6 +749,13 @@ public:
      */
      */
     virtual void addListener(Control::Listener* listener, int eventFlags);
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
 
+    /**
+     * Removes a listener from this control.
+     * 
+     * @param listener The listener to remove.
+     */
+    virtual void removeListener(Control::Listener* listener);
+
     /**
     /**
      * @see AnimationTarget::getAnimationPropertyComponentCount
      * @see AnimationTarget::getAnimationPropertyComponentCount
      */
      */
@@ -847,7 +867,7 @@ protected:
     virtual void drawText(const Rectangle& clip);
     virtual void drawText(const Rectangle& clip);
 
 
     /**
     /**
-     * Draws a sprite batch for the specified clipping rect .
+     * Draws a sprite batch for the specified clipping rect.
      *
      *
      * @param spriteBatch The sprite batch to use.
      * @param spriteBatch The sprite batch to use.
      * @param clip The clipping rectangle.
      * @param clip The clipping rectangle.
@@ -965,6 +985,11 @@ protected:
      * The Control's Alignment
      * The Control's Alignment
      */
      */
     Alignment _alignment;
     Alignment _alignment;
+
+    /**
+     * Whether the Control's alignment has been set programmatically.
+     */
+    bool _isAlignmentSet;
     
     
     /**
     /**
      * Whether the Control's width is auto-sized.
      * Whether the Control's width is auto-sized.
@@ -986,6 +1011,11 @@ protected:
      */
      */
     Theme::Style* _style;
     Theme::Style* _style;
 
 
+    /**
+     * The control is not visible and _state become DISABLED if false.
+     */
+    bool _visible;
+
     /**
     /**
      * The current opacity of the control.
      * The current opacity of the control.
      */
      */

+ 106 - 3
gameplay/src/DebugNew.h

@@ -52,7 +52,7 @@ template<typename T> T* bullet_new()
 #endif
 #endif
 }
 }
 
 
-template<typename T, typename T1> T* bullet_new(T1 t1)
+template<typename T, typename T1> T* bullet_new(const T1& t1)
 {
 {
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION 
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION 
 #undef new 
 #undef new 
@@ -64,7 +64,7 @@ template<typename T, typename T1> T* bullet_new(T1 t1)
 #endif
 #endif
 }
 }
 
 
-template<typename T, typename T1, typename T2> T* bullet_new(T1 t1, T2 t2)
+template<typename T, typename T1, typename T2> T* bullet_new(const T1& t1, const T2& t2)
 {
 {
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #undef new
 #undef new
@@ -76,8 +76,111 @@ template<typename T, typename T1, typename T2> T* bullet_new(T1 t1, T2 t2)
 #endif
 #endif
 }
 }
 
 
+template<typename T, typename T1, typename T2> T* bullet_new(T1& t1, const T2& t2)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3> 
+T* bullet_new(const T1& t1, const T2& t2, const T3& t3)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3> 
+T* bullet_new(T1& t1, const T2& t2, const T3& t3)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3, typename T4> 
+T* bullet_new(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3, t4);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3, t4);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3, typename T4> 
+T* bullet_new(T1& t1, const T2& t2, const T3& t3, const T4& t4)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3, t4);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3, t4);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3, typename T4> 
+T* bullet_new(T1& t1, T2& t2, const T3& t3, const T4& t4)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3, t4);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3, t4);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3, typename T4, typename T5> 
+T* bullet_new(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3, t4, t5);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3, t4, t5);
+#endif
+}
+
+template<typename T, typename T1, typename T2, typename T3, typename T4, typename T5> 
+T* bullet_new(T1& t1, T2& t2, const T3& t3, const T4& t4, const T5& t5)
+{
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+    T* t = new T(t1, t2, t3, t4, t5);
+#define new DEBUG_NEW
+    return t;
+#else
+    return new T(t1, t2, t3, t4, t5);
+#endif
+}
+
 template<typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> 
 template<typename T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9> 
-T* bullet_new(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
+T* bullet_new(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8, const T9& t9)
 {
 {
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
 #undef new
 #undef new

+ 8 - 8
gameplay/src/Effect.cpp

@@ -21,7 +21,7 @@ Effect::~Effect()
     __effectCache.erase(_id);
     __effectCache.erase(_id);
 
 
     // Free uniforms.
     // Free uniforms.
-    for (std::map<std::string, Uniform*>::iterator itr = _uniforms.begin(); itr != _uniforms.end(); itr++)
+    for (std::map<std::string, Uniform*>::iterator itr = _uniforms.begin(); itr != _uniforms.end(); ++itr)
     {
     {
         SAFE_DELETE(itr->second);
         SAFE_DELETE(itr->second);
     }
     }
@@ -126,9 +126,8 @@ static void replaceIncludes(const char* filepath, const char* source, std::strin
     std::string str = source;
     std::string str = source;
     size_t lastPos = 0;
     size_t lastPos = 0;
     size_t headPos = 0;
     size_t headPos = 0;
-    size_t tailPos = 0;
     size_t fileLen = str.length();
     size_t fileLen = str.length();
-    tailPos = fileLen;
+    size_t tailPos = fileLen;
     while (headPos < fileLen)
     while (headPos < fileLen)
     {
     {
         lastPos = headPos;
         lastPos = headPos;
@@ -200,10 +199,11 @@ static void writeShaderToErrorFile(const char* filePath, const char* source)
 {
 {
     std::string path = filePath;
     std::string path = filePath;
     path += ".err";
     path += ".err";
-    FILE* file = FileSystem::openFile(path.c_str(), "wb");
-    int err = ferror(file);
-    fwrite(source, 1, strlen(source), file);
-    fclose(file);
+    std::auto_ptr<Stream> stream(FileSystem::open(path.c_str(), FileSystem::WRITE));
+    if (stream.get() != NULL && stream->canWrite())
+    {
+        stream->write(source, 1, strlen(source));
+    }
 }
 }
 
 
 Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, const char* fshPath, const char* fshSource, const char* defines)
 Effect* Effect::createFromSource(const char* vshPath, const char* vshSource, const char* fshPath, const char* fshSource, const char* defines)
@@ -454,7 +454,7 @@ Uniform* Effect::getUniform(const char* name) const
 Uniform* Effect::getUniform(unsigned int index) const
 Uniform* Effect::getUniform(unsigned int index) const
 {
 {
     unsigned int i = 0;
     unsigned int i = 0;
-    for (std::map<std::string, Uniform*>::const_iterator itr = _uniforms.begin(); itr != _uniforms.end(); itr++, i++)
+    for (std::map<std::string, Uniform*>::const_iterator itr = _uniforms.begin(); itr != _uniforms.end(); ++itr, ++i)
     {
     {
         if (i == index)
         if (i == index)
         {
         {

+ 441 - 33
gameplay/src/FileSystem.cpp

@@ -1,6 +1,7 @@
 #include "Base.h"
 #include "Base.h"
 #include "FileSystem.h"
 #include "FileSystem.h"
 #include "Properties.h"
 #include "Properties.h"
+#include "Stream.h"
 
 
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
@@ -28,7 +29,7 @@ namespace gameplay
 #ifdef __ANDROID__
 #ifdef __ANDROID__
 #include <unistd.h>
 #include <unistd.h>
 
 
-void makepath(std::string path, int mode)
+static void makepath(std::string path, int mode)
 {
 {
     std::vector<std::string> dirs;
     std::vector<std::string> dirs;
     while (path.length() > 0)
     while (path.length() > 0)
@@ -63,12 +64,100 @@ void makepath(std::string path, int mode)
     
     
     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
 #endif
 
 
 /** @script{ignore} */
 /** @script{ignore} */
 static std::string __resourcePath("./");
 static std::string __resourcePath("./");
 static std::map<std::string, std::string> __aliases;
 static std::map<std::string, std::string> __aliases;
 
 
+/**
+ * 
+ * @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()
 {
 {
 }
 }
@@ -201,11 +290,16 @@ bool FileSystem::fileExists(const char* filePath)
 {
 {
     GP_ASSERT(filePath);
     GP_ASSERT(filePath);
 
 
+#ifdef __ANDROID__
+    if (androidFileExists(filePath))
+    {
+        return true;
+    }
+#endif
+
     std::string fullPath(__resourcePath);
     std::string fullPath(__resourcePath);
     fullPath += resolvePath(filePath);
     fullPath += resolvePath(filePath);
 
 
-    createFileFromAsset(filePath);
-
     gp_stat_struct s;
     gp_stat_struct s;
 
 
 #ifdef WIN32
 #ifdef WIN32
@@ -230,15 +324,72 @@ bool FileSystem::fileExists(const char* filePath)
 #endif
 #endif
 }
 }
 
 
-FILE* FileSystem::openFile(const char* path, const char* mode)
+Stream* FileSystem::open(const char* path, size_t mode)
 {
 {
-    GP_ASSERT(path);
-    GP_ASSERT(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(__resourcePath);
     std::string fullPath(__resourcePath);
     fullPath += resolvePath(path);
     fullPath += resolvePath(path);
+    
+#ifdef WIN32
+    gp_stat_struct s;
+    if (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
+}
 
 
-    createFileFromAsset(path);
+FILE* FileSystem::openFile(const char* filePath, const char* mode)
+{
+    GP_ASSERT(filePath);
+    GP_ASSERT(mode);
+
+    std::string fullPath(__resourcePath);
+    fullPath += resolvePath(filePath);
+
+    createFileFromAsset(filePath);
     
     
     FILE* fp = fopen(fullPath.c_str(), mode);
     FILE* fp = fopen(fullPath.c_str(), mode);
     
     
@@ -247,14 +398,14 @@ FILE* FileSystem::openFile(const char* path, const char* mode)
     {
     {
         fullPath = __resourcePath;
         fullPath = __resourcePath;
         fullPath += "../../gameplay/";
         fullPath += "../../gameplay/";
-        fullPath += path;
+        fullPath += filePath;
         
         
         fp = fopen(fullPath.c_str(), mode);
         fp = fopen(fullPath.c_str(), mode);
         if (!fp)
         if (!fp)
         {
         {
             fullPath = __resourcePath;
             fullPath = __resourcePath;
             fullPath += "../gameplay/";
             fullPath += "../gameplay/";
-            fullPath += path;
+            fullPath += filePath;
             fp = fopen(fullPath.c_str(), mode);
             fp = fopen(fullPath.c_str(), mode);
         }
         }
     }
     }
@@ -268,32 +419,20 @@ char* FileSystem::readAll(const char* filePath, int* fileSize)
     GP_ASSERT(filePath);
     GP_ASSERT(filePath);
 
 
     // Open file for reading.
     // Open file for reading.
-    FILE* file = openFile(filePath, "rb");
-    if (file == NULL)
+    std::auto_ptr<Stream> stream(open(filePath));
+    if (stream.get() == NULL)
     {
     {
         GP_ERROR("Failed to load file: %s", filePath);
         GP_ERROR("Failed to load file: %s", filePath);
         return NULL;
         return NULL;
     }
     }
-
-    // Obtain file length.
-    if (fseek(file, 0, SEEK_END) != 0)
-    {
-        GP_ERROR("Failed to seek to the end of the file '%s' to obtain the file length.", filePath);
-        return NULL;
-    }
-    int size = (int)ftell(file);
-    if (fseek(file, 0, SEEK_SET) != 0)
-    {
-        GP_ERROR("Failed to seek to beginning of the file '%s' to begin reading in the entire file.", filePath);
-        return NULL;
-    }
+    size_t size = stream->length();
 
 
     // Read entire file contents.
     // Read entire file contents.
     char* buffer = new char[size + 1];
     char* buffer = new char[size + 1];
-    int read = (int)fread(buffer, 1, size, file);
+    size_t read = stream->read(buffer, 1, size);
     if (read != size)
     if (read != size)
     {
     {
-        GP_ERROR("Failed to read complete contents of file '%s' (amount read vs. file size: %d < %d).", filePath, (int)read, (int)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);
         SAFE_DELETE_ARRAY(buffer);
         return NULL;
         return NULL;
     }
     }
@@ -301,15 +440,9 @@ char* FileSystem::readAll(const char* filePath, int* fileSize)
     // Force the character buffer to be NULL-terminated.
     // Force the character buffer to be NULL-terminated.
     buffer[size] = '\0';
     buffer[size] = '\0';
 
 
-    // Close file and return.
-    if (fclose(file) != 0)
-    {
-        GP_ERROR("Failed to close file '%s'.", filePath);
-    }
-
     if (fileSize)
     if (fileSize)
     {
     {
-        *fileSize = size; 
+        *fileSize = (int)size; 
     }
     }
     return buffer;
     return buffer;
 }
 }
@@ -383,4 +516,279 @@ void FileSystem::createFileFromAsset(const char* path)
 #endif
 #endif
 }
 }
 
 
+//////////////////
+
+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
+
 }
 }

+ 28 - 0
gameplay/src/FileSystem.h

@@ -1,6 +1,8 @@
 #ifndef FILESYSTEM_H_
 #ifndef FILESYSTEM_H_
 #define FILESYSTEM_H_
 #define FILESYSTEM_H_
 
 
+#include "Stream.h"
+
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -13,6 +15,16 @@ class FileSystem
 {
 {
 public:
 public:
 
 
+    /**
+     * Mode flags for opening a stream.
+     * @script{ignore}
+     */
+    enum StreamMode
+    {
+        READ = 1,
+        WRITE = 2
+    };
+
     /**
     /**
      * Destructor.
      * Destructor.
      */
      */
@@ -107,6 +119,22 @@ public:
      */
      */
     static bool fileExists(const char* filePath);
     static bool fileExists(const char* filePath);
 
 
+    /**
+     * Opens a byte stream for the given resource path.
+     *
+     * If <code>path</code> is a file path, the file at the specified location is opened relative to the currently set
+     * resource path.
+     *
+     * @param path The path to the resource to be opened, relative to the currently set resource path.
+     * @param mode The mode used to open the file.
+     * 
+     * @return A stream that can be used to read or write to the file depending on the mode.
+     *         Returns NULL if there was an error. (Request mode not supported).
+     * 
+     * @script{ignore}
+     */
+    static Stream* open(const char* path, size_t mode = READ);
+
     /**
     /**
      * Opens the specified file.
      * Opens the specified file.
      *
      *

+ 4 - 4
gameplay/src/Font.cpp

@@ -30,7 +30,7 @@
     "void main()\n" \
     "void main()\n" \
     "{\n" \
     "{\n" \
         "gl_FragColor = v_color;\n" \
         "gl_FragColor = v_color;\n" \
-        "gl_FragColor.a = texture2D(u_texture, v_texCoord).a;\n" \
+        "gl_FragColor.a = texture2D(u_texture, v_texCoord).a * v_color.a;\n" \
     "}"
     "}"
 
 
 namespace gameplay
 namespace gameplay
@@ -272,7 +272,7 @@ Font::Text* Font::createText(const char* text, const Rectangle& area, const Vect
         }
         }
 
 
         bool draw = true;
         bool draw = true;
-        if (yPos < area.y)
+        if (yPos < static_cast<int>(area.y))
         {
         {
             // Skip drawing until line break or wrap.
             // Skip drawing until line break or wrap.
             draw = false;
             draw = false;
@@ -490,7 +490,7 @@ void Font::drawText(const char* text, int x, int y, const Vector4& color, unsign
 
 
         GP_ASSERT(_glyphs);
         GP_ASSERT(_glyphs);
         GP_ASSERT(_batch);
         GP_ASSERT(_batch);
-        for (size_t i = startIndex; i < length && i >= 0; i += iteration)
+        for (size_t i = startIndex; i < length; i += (size_t)iteration)
         {
         {
             char c = 0;
             char c = 0;
             if (rightToLeft)
             if (rightToLeft)
@@ -629,7 +629,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         }
         }
 
 
         bool draw = true;
         bool draw = true;
-        if (yPos < area.y - size)
+        if (yPos < static_cast<int>(area.y - size))
         {
         {
             // Skip drawing until line break or wrap.
             // Skip drawing until line break or wrap.
             draw = false;
             draw = false;

+ 9 - 5
gameplay/src/Font.h

@@ -69,17 +69,21 @@ public:
          */
          */
         ~Text();
         ~Text();
 
 
-        /**
-         * Hidden copy assignment operator.
-         */
-        Text& operator=(const Text&);
-
         /**
         /**
          * Get the string that will be drawn from this Text object.
          * Get the string that will be drawn from this Text object.
          */
          */
         const char* getText();
         const char* getText();
 
 
     private:
     private:
+        /**
+         * Hidden copy constructor.
+         */
+        Text(const Text&); 
+        /**
+         * Hidden copy assignment operator.
+         */
+        Text& operator=(const Text&);
+        
         std::string _text;
         std::string _text;
         unsigned int _vertexCount;
         unsigned int _vertexCount;
         SpriteBatch::SpriteVertex* _vertices;
         SpriteBatch::SpriteVertex* _vertices;

+ 16 - 7
gameplay/src/Form.cpp

@@ -99,6 +99,8 @@ Form* Form::create(const char* id, Theme::Style* style, Layout::Type layoutType)
     Game* game = Game::getInstance();
     Game* game = Game::getInstance();
     Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &form->_defaultProjectionMatrix);
     Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &form->_defaultProjectionMatrix);
 
 
+    form->updateBounds();
+
     __forms.push_back(form);
     __forms.push_back(form);
 
 
     return form;
     return form;
@@ -200,6 +202,8 @@ Form* Form::create(const char* url)
     form->addControls(theme, formProperties);
     form->addControls(theme, formProperties);
 
 
     SAFE_DELETE(properties);
     SAFE_DELETE(properties);
+    
+    form->updateBounds();
 
 
     __forms.push_back(form);
     __forms.push_back(form);
 
 
@@ -209,7 +213,7 @@ Form* Form::create(const char* url)
 Form* Form::getForm(const char* id)
 Form* Form::getForm(const char* id)
 {
 {
     std::vector<Form*>::const_iterator it;
     std::vector<Form*>::const_iterator it;
-    for (it = __forms.begin(); it < __forms.end(); it++)
+    for (it = __forms.begin(); it < __forms.end(); ++it)
     {
     {
         Form* f = *it;
         Form* f = *it;
         GP_ASSERT(f);
         GP_ASSERT(f);
@@ -403,6 +407,11 @@ void Form::setNode(Node* node)
 }
 }
 
 
 void Form::update(float elapsedTime)
 void Form::update(float elapsedTime)
+{
+    updateBounds();
+}
+
+void Form::updateBounds()
 {
 {
     if (isDirty())
     if (isDirty())
     {
     {
@@ -552,7 +561,8 @@ void Form::draw()
 
 
         GP_ASSERT(_theme);
         GP_ASSERT(_theme);
         _theme->setProjectionMatrix(_projectionMatrix);
         _theme->setProjectionMatrix(_projectionMatrix);
-        Container::draw(_theme->getSpriteBatch(), Rectangle(0, 0, _bounds.width, _bounds.height), _skin != NULL, false, _bounds.height);
+        Container::draw(_theme->getSpriteBatch(), Rectangle(0, 0, _bounds.width, _bounds.height),
+                        true/*WAS _skin!=NULL*/, false, _bounds.height);
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
 
 
         // Rebind the default framebuffer and game viewport.
         // Rebind the default framebuffer and game viewport.
@@ -710,13 +720,12 @@ bool Form::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelt
 bool Form::projectPoint(int x, int y, Vector3* point)
 bool Form::projectPoint(int x, int y, Vector3* point)
 {
 {
     Scene* scene = _node->getScene();
     Scene* scene = _node->getScene();
-    GP_ASSERT(scene);
-    Camera* camera = scene->getActiveCamera();
+    Camera* camera;
 
 
-    if (camera)
+    if (scene && (camera = scene->getActiveCamera()))
     {
     {
         // Get info about the form's position.
         // Get info about the form's position.
-        Matrix m = _node->getMatrix();
+        Matrix m = _node->getWorldMatrix();
         Vector3 min(0, 0, 0);
         Vector3 min(0, 0, 0);
         m.transformPoint(&min);
         m.transformPoint(&min);
 
 
@@ -731,7 +740,7 @@ bool Form::projectPoint(int x, int y, Vector3* point)
         // by the quad's forward vector and one of its points to the plane defined by the same vector and the origin.
         // by the quad's forward vector and one of its points to the plane defined by the same vector and the origin.
         const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
         const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
         const float d = -(a*min.x) - (b*min.y) - (c*min.z);
         const float d = -(a*min.x) - (b*min.y) - (c*min.z);
-        const float distance = abs(d) /  sqrt(a*a + b*b + c*c);
+        const float distance = fabs(d) /  sqrt(a*a + b*b + c*c);
         Plane plane(normal, -distance);
         Plane plane(normal, -distance);
 
 
         // Check for collision with plane.
         // Check for collision with plane.

+ 5 - 0
gameplay/src/Form.h

@@ -183,6 +183,11 @@ private:
      */
      */
     void initializeQuad(Mesh* mesh);
     void initializeQuad(Mesh* mesh);
 
 
+    /**
+     * Update this form's bounds.
+     */
+    void updateBounds();
+
     /**
     /**
      * Propagate touch events to enabled forms.
      * Propagate touch events to enabled forms.
      *
      *

+ 1 - 11
gameplay/src/FrameBuffer.cpp

@@ -84,12 +84,6 @@ FrameBuffer* FrameBuffer::create(const char* id, unsigned int width, unsigned in
     RenderTarget* renderTarget = NULL;
     RenderTarget* renderTarget = NULL;
     if (width > 0 && height > 0)
     if (width > 0 && height > 0)
     {
     {
-        if (!isPowerOfTwo(width) | !isPowerOfTwo(height))
-        {
-            GP_ERROR("Failed to create render target for frame buffer. Width and Height must be a power of 2.");
-            return NULL;
-        }
-
         // Create a default RenderTarget with same ID.
         // Create a default RenderTarget with same ID.
         renderTarget = RenderTarget::create(id, width, height);
         renderTarget = RenderTarget::create(id, width, height);
         if (renderTarget == NULL)
         if (renderTarget == NULL)
@@ -126,7 +120,7 @@ FrameBuffer* FrameBuffer::getFrameBuffer(const char* id)
 
 
     // Search the vector for a matching ID.
     // Search the vector for a matching ID.
     std::vector<FrameBuffer*>::const_iterator it;
     std::vector<FrameBuffer*>::const_iterator it;
-    for (it = __frameBuffers.begin(); it < __frameBuffers.end(); it++)
+    for (it = __frameBuffers.begin(); it < __frameBuffers.end(); ++it)
     {
     {
         FrameBuffer* fb = *it;
         FrameBuffer* fb = *it;
         GP_ASSERT(fb);
         GP_ASSERT(fb);
@@ -266,9 +260,5 @@ void FrameBuffer::bindDefault()
     __currentHandle = __defaultHandle;
     __currentHandle = __defaultHandle;
 }
 }
 
 
-bool FrameBuffer::isPowerOfTwo(unsigned int value)
-{
-    return (value != 0) && ((value & (value - 1)) == 0);
-}
 
 
 }
 }

+ 2 - 2
gameplay/src/Frustum.h

@@ -114,7 +114,7 @@ public:
     void getCorners(Vector3* corners) const;
     void getCorners(Vector3* corners) const;
 
 
     /**
     /**
-     * Tests whether this frustum instersects the specified point.
+     * Tests whether this frustum intersects the specified point.
      *
      *
      * @param point The point to test intersection with.
      * @param point The point to test intersection with.
      *
      *
@@ -123,7 +123,7 @@ public:
     bool intersects(const Vector3& point) const;
     bool intersects(const Vector3& point) const;
 
 
     /**
     /**
-     * Tests whether this frustum instersects the specified point.
+     * Tests whether this frustum intersects the specified point.
      *
      *
      * @param x The x coordinate.
      * @param x The x coordinate.
      * @param y The y coordinate.
      * @param y The y coordinate.

+ 12 - 12
gameplay/src/Game.cpp

@@ -246,18 +246,18 @@ void Game::resume()
         --_pausedCount;
         --_pausedCount;
 
 
         if (_pausedCount == 0)
         if (_pausedCount == 0)
-		{
-			GP_ASSERT(_animationController);
-			GP_ASSERT(_audioController);
-			GP_ASSERT(_physicsController);
-			GP_ASSERT(_aiController);
-			_state = RUNNING;
-			_pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
-			_animationController->resume();
-			_audioController->resume();
-			_physicsController->resume();
-			_aiController->resume();
-		}
+        {
+            GP_ASSERT(_animationController);
+            GP_ASSERT(_audioController);
+            GP_ASSERT(_physicsController);
+            GP_ASSERT(_aiController);
+            _state = RUNNING;
+            _pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
+            _animationController->resume();
+            _audioController->resume();
+            _physicsController->resume();
+            _aiController->resume();
+        }
     }
     }
 }
 }
 
 

+ 10 - 4
gameplay/src/Game.h

@@ -1,8 +1,6 @@
 #ifndef GAME_H_
 #ifndef GAME_H_
 #define GAME_H_
 #define GAME_H_
 
 
-#include <queue>
-
 #include "Keyboard.h"
 #include "Keyboard.h"
 #include "Mouse.h"
 #include "Mouse.h"
 #include "Touch.h"
 #include "Touch.h"
@@ -17,7 +15,6 @@
 #include "Vector4.h"
 #include "Vector4.h"
 #include "TimeListener.h"
 #include "TimeListener.h"
 
 
-
 namespace gameplay
 namespace gameplay
 {
 {
 
 
@@ -466,7 +463,7 @@ public:
     inline Gamepad* getGamepad(unsigned int index) const;
     inline Gamepad* getGamepad(unsigned int index) const;
 
 
     /**
     /**
-     * Sets muli-touch is to be enabled/disabled. Default is disabled.
+     * Sets multi-touch is to be enabled/disabled. Default is disabled.
      *
      *
      * @param enabled true sets multi-touch is enabled, false to be disabled.
      * @param enabled true sets multi-touch is enabled, false to be disabled.
      */
      */
@@ -517,6 +514,15 @@ public:
      */
      */
     void schedule(float timeOffset, const char* function);
     void schedule(float timeOffset, const char* function);
 
 
+    /**
+     * Opens an URL in an external browser, if available.
+     *
+     * @param url URL to be opened.
+     *
+     * @return True if URL was opened successfully, false otherwise.
+     */
+    bool launchURL(const char *url) const;
+
 protected:
 protected:
 
 
     /**
     /**

+ 6 - 0
gameplay/src/Game.inl

@@ -140,4 +140,10 @@ inline Gamepad* Game::getGamepad(unsigned int index) const
     else
     else
         return NULL;
         return NULL;
 }
 }
+
+inline bool Game::launchURL(const char* url) const
+{
+    return Platform::launchURL(url);
+}
+
 }
 }

+ 3 - 3
gameplay/src/Gamepad.h

@@ -33,8 +33,8 @@ public:
      */
      */
     enum ButtonState
     enum ButtonState
     {
     {
-        BUTTON_PRESSED = gameplay::Button::Listener::PRESS, 
-        BUTTON_RELEASED = gameplay::Button::Listener::RELEASE
+        BUTTON_PRESSED = gameplay::Control::Listener::PRESS, 
+        BUTTON_RELEASED = gameplay::Control::Listener::RELEASE
     };
     };
 
 
     /**
     /**
@@ -78,7 +78,7 @@ public:
      * Returns the specified joystick's value as a Vector2.
      * Returns the specified joystick's value as a Vector2.
      *
      *
      * @param joystickId The index of the joystick to get the value for.
      * @param joystickId The index of the joystick to get the value for.
-     * @param outValues The current x-axis and y-asix value displacement of the joystick.
+     * @param outValues The current x-axis and y-axis value displacement of the joystick.
      */
      */
     void getJoystickAxisValues(unsigned int joystickId, Vector2* outValues) const;
     void getJoystickAxisValues(unsigned int joystickId, Vector2* outValues) const;
 
 

+ 13 - 28
gameplay/src/Image.cpp

@@ -4,14 +4,23 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
+// Callback for reading a png image using Stream
+static void readStream(png_structp png, png_bytep data, png_size_t length)
+{
+    Stream* stream = reinterpret_cast<Stream*>(png_get_io_ptr(png));
+    if (stream == NULL || stream->read(data, 1, length) != length)
+    {
+        png_error(png, "Error reading PNG.");
+    }
+}
 
 
 Image* Image::create(const char* path)
 Image* Image::create(const char* path)
 {
 {
     GP_ASSERT(path);
     GP_ASSERT(path);
 
 
     // Open the file.
     // Open the file.
-    FILE* fp = FileSystem::openFile(path, "rb");
-    if (fp == NULL)
+    std::auto_ptr<Stream> stream(FileSystem::open(path));
+    if (stream.get() == NULL || !stream->canRead())
     {
     {
         GP_ERROR("Failed to open image file '%s'.", path);
         GP_ERROR("Failed to open image file '%s'.", path);
         return NULL;
         return NULL;
@@ -19,13 +28,9 @@ Image* Image::create(const char* path)
 
 
     // Verify PNG signature.
     // Verify PNG signature.
     unsigned char sig[8];
     unsigned char sig[8];
-    if (fread(sig, 1, 8, fp) != 8 || png_sig_cmp(sig, 0, 8) != 0)
+    if (stream->read(sig, 1, 8) != 8 || png_sig_cmp(sig, 0, 8) != 0)
     {
     {
         GP_ERROR("Failed to load file '%s'; not a valid PNG.", path);
         GP_ERROR("Failed to load file '%s'; not a valid PNG.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close image file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -34,10 +39,6 @@ Image* Image::create(const char* path)
     if (png == NULL)
     if (png == NULL)
     {
     {
         GP_ERROR("Failed to create PNG structure for reading PNG file '%s'.", path);
         GP_ERROR("Failed to create PNG structure for reading PNG file '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close image file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -46,10 +47,6 @@ Image* Image::create(const char* path)
     if (info == NULL)
     if (info == NULL)
     {
     {
         GP_ERROR("Failed to create PNG info structure for PNG file '%s'.", path);
         GP_ERROR("Failed to create PNG info structure for PNG file '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close image file '%s'.", path);
-        }
         png_destroy_read_struct(&png, NULL, NULL);
         png_destroy_read_struct(&png, NULL, NULL);
         return NULL;
         return NULL;
     }
     }
@@ -58,16 +55,12 @@ Image* Image::create(const char* path)
     if (setjmp(png_jmpbuf(png)))
     if (setjmp(png_jmpbuf(png)))
     {
     {
         GP_ERROR("Failed to set up error handling for reading PNG file '%s'.", path);
         GP_ERROR("Failed to set up error handling for reading PNG file '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close image file '%s'.", path);
-        }
         png_destroy_read_struct(&png, &info, NULL);
         png_destroy_read_struct(&png, &info, NULL);
         return NULL;
         return NULL;
     }
     }
 
 
     // Initialize file io.
     // Initialize file io.
-    png_init_io(png, fp);
+    png_set_read_fn(png, stream.get(), readStream);
 
 
     // Indicate that we already read the first 8 bytes (signature).
     // Indicate that we already read the first 8 bytes (signature).
     png_set_sig_bytes(png, 8);
     png_set_sig_bytes(png, 8);
@@ -92,10 +85,6 @@ Image* Image::create(const char* path)
 
 
     default:
     default:
         GP_ERROR("Unsupported PNG color type (%d) for image file '%s'.", (int)colorType, path);
         GP_ERROR("Unsupported PNG color type (%d) for image file '%s'.", (int)colorType, path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close image file '%s'.", path);
-        }
         png_destroy_read_struct(&png, &info, NULL);
         png_destroy_read_struct(&png, &info, NULL);
         return NULL;
         return NULL;
     }
     }
@@ -114,10 +103,6 @@ Image* Image::create(const char* path)
 
 
     // Clean up.
     // Clean up.
     png_destroy_read_struct(&png, &info, NULL);
     png_destroy_read_struct(&png, &info, NULL);
-    if (fclose(fp) != 0)
-    {
-        GP_ERROR("Failed to close image file '%s'.", path);
-    }
 
 
     return image;
     return image;
 }
 }

+ 0 - 2
gameplay/src/Joystick.h

@@ -18,10 +18,8 @@ namespace gameplay
         size        = <width, height>           // Size of the Control, measured in pixels.
         size        = <width, height>           // Size of the Control, measured in pixels.
         radius      = <float>                   // The value of the left- / bottom-most point on the slider.
         radius      = <float>                   // The value of the left- / bottom-most point on the slider.
         consumeEvents = <bool>                  // Whether the slider propagates input events to the Game's input event handler. Default is true.
         consumeEvents = <bool>                  // Whether the slider propagates input events to the Game's input event handler. Default is true.
-        
     }
     }
  @endverbatim
  @endverbatim
- *
  */
  */
 class Joystick : public Control
 class Joystick : public Control
 {
 {

+ 11 - 2
gameplay/src/Layout.cpp

@@ -12,8 +12,9 @@ void Layout::align(Control* control, const Container* container)
     GP_ASSERT(container);
     GP_ASSERT(container);
 
 
     if (control->_alignment != Control::ALIGN_TOP_LEFT ||
     if (control->_alignment != Control::ALIGN_TOP_LEFT ||
+        control->_isAlignmentSet ||
         control->_autoWidth || control->_autoHeight)
         control->_autoWidth || control->_autoHeight)
-    {
+    {
         Rectangle controlBounds = control->getBounds();
         Rectangle controlBounds = control->getBounds();
         const Theme::Margin& controlMargin = control->getMargin();
         const Theme::Margin& controlMargin = control->getMargin();
         const Rectangle& containerBounds = container->getBounds();
         const Rectangle& containerBounds = container->getBounds();
@@ -35,7 +36,7 @@ void Layout::align(Control* control, const Container* container)
             clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
             clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
         }
         }
 
 
-        if (control->_autoWidth)
+        if (control->_autoWidth)
         {
         {
             controlBounds.width = clipWidth - controlMargin.left - controlMargin.right;
             controlBounds.width = clipWidth - controlMargin.left - controlMargin.right;
         }
         }
@@ -54,6 +55,10 @@ void Layout::align(Control* control, const Container* container)
         {
         {
             controlBounds.y = clipHeight * 0.5f - controlBounds.height * 0.5f;
             controlBounds.y = clipHeight * 0.5f - controlBounds.height * 0.5f;
         }
         }
+        else if ((control->_alignment & Control::ALIGN_TOP) == Control::ALIGN_TOP)
+        {
+            controlBounds.y = 0;
+        }
 
 
         // Horizontal alignment
         // Horizontal alignment
         if ((control->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
         if ((control->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
@@ -64,6 +69,10 @@ void Layout::align(Control* control, const Container* container)
         {
         {
             controlBounds.x = clipWidth * 0.5f - controlBounds.width * 0.5f;
             controlBounds.x = clipWidth * 0.5f - controlBounds.width * 0.5f;
         }
         }
+        else if ((control->_alignment & Control::ALIGN_LEFT) == Control::ALIGN_LEFT)
+        {
+            controlBounds.x = 0;
+        }
 
 
         control->setBounds(controlBounds);
         control->setBounds(controlBounds);
     }
     }

+ 2 - 3
gameplay/src/MathUtil.cpp

@@ -17,11 +17,10 @@ void MathUtil::smooth(float* x, float target, float elapsedTime, float responseT
 void MathUtil::smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime)
 void MathUtil::smooth(float* x, float target, float elapsedTime, float riseTime, float fallTime)
 {
 {
     GP_ASSERT(x);
     GP_ASSERT(x);
-
-    float delta;
+    
     if (elapsedTime > 0)
     if (elapsedTime > 0)
     {
     {
-        delta = target - *x;
+        float delta = target - *x;
         *x += delta * elapsedTime / (elapsedTime + (delta > 0 ? riseTime : fallTime));
         *x += delta * elapsedTime / (elapsedTime + (delta > 0 ? riseTime : fallTime));
     }
     }
 }
 }

+ 72 - 3
gameplay/src/Matrix.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "Base.h"
 #include "Matrix.h"
 #include "Matrix.h"
+#include "Plane.h"
 #include "Quaternion.h"
 #include "Quaternion.h"
 #include "MathUtil.h"
 #include "MathUtil.h"
 
 
@@ -19,7 +20,8 @@ Matrix::Matrix()
     *this = Matrix::identity();
     *this = Matrix::identity();
 }
 }
 
 
-Matrix::Matrix(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
+Matrix::Matrix(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
+               float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
 {
 {
     set(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
     set(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
 }
 }
@@ -60,7 +62,8 @@ const Matrix& Matrix::zero()
 
 
 void Matrix::createLookAt(const Vector3& eyePosition, const Vector3& targetPosition, const Vector3& up, Matrix* dst)
 void Matrix::createLookAt(const Vector3& eyePosition, const Vector3& targetPosition, const Vector3& up, Matrix* dst)
 {
 {
-    createLookAt(eyePosition.x, eyePosition.y, eyePosition.z, targetPosition.x, targetPosition.y, targetPosition.z, up.x, up.y, up.z, dst);
+    createLookAt(eyePosition.x, eyePosition.y, eyePosition.z, targetPosition.x, targetPosition.y, targetPosition.z,
+                 up.x, up.y, up.z, dst);
 }
 }
 
 
 void Matrix::createLookAt(float eyePositionX, float eyePositionY, float eyePositionZ,
 void Matrix::createLookAt(float eyePositionX, float eyePositionY, float eyePositionZ,
@@ -162,6 +165,71 @@ void Matrix::createOrthographicOffCenter(float left, float right, float bottom,
     dst->m[14] = (-(zFarPlane + zNearPlane)) * f_n;
     dst->m[14] = (-(zFarPlane + zNearPlane)) * f_n;
     dst->m[15] = 1.0f;
     dst->m[15] = 1.0f;
 }
 }
+    
+void Matrix::createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                             const Vector3& cameraUpVector, Matrix* dst)
+{
+    createBillboardHelper(objectPosition, cameraPosition, cameraUpVector, NULL, dst);
+}
+
+void Matrix::createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                             const Vector3& cameraUpVector, const Vector3& cameraForwardVector,
+                             Matrix* dst)
+{
+    createBillboardHelper(objectPosition, cameraPosition, cameraUpVector, &cameraForwardVector, dst);
+}
+
+void Matrix::createBillboardHelper(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                   const Vector3& cameraUpVector, const Vector3* cameraForwardVector,
+                                   Matrix* dst)
+{
+    Vector3 delta(objectPosition, cameraPosition);
+    bool isSufficientDelta = delta.lengthSquared() > MATH_EPSILON;
+
+    dst->setIdentity();
+    dst->m[3] = objectPosition.x;
+    dst->m[7] = objectPosition.y;
+    dst->m[11] = objectPosition.z;
+
+    // As per the contracts for the 2 variants of createBillboard, we need
+    // either a safe default or a sufficient distance between object and camera.
+    if (cameraForwardVector || isSufficientDelta)
+    {
+        Vector3 target = isSufficientDelta ? cameraPosition : (objectPosition - *cameraForwardVector);
+
+        // A billboard is the inverse of a lookAt rotation
+        Matrix lookAt;
+        createLookAt(objectPosition, target, cameraUpVector, &lookAt);
+        dst->m[0] = lookAt.m[0];
+        dst->m[1] = lookAt.m[4];
+        dst->m[2] = lookAt.m[8];
+        dst->m[4] = lookAt.m[1];
+        dst->m[5] = lookAt.m[5];
+        dst->m[6] = lookAt.m[9];
+        dst->m[8] = lookAt.m[2];
+        dst->m[9] = lookAt.m[6];
+        dst->m[10] = lookAt.m[10];
+    }
+}
+    
+void Matrix::createReflection(const Plane& plane, Matrix* dst)
+{
+    Vector3 normal(plane.getNormal());
+    float k = -2.0f * plane.getDistance();
+
+    dst->setIdentity();
+
+    dst->m[0] -= 2.0f * normal.x * normal.x;
+    dst->m[5] -= 2.0f * normal.y * normal.y;
+    dst->m[10] -= 2.0f * normal.z * normal.z;
+    dst->m[1] = dst->m[4] = -2.0f * normal.x * normal.y;
+    dst->m[2] = dst->m[8] = -2.0f * normal.x * normal.z;
+    dst->m[6] = dst->m[9] = -2.0f * normal.y * normal.z;
+    
+    dst->m[3] = k * normal.x;
+    dst->m[7] = k * normal.y;
+    dst->m[11] = k * normal.z;
+}
 
 
 void Matrix::createScale(const Vector3& scale, Matrix* dst)
 void Matrix::createScale(const Vector3& scale, Matrix* dst)
 {
 {
@@ -763,7 +831,8 @@ void Matrix::scale(const Vector3& s, Matrix* dst) const
     scale(s.x, s.y, s.z, dst);
     scale(s.x, s.y, s.z, dst);
 }
 }
 
 
-void Matrix::set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
+void Matrix::set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
+                 float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
 {
 {
     m[0]  = m11;
     m[0]  = m11;
     m[1]  = m21;
     m[1]  = m21;

+ 63 - 31
gameplay/src/Matrix.h

@@ -7,6 +7,8 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+class Plane;
+
 /**
 /**
  * Defines a 4 x 4 floating point matrix representing a 3D transformation.
  * Defines a 4 x 4 floating point matrix representing a 3D transformation.
  *
  *
@@ -77,8 +79,8 @@ public:
      * @param m43 The third element of the fourth row.
      * @param m43 The third element of the fourth row.
      * @param m44 The fourth element of the fourth row.
      * @param m44 The fourth element of the fourth row.
      */
      */
-    Matrix(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31,
-           float m32, float m33, float m34, float m41, float m42, float m43, float m44);
+    Matrix(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
+           float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44);
 
 
     /**
     /**
      * Creates a matrix initialized to the specified column-major array.
      * Creates a matrix initialized to the specified column-major array.
@@ -149,8 +151,9 @@ public:
      * @param upZ The up vector z-coordinate value.
      * @param upZ The up vector z-coordinate value.
      * @param dst A matrix to store the result in.
      * @param dst A matrix to store the result in.
      */
      */
-    static void createLookAt(float eyePositionX, float eyePositionY, float eyePositionZ, float targetCenterX,
-                             float targetCenterY, float targetCenterZ, float upX, float upY, float upZ, Matrix* dst);
+    static void createLookAt(float eyePositionX, float eyePositionY, float eyePositionZ,
+                             float targetCenterX, float targetCenterY, float targetCenterZ,
+                             float upX, float upY, float upZ, Matrix* dst);
 
 
     /**
     /**
      * Builds a perspective projection matrix based on a field of view and returns by value.
      * Builds a perspective projection matrix based on a field of view and returns by value.
@@ -207,31 +210,54 @@ public:
      * @param zFarPlane The maximum z-value of the view volume.
      * @param zFarPlane The maximum z-value of the view volume.
      * @param dst A matrix to store the result in.
      * @param dst A matrix to store the result in.
      */
      */
-    static void createOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane,
-                                            float zFarPlane, Matrix* dst);
-
-//    /*
-//     * Creates a spherical billboard that rotates around a specified object position.
-//     *
-//     * This method computes the facing direction of the billboard from the object position
-//     * and camera position. When the object and camera positions are too close, the matrix
-//     * will not be accurate. To avoid this problem, the method uses the optional camera
-//     * forward vector if the positions are too close.
-//     *
-//     * @param objectPosition The position of the object the billboard will rotate around.
-//     * @param cameraPosition The position of the camera.
-//     * @param cameraUpVector The up vector of the camera.
-//     * @param dst A matrix to store the result in.
-//     */
-//    static void createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition, const Vector3& cameraUpVector, Matrix* dst);
-//
-//    /*
-//     * Fills in an existing Matrix so that it reflects the coordinate system about a specified Plane.
-//     *
-//     * @param plane The Plane about which to create a reflection.
-//     * @param dst A matrix to store the result in.
-//     */
-//    static void createReflection(const Plane& plane, Matrix* dst);
+    static void createOrthographicOffCenter(float left, float right, float bottom, float top,
+                                            float zNearPlane, float zFarPlane, Matrix* dst);
+
+    /*
+     * Creates a spherical billboard that rotates around a specified object position.
+     *
+     * This method computes the facing direction of the billboard from the object position
+     * and camera position. When the object and camera positions are too close, the matrix
+     * will not be accurate. To avoid this problem, this method defaults to the identity
+     * rotation if the positions are too close. (See the other overload of createBillboard
+     * for an alternative approach).
+     *
+     * @param objectPosition The position of the object the billboard will rotate around.
+     * @param cameraPosition The position of the camera.
+     * @param cameraUpVector The up vector of the camera.
+     * @param dst A matrix to store the result in.
+     */
+    static void createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                const Vector3& cameraUpVector, Matrix* dst);
+
+    /*
+     * Creates a spherical billboard that rotates around a specified object position with
+     * provision for a safe default orientation.
+     *
+     * This method computes the facing direction of the billboard from the object position
+     * and camera position. When the object and camera positions are too close, the matrix
+     * will not be accurate. To avoid this problem, this method uses the specified camera
+     * forward vector if the positions are too close. (See the other overload of createBillboard
+     * for an alternative approach).
+     *
+     * @param objectPosition The position of the object the billboard will rotate around.
+     * @param cameraPosition The position of the camera.
+     * @param cameraUpVector The up vector of the camera.
+     * @param cameraForwardVector The forward vector of the camera, used if the positions
+     *                            are too close.
+     * @param dst A matrix to store the result in.
+     */
+    static void createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                const Vector3& cameraUpVector, const Vector3& cameraForwardVector,
+                                Matrix* dst);
+
+    /*
+     * Fills in an existing Matrix so that it reflects the coordinate system about a specified Plane.
+     *
+     * @param plane The Plane about which to create a reflection.
+     * @param dst A matrix to store the result in.
+     */
+    static void createReflection(const Plane& plane, Matrix* dst);
 
 
     /**
     /**
      * Creates a scale matrix.
      * Creates a scale matrix.
@@ -664,8 +690,8 @@ public:
      * @param m43 The third element of the fourth row.
      * @param m43 The third element of the fourth row.
      * @param m44 The fourth element of the fourth row.
      * @param m44 The fourth element of the fourth row.
      */
      */
-    void set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31,
-             float m32, float m33, float m34, float m41, float m42, float m43, float m44);
+    void set(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24,
+             float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44);
 
 
     /**
     /**
      * Sets the values of this matrix to those in the specified column-major array.
      * Sets the values of this matrix to those in the specified column-major array.
@@ -885,6 +911,12 @@ public:
      * @return This matrix, after the multiplication occurs.
      * @return This matrix, after the multiplication occurs.
      */
      */
     inline Matrix& operator*=(const Matrix& m);
     inline Matrix& operator*=(const Matrix& m);
+    
+private:
+
+    static void createBillboardHelper(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                      const Vector3& cameraUpVector, const Vector3* cameraForwardVector,
+                                      Matrix* dst);
 };
 };
 
 
 /**
 /**

+ 78 - 35
gameplay/src/Model.cpp

@@ -253,6 +253,82 @@ void Model::setNode(Node* node)
     }
     }
 }
 }
 
 
+static bool drawWireframe(Mesh* mesh)
+{
+    switch (mesh->getPrimitiveType())
+    {
+    case Mesh::TRIANGLES:
+        {
+            unsigned int vertexCount = mesh->getVertexCount();
+            for (unsigned int i = 0; i < vertexCount; i += 3)
+            {
+                GL_ASSERT( glDrawArrays(GL_LINE_LOOP, i, 3) );
+            }
+        }
+        return true;
+
+    case Mesh::TRIANGLE_STRIP:
+        {
+            unsigned int vertexCount = mesh->getVertexCount();
+            for (unsigned int i = 2; i < vertexCount; ++i)
+            {
+                GL_ASSERT( glDrawArrays(GL_LINE_LOOP, i-2, 3) );
+            }
+        }
+        return true;
+
+    default:
+        // not supported
+        return false;
+    }
+}
+
+static bool drawWireframe(MeshPart* part)
+{
+    unsigned int indexCount = part->getIndexCount();
+    unsigned int indexSize = 0;
+    switch (part->getIndexFormat())
+    {
+    case Mesh::INDEX8:
+        indexSize = 1;
+        break;
+    case Mesh::INDEX16:
+        indexSize = 2;
+        break;
+    case Mesh::INDEX32:
+        indexSize = 4;
+        break;
+    default:
+        GP_ERROR("Unsupported index format (%d).", part->getIndexFormat());
+        return false;
+    }
+
+    switch (part->getPrimitiveType())
+    {
+    case Mesh::TRIANGLES:
+        {
+            for (unsigned int i = 0; i < indexCount; i += 3)
+            {
+                GL_ASSERT( glDrawElements(GL_LINE_LOOP, 3, part->getIndexFormat(), ((const GLvoid*)(i*indexSize))) );
+            }
+        }
+        return true;
+
+    case Mesh::TRIANGLE_STRIP:
+        {
+            for (unsigned int i = 2; i < indexCount; ++i)
+            {
+                GL_ASSERT( glDrawElements(GL_LINE_LOOP, 3, part->getIndexFormat(), ((const GLvoid*)((i-2)*indexSize))) );
+            }
+        }
+        return true;
+
+    default:
+        // not supported
+        return false;
+    }
+}
+
 void Model::draw(bool wireframe)
 void Model::draw(bool wireframe)
 {
 {
     GP_ASSERT(_mesh);
     GP_ASSERT(_mesh);
@@ -272,15 +348,7 @@ void Model::draw(bool wireframe)
                 GP_ASSERT(pass);
                 GP_ASSERT(pass);
                 pass->bind();
                 pass->bind();
                 GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) );
                 GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) );
-                if (wireframe && (_mesh->getPrimitiveType() == Mesh::TRIANGLES || _mesh->getPrimitiveType() == Mesh::TRIANGLE_STRIP))
-                {
-                    unsigned int vertexCount = _mesh->getVertexCount();
-                    for (unsigned int j = 0; j < vertexCount; j += 3)
-                    {
-                        GL_ASSERT( glDrawArrays(GL_LINE_LOOP, j, 3) );
-                    }
-                }
-                else
+                if (!wireframe || !drawWireframe(_mesh))
                 {
                 {
                     GL_ASSERT( glDrawArrays(_mesh->getPrimitiveType(), 0, _mesh->getVertexCount()) );
                     GL_ASSERT( glDrawArrays(_mesh->getPrimitiveType(), 0, _mesh->getVertexCount()) );
                 }
                 }
@@ -308,32 +376,7 @@ void Model::draw(bool wireframe)
                     GP_ASSERT(pass);
                     GP_ASSERT(pass);
                     pass->bind();
                     pass->bind();
                     GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, part->_indexBuffer) );
                     GL_ASSERT( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, part->_indexBuffer) );
-                    if (wireframe && (_mesh->getPrimitiveType() == Mesh::TRIANGLES || _mesh->getPrimitiveType() == Mesh::TRIANGLE_STRIP))
-                    {
-                        unsigned int indexCount = part->getIndexCount();
-                        unsigned int indexSize = 0;
-                        switch (part->getIndexFormat())
-                        {
-                        case Mesh::INDEX8:
-                            indexSize = 1;
-                            break;
-                        case Mesh::INDEX16:
-                            indexSize = 2;
-                            break;
-                        case Mesh::INDEX32:
-                            indexSize = 4;
-                            break;
-                        default:
-                            GP_ERROR("Unsupported index format (%d).", part->getIndexFormat());
-                            continue;
-                        }
-
-                        for (unsigned int k = 0; k < indexCount; k += 3)
-                        {
-                            GL_ASSERT( glDrawElements(GL_LINE_LOOP, 3, part->getIndexFormat(), ((const GLvoid*)(k*indexSize))) );
-                        }
-                    }
-                    else
+                    if (!wireframe || !drawWireframe(part))
                     {
                     {
                         GL_ASSERT( glDrawElements(part->getPrimitiveType(), part->getIndexCount(), part->getIndexFormat(), 0) );
                         GL_ASSERT( glDrawElements(part->getPrimitiveType(), part->getIndexCount(), part->getIndexFormat(), 0) );
                     }
                     }

+ 12 - 0
gameplay/src/Node.cpp

@@ -337,6 +337,18 @@ unsigned int Node::findNodes(const char* id, std::vector<Node*>& nodes, bool rec
     
     
     unsigned int count = 0;
     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.
     // Search immediate children first.
     for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
     for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
     {
     {

+ 5 - 5
gameplay/src/Node.h

@@ -334,7 +334,7 @@ public:
     /**
     /**
      * Returns the forward vector of the Node in view space.
      * Returns the forward vector of the Node in view space.
      *
      *
-     * @return The forwward vector in view space.
+     * @return The forward vector in view space.
      */
      */
     Vector3 getForwardVectorView() const;
     Vector3 getForwardVectorView() const;
 
 
@@ -505,11 +505,11 @@ public:
      * 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.
      * power-ups, etc.
      *
      *
-     * Characters are an extention of ghost objects which provide a number of additional features
+     * Characters are an extension of ghost objects which provide a number of additional features
      * for animating and moving characters within a game. Characters are represented as ghost
      * for animating and moving characters within a game. Characters are represented as ghost
      * objects instead of rigid bodies to allow more direct control over character movement,
      * objects instead of rigid bodies to allow more direct control over character movement,
      * since attempting to model a physics character with a simulated rigid body usually results
      * since attempting to model a physics character with a simulated rigid body usually results
-     * in unresponse and unpredictable character movement. Unlike normal ghost objects,
+     * in unresponsive and unpredictable character movement. Unlike normal ghost objects,
      * characters to react to other characters and rigid bodies in the world. Characters react
      * characters to react to other characters and rigid bodies in the world. Characters react
      * to gravity and collide (and respond) with rigid bodies to allow them to walk on the ground,
      * to gravity and collide (and respond) with rigid bodies to allow them to walk on the ground,
      * slide along walls and walk up/down slopes and stairs.
      * slide along walls and walk up/down slopes and stairs.
@@ -517,12 +517,12 @@ public:
      * @param type The type of the collision object to set; to disable the physics
      * @param type The type of the collision object to set; to disable the physics
      *        collision object, pass PhysicsCollisionObject::NONE.
      *        collision object, pass PhysicsCollisionObject::NONE.
      * @param shape Definition of a physics collision shape to be used for this collision object.
      * @param shape Definition of a physics collision shape to be used for this collision object.
-     *        Use the static shape methods on the PhysicsCollisionShape class to specificy a shape
+     *        Use the static shape methods on the PhysicsCollisionShape class to specify a shape
      *        definition, such as PhysicsCollisionShape::box().
      *        definition, such as PhysicsCollisionShape::box().
      * @param rigidBodyParameters If type is PhysicsCollisionObject::RIGID_BODY or
      * @param rigidBodyParameters If type is PhysicsCollisionObject::RIGID_BODY or
      *        PhysicsCollisionObject::VEHICLE, this must point to a valid rigid body
      *        PhysicsCollisionObject::VEHICLE, this must point to a valid rigid body
      *        parameters object containing information about the rigid body;
      *        parameters object containing information about the rigid body;
-     *        otherwise, this parmater may be NULL.
+     *        otherwise, this parameter may be NULL.
      */
      */
     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);
                                                PhysicsRigidBody::Parameters* rigidBodyParameters = NULL);

+ 1 - 2
gameplay/src/ParticleEmitter.cpp

@@ -48,8 +48,7 @@ ParticleEmitter::~ParticleEmitter()
 
 
 ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlending textureBlending, unsigned int particleCountMax)
 ParticleEmitter* ParticleEmitter::create(const char* textureFile, TextureBlending textureBlending, unsigned int particleCountMax)
 {
 {
-    Texture* texture = NULL;
-    texture = Texture::create(textureFile, false);
+    Texture* texture = Texture::create(textureFile, false);
 
 
     if (!texture)
     if (!texture)
     {
     {

+ 0 - 6
gameplay/src/Pass.h

@@ -35,12 +35,6 @@ public:
      */
      */
     Effect* getEffect() const;
     Effect* getEffect() const;
 
 
-    /**
-     * Get a list of properties to be auto-bound.
-     * @script{ignore}
-     */
-    const std::vector<std::string>* getAutoBindProperties() const;
-
     /**
     /**
      * Sets a vertex attribute binding for this pass.
      * Sets a vertex attribute binding for this pass.
      *
      *

+ 2 - 2
gameplay/src/PhysicsCollisionObject.cpp

@@ -17,7 +17,7 @@ struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
     /**
     /**
      * Called with each contact. Needed to implement collidesWith(PhysicsCollisionObject*).
      * Called with each contact. Needed to implement collidesWith(PhysicsCollisionObject*).
      */
      */
-    btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, const btCollisionObject* b, int partIdB, int indexB)
+    btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* a, int partIdA, int indexA, const btCollisionObjectWrapper* b, int partIdB, int indexB)
     {
     {
         result = true;
         result = true;
         return 0.0f;
         return 0.0f;
@@ -252,8 +252,8 @@ void PhysicsCollisionObject::PhysicsMotionState::updateTransformFromNode() const
 }
 }
 
 
 PhysicsCollisionObject::ScriptListener::ScriptListener(const char* url)
 PhysicsCollisionObject::ScriptListener::ScriptListener(const char* url)
+    : url(url)
 {
 {
-    this->url = url;
     function = Game::getInstance()->getScriptController()->loadUrl(url);
     function = Game::getInstance()->getScriptController()->loadUrl(url);
 }
 }
 
 

+ 1 - 1
gameplay/src/PhysicsCollisionObject.h

@@ -182,7 +182,7 @@ public:
     bool isDynamic() const;
     bool isDynamic() const;
 
 
     /**
     /**
-     * Check if th collision object is enabled.
+     * Check if the collision object is enabled.
      *
      *
      * @return true if the collision object is enabled.
      * @return true if the collision object is enabled.
      */
      */

+ 15 - 9
gameplay/src/PhysicsController.cpp

@@ -6,7 +6,13 @@
 #include "MeshPart.h"
 #include "MeshPart.h"
 #include "Bundle.h"
 #include "Bundle.h"
 
 
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#undef new
+#endif
 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
 #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
+#ifdef GAMEPLAY_MEM_LEAK_DETECTION
+#define new DEBUG_NEW
+#endif
 
 
 // The initial capacity of the Bullet debug drawer's vertex batch.
 // The initial capacity of the Bullet debug drawer's vertex batch.
 #define INITIAL_CAPACITY 280
 #define INITIAL_CAPACITY 280
@@ -347,14 +353,14 @@ bool PhysicsController::sweepTest(PhysicsCollisionObject* object, const Vector3&
     return false;
     return false;
 }
 }
 
 
-btScalar PhysicsController::CollisionCallback::addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, 
-    const btCollisionObject* b, int partIdB, int indexB)
+btScalar PhysicsController::CollisionCallback::addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* a, int partIdA, int indexA, 
+    const btCollisionObjectWrapper* b, int partIdB, int indexB)
 {
 {
     GP_ASSERT(_pc);
     GP_ASSERT(_pc);
 
 
     // Get pointers to the PhysicsCollisionObject objects.
     // Get pointers to the PhysicsCollisionObject objects.
-    PhysicsCollisionObject* objectA = _pc->getCollisionObject(a);
-    PhysicsCollisionObject* objectB = _pc->getCollisionObject(b);
+    PhysicsCollisionObject* objectA = _pc->getCollisionObject(a->m_collisionObject);
+    PhysicsCollisionObject* objectB = _pc->getCollisionObject(b->m_collisionObject);
 
 
     // If the given collision object pair has collided in the past, then
     // If the given collision object pair has collided in the past, then
     // we notify the listeners only if the pair was not colliding
     // we notify the listeners only if the pair was not colliding
@@ -422,13 +428,13 @@ btScalar PhysicsController::CollisionCallback::addSingleResult(btManifoldPoint&
 
 
 void PhysicsController::initialize()
 void PhysicsController::initialize()
 {
 {
-    _collisionConfiguration = new btDefaultCollisionConfiguration();
-    _dispatcher = new btCollisionDispatcher(_collisionConfiguration);
-    _overlappingPairCache = new btDbvtBroadphase();
-    _solver = new btSequentialImpulseConstraintSolver();
+    _collisionConfiguration = bullet_new<btDefaultCollisionConfiguration>();
+    _dispatcher = bullet_new<btCollisionDispatcher>(_collisionConfiguration);
+    _overlappingPairCache = bullet_new<btDbvtBroadphase>();
+    _solver = bullet_new<btSequentialImpulseConstraintSolver>();
 
 
     // Create the world.
     // Create the world.
-    _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
+    _world = bullet_new<btDiscreteDynamicsWorld>(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
     _world->setGravity(BV(_gravity));
     _world->setGravity(BV(_gravity));
 
 
     // Register ghost pair callback so bullet detects collisions with ghost objects (used for character collisions).
     // Register ghost pair callback so bullet detects collisions with ghost objects (used for character collisions).

+ 1 - 1
gameplay/src/PhysicsController.h

@@ -345,7 +345,7 @@ private:
         /**
         /**
             * Internal function used for Bullet integration (do not use or override).
             * Internal function used for Bullet integration (do not use or override).
             */
             */
-        btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, const btCollisionObject* b, int partIdB, int indexB);    
+        btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* a, int partIdA, int indexA, const btCollisionObjectWrapper* b, int partIdB, int indexB);    
 
 
     private:
     private:
         PhysicsController* _pc;
         PhysicsController* _pc;

+ 4 - 4
gameplay/src/PhysicsGenericConstraint.cpp

@@ -23,11 +23,11 @@ PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, PhysicsR
     {
     {
         GP_ASSERT(b->_body && b->getNode());
         GP_ASSERT(b->_body && b->getNode());
         Vector3 origin = centerOfMassMidpoint(a->getNode(), b->getNode());
         Vector3 origin = centerOfMassMidpoint(a->getNode(), b->getNode());
-        _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, getTransformOffset(a->getNode(), origin), getTransformOffset(b->getNode(), origin), true);
+        _constraint = bullet_new<btGeneric6DofConstraint>(*a->_body, *b->_body, getTransformOffset(a->getNode(), origin), getTransformOffset(b->getNode(), origin), true);
     }
     }
     else
     else
     {
     {
-        _constraint = new btGeneric6DofConstraint(*a->_body, btTransform::getIdentity(), true);
+        _constraint = bullet_new<btGeneric6DofConstraint>(*a->_body, btTransform::getIdentity(), true);
     }
     }
 }
 }
 
 
@@ -53,12 +53,12 @@ PhysicsGenericConstraint::PhysicsGenericConstraint(PhysicsRigidBody* a, const Qu
 
 
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         btTransform frameInB(BQ(rotationOffsetB), BV(tB));
         btTransform frameInB(BQ(rotationOffsetB), BV(tB));
-        _constraint = new btGeneric6DofConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
+        _constraint = bullet_new<btGeneric6DofConstraint>(*a->_body, *b->_body, frameInA, frameInB, true);
     }
     }
     else
     else
     {
     {
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
-        _constraint = new btGeneric6DofConstraint(*a->_body, frameInA, true);
+        _constraint = bullet_new<btGeneric6DofConstraint>(*a->_body, frameInA, true);
     }
     }
 }
 }
 
 

+ 2 - 2
gameplay/src/PhysicsHingeConstraint.cpp

@@ -34,12 +34,12 @@ PhysicsHingeConstraint::PhysicsHingeConstraint(PhysicsRigidBody* a, const Quater
 
 
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         btTransform frameInB(BQ(rotationOffsetB), BV(tB));
         btTransform frameInB(BQ(rotationOffsetB), BV(tB));
-        _constraint = new btHingeConstraint(*a->_body, *b->_body, frameInA, frameInB);
+        _constraint = bullet_new<btHingeConstraint>(*a->_body, *b->_body, frameInA, frameInB);
     }
     }
     else
     else
     {
     {
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
         btTransform frameInA(BQ(rotationOffsetA), BV(tA));
-        _constraint = new btHingeConstraint(*a->_body, frameInA);
+        _constraint = bullet_new<btHingeConstraint>(*a->_body, frameInA);
     }
     }
 }
 }
 
 

+ 4 - 4
gameplay/src/PhysicsSocketConstraint.cpp

@@ -16,11 +16,11 @@ PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, PhysicsRig
         btTransform frameInA = getTransformOffset(a->getNode(), origin);
         btTransform frameInA = getTransformOffset(a->getNode(), origin);
         btTransform frameInB = getTransformOffset(b->getNode(), origin);
         btTransform frameInB = getTransformOffset(b->getNode(), origin);
 
 
-        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, frameInA.getOrigin(), frameInB.getOrigin());
+        _constraint = bullet_new<btPoint2PointConstraint>(*a->_body, *b->_body, frameInA.getOrigin(), frameInB.getOrigin());
     }
     }
     else
     else
     {
     {
-        _constraint = new btPoint2PointConstraint(*a->_body, btVector3(0.0f, 0.0f, 0.0f));
+        _constraint = bullet_new<btPoint2PointConstraint>(*a->_body, btVector3(0.0f, 0.0f, 0.0f));
     }
     }
 }
 }
 
 
@@ -44,11 +44,11 @@ PhysicsSocketConstraint::PhysicsSocketConstraint(PhysicsRigidBody* a, const Vect
         b->getNode()->getWorldMatrix().getScale(&sB);
         b->getNode()->getWorldMatrix().getScale(&sB);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
         Vector3 tB(translationOffsetB.x * sB.x, translationOffsetB.y * sB.y, translationOffsetB.z * sB.z);
 
 
-        _constraint = new btPoint2PointConstraint(*a->_body, *b->_body, BV(tA), BV(tB));
+        _constraint = bullet_new<btPoint2PointConstraint>(*a->_body, *b->_body, BV(tA), BV(tB));
     }
     }
     else
     else
     {
     {
-        _constraint = new btPoint2PointConstraint(*a->_body, BV(tA));
+        _constraint = bullet_new<btPoint2PointConstraint>(*a->_body, BV(tA));
     }
     }
 }
 }
 
 

+ 2 - 2
gameplay/src/PhysicsSpringConstraint.cpp

@@ -16,7 +16,7 @@ PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, PhysicsRig
     _b = b;
     _b = b;
 
 
     Vector3 origin = centerOfMassMidpoint(a->getNode(), b->getNode());
     Vector3 origin = centerOfMassMidpoint(a->getNode(), b->getNode());
-    _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, getTransformOffset(a->getNode(), origin), getTransformOffset(b->getNode(), origin), true);
+    _constraint = bullet_new<btGeneric6DofSpringConstraint>(*a->_body, *b->_body, getTransformOffset(a->getNode(), origin), getTransformOffset(b->getNode(), origin), true);
 }
 }
 
 
 PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
 PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
@@ -40,7 +40,7 @@ PhysicsSpringConstraint::PhysicsSpringConstraint(PhysicsRigidBody* a, const Quat
 
 
     btTransform frameInA(BQ(rotationOffsetA), BV(tA));
     btTransform frameInA(BQ(rotationOffsetA), BV(tA));
     btTransform frameInB(BQ(rotationOffsetB), BV(tB));
     btTransform frameInB(BQ(rotationOffsetB), BV(tB));
-    _constraint = new btGeneric6DofSpringConstraint(*a->_body, *b->_body, frameInA, frameInB, true);
+    _constraint = bullet_new<btGeneric6DofSpringConstraint>(*a->_body, *b->_body, frameInA, frameInB, true);
 }
 }
 
 
 PhysicsSpringConstraint::~PhysicsSpringConstraint()
 PhysicsSpringConstraint::~PhysicsSpringConstraint()

+ 1 - 1
gameplay/src/PhysicsVehicle.cpp

@@ -184,7 +184,7 @@ void PhysicsVehicle::initialize()
     btRigidBody* body = static_cast<btRigidBody*>(_rigidBody->getCollisionObject());
     btRigidBody* body = static_cast<btRigidBody*>(_rigidBody->getCollisionObject());
     btDynamicsWorld* dynamicsWorld = Game::getInstance()->getPhysicsController()->_world;
     btDynamicsWorld* dynamicsWorld = Game::getInstance()->getPhysicsController()->_world;
     _vehicleRaycaster = new VehicleNotMeRaycaster(dynamicsWorld, body);
     _vehicleRaycaster = new VehicleNotMeRaycaster(dynamicsWorld, body);
-    _vehicle = new btRaycastVehicle(_vehicleTuning, body, _vehicleRaycaster);
+    _vehicle = bullet_new<btRaycastVehicle>(_vehicleTuning, body, _vehicleRaycaster);
     body->setActivationState(DISABLE_DEACTIVATION);
     body->setActivationState(DISABLE_DEACTIVATION);
     dynamicsWorld->addVehicle(_vehicle);
     dynamicsWorld->addVehicle(_vehicle);
     _vehicle->setCoordinateSystem(0, 1, 2);
     _vehicle->setCoordinateSystem(0, 1, 2);

+ 9 - 0
gameplay/src/Platform.h

@@ -361,6 +361,15 @@ public:
      * @see Mouse::MouseEvent
      * @see Mouse::MouseEvent
      */
      */
     static bool mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
     static bool mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta);
+
+    /**
+     * Opens an URL in an external browser, if available.
+     *
+     * @param url URL to be opened.
+     *
+     * @return True if URL was opened successfully, false otherwise.
+     */
+    static bool launchURL(const char* url);
     
     
 private:
 private:
 
 

+ 194 - 61
gameplay/src/PlatformAndroid.cpp

@@ -105,25 +105,68 @@ static EGLenum checkErrorEGL(const char* msg)
     return error;
     return error;
 }
 }
 
 
+static int getRotation()
+{
+    jint rotation;
+
+    // Get the android application's activity.
+    ANativeActivity* activity = __state->activity;
+    JavaVM* jvm = __state->activity->vm;
+    JNIEnv* env = NULL;
+    jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
+    jint res = jvm->AttachCurrentThread(&env, NULL);
+    if (res == JNI_ERR)
+    {
+        GP_ERROR("Failed to retrieve JVM environment when entering message pump.");
+        return -1; 
+    }
+    GP_ASSERT(env);
+
+    jclass clsContext = env->FindClass("android/content/Context");
+    GP_ASSERT(clsContext != NULL);
+    jmethodID getSystemService = env->GetMethodID(clsContext, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
+    GP_ASSERT(getSystemService != NULL);
+    jfieldID WINDOW_SERVICE_ID = env->GetStaticFieldID(clsContext, "WINDOW_SERVICE", "Ljava/lang/String;");
+    GP_ASSERT(WINDOW_SERVICE_ID != NULL);
+    jstring WINDOW_SERVICE = (jstring) env->GetStaticObjectField(clsContext, WINDOW_SERVICE_ID);
+    GP_ASSERT(WINDOW_SERVICE != NULL);
+    jobject windowManager = env->CallObjectMethod(activity->clazz, getSystemService, WINDOW_SERVICE);
+    GP_ASSERT(windowManager != NULL);
+    jclass clsWindowManager = env->FindClass("android/view/WindowManager");
+    GP_ASSERT(clsWindowManager != NULL);
+    jmethodID getDefaultDisplay = env->GetMethodID(clsWindowManager, "getDefaultDisplay", "()Landroid/view/Display;");
+    GP_ASSERT(getDefaultDisplay != NULL);
+    jobject defaultDisplay = env->CallObjectMethod(windowManager, getDefaultDisplay);
+    GP_ASSERT(defaultDisplay != NULL);
+    jclass clsDisplay = env->FindClass("android/view/Display");
+    GP_ASSERT(clsDisplay != NULL);
+    jmethodID getRotation = env->GetMethodID(clsDisplay, "getRotation", "()I");
+    GP_ASSERT(getRotation != NULL)
+    rotation =  env->CallIntMethod(defaultDisplay, getRotation);
+
+    return rotation;
+}
+
+
 // Initialized EGL resources.
 // Initialized EGL resources.
 static bool initEGL()
 static bool initEGL()
 {
 {
-	int samples = 0;
-	Properties* config = Game::getInstance()->getConfig()->getNamespace("window", true);
-	if (config)
-	{
-		samples = std::max(config->getInt("samples"), 0);
-	}
+    int samples = 0;
+    Properties* config = Game::getInstance()->getConfig()->getNamespace("window", true);
+    if (config)
+    {
+        samples = std::max(config->getInt("samples"), 0);
+    }
 
 
     // Hard-coded to 32-bit/OpenGL ES 2.0.
     // Hard-coded to 32-bit/OpenGL ES 2.0.
     // NOTE: EGL_SAMPLE_BUFFERS, EGL_SAMPLES and EGL_DEPTH_SIZE MUST remain at the beginning of the attribute list
     // NOTE: EGL_SAMPLE_BUFFERS, EGL_SAMPLES and EGL_DEPTH_SIZE MUST remain at the beginning of the attribute list
     // since they are expected to be at indices 0-5 in config fallback code later.
     // since they are expected to be at indices 0-5 in config fallback code later.
-	// EGL_DEPTH_SIZE is also expected to
+    // EGL_DEPTH_SIZE is also expected to
     EGLint eglConfigAttrs[] =
     EGLint eglConfigAttrs[] =
     {
     {
-		EGL_SAMPLE_BUFFERS,     samples > 0 ? 1 : 0,
-		EGL_SAMPLES,            samples,
-		EGL_DEPTH_SIZE,         24,
+        EGL_SAMPLE_BUFFERS,     samples > 0 ? 1 : 0,
+        EGL_SAMPLES,            samples,
+        EGL_DEPTH_SIZE,         24,
         EGL_RED_SIZE,           8,
         EGL_RED_SIZE,           8,
         EGL_GREEN_SIZE,         8,
         EGL_GREEN_SIZE,         8,
         EGL_BLUE_SIZE,          8,
         EGL_BLUE_SIZE,          8,
@@ -163,51 +206,51 @@ static bool initEGL()
             goto error;
             goto error;
         }
         }
 
 
-		// Try both 24 and 16-bit depth sizes since some hardware (i.e. Tegra) does not support 24-bit depth
-		bool validConfig = false;
-		EGLint depthSizes[] = { 24, 16 };
-		for (unsigned int i = 0; i < 2; ++i)
-		{
-			eglConfigAttrs[1] = samples > 0 ? 1 : 0;
-			eglConfigAttrs[3] = samples;
-			eglConfigAttrs[5] = depthSizes[i];
-
-			if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
-			{
-				validConfig = true;
-				break;
-			}
-
-			if (samples)
-			{
-				// Try lowering the MSAA sample size until we find a supported config
-				int sampleCount = samples;
-				while (sampleCount)
-				{
-					GP_WARN("No EGL config found for depth_size=%d and samples=%d. Trying samples=%d instead.", depthSizes[i], sampleCount, sampleCount / 2);
-					sampleCount /= 2;
-					eglConfigAttrs[1] = sampleCount > 0 ? 1 : 0;
-					eglConfigAttrs[3] = sampleCount;
-					if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
-					{
-						validConfig = true;
-						break;
-					}
-				}
-				if (validConfig)
-					break;
-			}
-			else
-			{
-				GP_WARN("No EGL config found for depth_size=%d.", depthSizes[i]);
-			}
-		}
-
-		if (!validConfig)
-		{
-			checkErrorEGL("eglChooseConfig");
-			goto error;
-		}
+        // Try both 24 and 16-bit depth sizes since some hardware (i.e. Tegra) does not support 24-bit depth
+        bool validConfig = false;
+        EGLint depthSizes[] = { 24, 16 };
+        for (unsigned int i = 0; i < 2; ++i)
+        {
+            eglConfigAttrs[1] = samples > 0 ? 1 : 0;
+            eglConfigAttrs[3] = samples;
+            eglConfigAttrs[5] = depthSizes[i];
+
+            if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
+            {
+                validConfig = true;
+                break;
+            }
+
+            if (samples)
+            {
+                // Try lowering the MSAA sample size until we find a supported config
+                int sampleCount = samples;
+                while (sampleCount)
+                {
+                    GP_WARN("No EGL config found for depth_size=%d and samples=%d. Trying samples=%d instead.", depthSizes[i], sampleCount, sampleCount / 2);
+                    sampleCount /= 2;
+                    eglConfigAttrs[1] = sampleCount > 0 ? 1 : 0;
+                    eglConfigAttrs[3] = sampleCount;
+                    if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
+                    {
+                        validConfig = true;
+                        break;
+                    }
+                }
+                if (validConfig)
+                    break;
+            }
+            else
+            {
+                GP_WARN("No EGL config found for depth_size=%d.", depthSizes[i]);
+            }
+        }
+
+        if (!validConfig)
+        {
+            checkErrorEGL("eglChooseConfig");
+            goto error;
+        }
 
 
         __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
         __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
         if (__eglContext == EGL_NO_CONTEXT)
         if (__eglContext == EGL_NO_CONTEXT)
@@ -241,8 +284,7 @@ static bool initEGL()
     eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
     eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
     eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
     eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
 
 
-    if (__width < __height)
-        __orientationAngle = 0;
+    __orientationAngle = getRotation() * 90;
     
     
     // Set vsync.
     // Set vsync.
     eglSwapInterval(__eglDisplay, WINDOW_VSYNC ? 1 : 0);
     eglSwapInterval(__eglDisplay, WINDOW_VSYNC ? 1 : 0);
@@ -1107,15 +1149,24 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     
     
     // By default, android accelerometer values are oriented to the portrait mode.
     // By default, android accelerometer values are oriented to the portrait mode.
     // flipping the x and y to get the desired landscape mode values.
     // flipping the x and y to get the desired landscape mode values.
-    if (__orientationAngle == 90)
+    switch (__orientationAngle)
     {
     {
+    case 90:
         tx = -__sensorEvent.acceleration.y;
         tx = -__sensorEvent.acceleration.y;
         ty = __sensorEvent.acceleration.x;
         ty = __sensorEvent.acceleration.x;
-    }
-    else
-    {
+        break;
+    case 180:
+        tx = -__sensorEvent.acceleration.x;
+        ty = -__sensorEvent.acceleration.y;
+        break;
+    case 270:
+        tx = __sensorEvent.acceleration.y;
+        ty = -__sensorEvent.acceleration.x;
+        break;
+    default:
         tx = __sensorEvent.acceleration.x;
         tx = __sensorEvent.acceleration.x;
         ty = __sensorEvent.acceleration.y;
         ty = __sensorEvent.acceleration.y;
+        break;
     }
     }
     tz = __sensorEvent.acceleration.z;
     tz = __sensorEvent.acceleration.z;
 
 
@@ -1307,6 +1358,88 @@ float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int
     return 0.0f;
     return 0.0f;
 }
 }
 
 
+bool Platform::launchURL(const char *url)
+{
+    if (url == NULL || *url == '\0')
+        return false;
+
+    bool result = true;
+
+    android_app* state = __state;
+    GP_ASSERT(state && state->activity && state->activity->vm);
+    JavaVM* jvm = state->activity->vm;
+    JNIEnv* env = NULL;
+    jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
+    jint r = jvm->AttachCurrentThread(&env, NULL);
+    if (r == JNI_ERR)
+    {
+        GP_ERROR("Failed to retrieve JVM environment to display keyboard.");
+        return false;
+    }
+    GP_ASSERT(env);
+
+    jclass classActivity = env->FindClass("android/app/NativeActivity");
+    jclass classIntent = env->FindClass("android/content/Intent");
+    jclass classUri = env->FindClass("android/net/Uri");
+
+    GP_ASSERT(classActivity && classIntent && classUri);
+
+    // Get static field ID Intent.ACTION_VIEW
+    jfieldID fieldActionView = env->GetStaticFieldID(classIntent, "ACTION_VIEW", "Ljava/lang/String;");
+    GP_ASSERT(fieldActionView);
+
+    // Get string value of Intent.ACTION_VIEW, we'll need that to pass to Intent's constructor later on
+    jstring paramActionView = (jstring)env->GetStaticObjectField(classIntent, fieldActionView);
+    GP_ASSERT(paramActionView);
+
+    // Get method ID Uri.parse, will be needed to parse the url given into Uri object
+    jmethodID methodUriParse = env->GetStaticMethodID(classUri, "parse","(Ljava/lang/String;)Landroid/net/Uri;");
+    GP_ASSERT(methodUriParse);
+
+    // Get method ID Activity.startActivity, so we can start the appropriate activity for the View action of our Uri
+    jmethodID methodActivityStartActivity = env->GetMethodID(classActivity, "startActivity","(Landroid/content/Intent;)V");
+    GP_ASSERT(methodActivityStartActivity);
+
+    // Get method ID Intent constructor, the one that takes action and uri (String;Uri)
+    jmethodID methodIntentInit = env->GetMethodID(classIntent, "<init>","(Ljava/lang/String;Landroid/net/Uri;)V");
+    GP_ASSERT(methodIntentInit);
+
+    // Convert our url to Java's string and parse it to Uri
+    jstring paramUrlString = env->NewStringUTF(url);
+    jobject paramUri = env->CallStaticObjectMethod(classUri, methodUriParse, paramUrlString);
+    GP_ASSERT(paramUri);
+
+    // Create Intent with Intent.ACTION_VIEW and parsed Uri arguments
+    jobject paramIntent = env->NewObject(classIntent, methodIntentInit, paramActionView, paramUri);
+    GP_ASSERT(paramIntent);
+
+    // Launch NativeActivity.startActivity with our intent to view the url! state->activity->clazz holds
+    // our NativeActivity object
+    env->CallVoidMethod(state->activity->clazz, methodActivityStartActivity, paramIntent);
+
+    /* startActivity may throw a ActivitNotFoundException if, well, activity is not found.
+       Example: http://<url> is passed to the intent but there is no browser installed in the system
+       we need to handle it. */
+    jobject exception = env->ExceptionOccurred();
+
+    // We're not lucky here
+    if (exception)
+    {
+        // Print out the exception data to logcat
+        env->ExceptionDescribe();
+
+        // Exception needs to be cleared
+        env->ExceptionClear();
+
+        // Launching the url failed
+        result = false;
+    }
+
+    // See you Space Cowboy
+    jvm->DetachCurrentThread();
+    return result;
+}
+
 }
 }
 
 
 #endif
 #endif

+ 28 - 20
gameplay/src/PlatformBlackBerry.cpp

@@ -776,26 +776,26 @@ Platform* Platform::create(Game* game, void* attachToWindow)
 
 
     if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
     if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
     {
     {
-    	bool success = false;
-    	while (samples)
-    	{
-    		// Try lowering the MSAA sample count until we find a supported config
-    		GP_WARN("Failed to find a valid EGL configuration with EGL samples=%d. Trying samples=%d instead.", samples, samples/2);
-    		samples /= 2;
-    		eglConfigAttrs[1] = samples > 0 ? 1 : 0;
-    		eglConfigAttrs[3] = samples;
-    		if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
-    		{
-    			success = true;
-    			break;
-    		}
-    	}
-
-    	if (!success)
-    	{
-			checkErrorEGL("eglChooseConfig");
-			goto error;
-    	}
+        bool success = false;
+        while (samples)
+        {
+            // Try lowering the MSAA sample count until we find a supported config
+            GP_WARN("Failed to find a valid EGL configuration with EGL samples=%d. Trying samples=%d instead.", samples, samples/2);
+            samples /= 2;
+            eglConfigAttrs[1] = samples > 0 ? 1 : 0;
+            eglConfigAttrs[3] = samples;
+            if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) == EGL_TRUE && eglConfigCount > 0)
+            {
+                success = true;
+                break;
+            }
+        }
+
+        if (!success)
+        {
+            checkErrorEGL("eglChooseConfig");
+            goto error;
+        }
     }
     }
 
 
     __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
     __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
@@ -1424,6 +1424,14 @@ float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int
     return 0.0f;
     return 0.0f;
 }
 }
 
 
+bool Platform::launchURL(const char* url)
+{
+    if (url == NULL || *url == '\0')
+        return false;
+
+    return navigator_invoke(url, NULL) == BPS_SUCCESS;
+}
+
 }
 }
 
 
 #endif
 #endif

+ 331 - 55
gameplay/src/PlatformLinux.cpp

@@ -24,12 +24,16 @@ static double __timeAbsolute;
 static bool __vsync = WINDOW_VSYNC;
 static bool __vsync = WINDOW_VSYNC;
 static float __pitch;
 static float __pitch;
 static float __roll;
 static float __roll;
+static bool __mouseCaptured = false;
+static float __mouseCapturePointX = 0;
+static float __mouseCapturePointY = 0;
 static bool __cursorVisible = true;
 static bool __cursorVisible = true;
 static Display* __display;
 static Display* __display;
 static Window   __window;
 static Window   __window;
 static int __windowSize[2];
 static int __windowSize[2];
 static GLXContext __context;
 static GLXContext __context;
 static Window __attachToWindow;
 static Window __attachToWindow;
+static Atom __atomWmDeleteWindow;
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -355,6 +359,124 @@ static Keyboard::Key getKey(KeySym sym)
     }
     }
 }
 }
 
 
+/**
+ * Returns the unicode value for the given keycode or zero if the key is not a valid printable character.
+ */
+static int getUnicode(Keyboard::Key key)
+{
+
+    switch (key)
+    {
+    case Keyboard::KEY_BACKSPACE:
+        return 0x0008;
+    case Keyboard::KEY_TAB:
+        return 0x0009;
+    case Keyboard::KEY_RETURN:
+    case Keyboard::KEY_KP_ENTER:
+        return 0x000A;
+    case Keyboard::KEY_ESCAPE:
+        return 0x001B;
+    case Keyboard::KEY_SPACE:
+    case Keyboard::KEY_EXCLAM:
+    case Keyboard::KEY_QUOTE:
+    case Keyboard::KEY_NUMBER:
+    case Keyboard::KEY_DOLLAR:
+    case Keyboard::KEY_PERCENT:
+    case Keyboard::KEY_CIRCUMFLEX:
+    case Keyboard::KEY_AMPERSAND:
+    case Keyboard::KEY_APOSTROPHE:
+    case Keyboard::KEY_LEFT_PARENTHESIS:
+    case Keyboard::KEY_RIGHT_PARENTHESIS:
+    case Keyboard::KEY_ASTERISK:
+    case Keyboard::KEY_PLUS:
+    case Keyboard::KEY_COMMA:
+    case Keyboard::KEY_MINUS:
+    case Keyboard::KEY_PERIOD:
+    case Keyboard::KEY_SLASH:
+    case Keyboard::KEY_ZERO:
+    case Keyboard::KEY_ONE:
+    case Keyboard::KEY_TWO:
+    case Keyboard::KEY_THREE:
+    case Keyboard::KEY_FOUR:
+    case Keyboard::KEY_FIVE:
+    case Keyboard::KEY_SIX:
+    case Keyboard::KEY_SEVEN:
+    case Keyboard::KEY_EIGHT:
+    case Keyboard::KEY_NINE:
+    case Keyboard::KEY_COLON:
+    case Keyboard::KEY_SEMICOLON:
+    case Keyboard::KEY_LESS_THAN:
+    case Keyboard::KEY_EQUAL:
+    case Keyboard::KEY_GREATER_THAN:
+    case Keyboard::KEY_QUESTION:
+    case Keyboard::KEY_AT:
+    case Keyboard::KEY_CAPITAL_A:
+    case Keyboard::KEY_CAPITAL_B:
+    case Keyboard::KEY_CAPITAL_C:
+    case Keyboard::KEY_CAPITAL_D:
+    case Keyboard::KEY_CAPITAL_E:
+    case Keyboard::KEY_CAPITAL_F:
+    case Keyboard::KEY_CAPITAL_G:
+    case Keyboard::KEY_CAPITAL_H:
+    case Keyboard::KEY_CAPITAL_I:
+    case Keyboard::KEY_CAPITAL_J:
+    case Keyboard::KEY_CAPITAL_K:
+    case Keyboard::KEY_CAPITAL_L:
+    case Keyboard::KEY_CAPITAL_M:
+    case Keyboard::KEY_CAPITAL_N:
+    case Keyboard::KEY_CAPITAL_O:
+    case Keyboard::KEY_CAPITAL_P:
+    case Keyboard::KEY_CAPITAL_Q:
+    case Keyboard::KEY_CAPITAL_R:
+    case Keyboard::KEY_CAPITAL_S:
+    case Keyboard::KEY_CAPITAL_T:
+    case Keyboard::KEY_CAPITAL_U:
+    case Keyboard::KEY_CAPITAL_V:
+    case Keyboard::KEY_CAPITAL_W:
+    case Keyboard::KEY_CAPITAL_X:
+    case Keyboard::KEY_CAPITAL_Y:
+    case Keyboard::KEY_CAPITAL_Z:
+    case Keyboard::KEY_LEFT_BRACKET:
+    case Keyboard::KEY_BACK_SLASH:
+    case Keyboard::KEY_RIGHT_BRACKET:
+    case Keyboard::KEY_UNDERSCORE:
+    case Keyboard::KEY_GRAVE:
+    case Keyboard::KEY_A:
+    case Keyboard::KEY_B:
+    case Keyboard::KEY_C:
+    case Keyboard::KEY_D:
+    case Keyboard::KEY_E:
+    case Keyboard::KEY_F:
+    case Keyboard::KEY_G:
+    case Keyboard::KEY_H:
+    case Keyboard::KEY_I:
+    case Keyboard::KEY_J:
+    case Keyboard::KEY_K:
+    case Keyboard::KEY_L:
+    case Keyboard::KEY_M:
+    case Keyboard::KEY_N:
+    case Keyboard::KEY_O:
+    case Keyboard::KEY_P:
+    case Keyboard::KEY_Q:
+    case Keyboard::KEY_R:
+    case Keyboard::KEY_S:
+    case Keyboard::KEY_T:
+    case Keyboard::KEY_U:
+    case Keyboard::KEY_V:
+    case Keyboard::KEY_W:
+    case Keyboard::KEY_X:
+    case Keyboard::KEY_Y:
+    case Keyboard::KEY_Z:
+    case Keyboard::KEY_LEFT_BRACE:
+    case Keyboard::KEY_BAR:
+    case Keyboard::KEY_RIGHT_BRACE:
+    case Keyboard::KEY_TILDE:
+        return key;
+    default:
+        return 0;
+    }
+}
+
 extern void print(const char* format, ...)
 extern void print(const char* format, ...)
 {
 {
     GP_ASSERT(format);
     GP_ASSERT(format);
@@ -380,19 +502,52 @@ Platform* Platform::create(Game* game, void* attachToWindow)
     __attachToWindow = (Window)attachToWindow;
     __attachToWindow = (Window)attachToWindow;
     FileSystem::setResourcePath("./");
     FileSystem::setResourcePath("./");
     Platform* platform = new Platform(game);
     Platform* platform = new Platform(game);
-
-    // Get the display and initialize.
+    
+    // Get the display and initialize
     __display = XOpenDisplay(NULL);
     __display = XOpenDisplay(NULL);
     if (__display == NULL)
     if (__display == NULL)
     {
     {
         perror("XOpenDisplay");
         perror("XOpenDisplay");
         return NULL;
         return NULL;
     }
     }
+     
+    // Get the window configuration values
+    const char *title = NULL;
+    int __x = 0, __y = 0, __width = 1280, __height = 800;
+    bool fullscreen = false;
+    if (game->getConfig())
+    {
+        Properties* config = game->getConfig()->getNamespace("window", true);
+        if (config)
+        {
+            // Read window title.
+            title = config->getString("title");
+
+            // Read window rect.
+            int x = config->getInt("x");
+            int y = config->getInt("y");
+            int width = config->getInt("width");
+            int height = config->getInt("height");
+            fullscreen = config->getBool("fullscreen");
+
+            if (fullscreen && width == 0 && height == 0)
+            {
+                // Use the screen resolution if fullscreen is true but width and height were not set in the config
+                int screen_num = DefaultScreen(__display);
+                width = DisplayWidth(__display, screen_num);
+                height = DisplayHeight(__display, screen_num);
+            }
+            if (x != 0) __x = x;
+            if (y != 0) __y = y;
+            if (width != 0) __width = width;
+            if (height != 0) __height = height;
+        }
+    }
 
 
     // GLX version
     // GLX version
     GLint majorGLX, minorGLX = 0;
     GLint majorGLX, minorGLX = 0;
     glXQueryVersion(__display, &majorGLX, &minorGLX);
     glXQueryVersion(__display, &majorGLX, &minorGLX);
-    if(majorGLX == 1 && minorGLX < 2)
+    if (majorGLX == 1 && minorGLX < 2)
     {
     {
         perror("GLX 1.2 or greater is required.");
         perror("GLX 1.2 or greater is required.");
         XCloseDisplay(__display);
         XCloseDisplay(__display);
@@ -411,25 +566,25 @@ Platform* Platform::create(Game* game, void* attachToWindow)
 
 
     // Get the configs
     // Get the configs
     int configAttribs[] = 
     int configAttribs[] = 
-    { 
+    {
         GLX_RENDER_TYPE,    GLX_RGBA_BIT,
         GLX_RENDER_TYPE,    GLX_RGBA_BIT,
         GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,
         GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,
         GLX_X_RENDERABLE,   True,
         GLX_X_RENDERABLE,   True,
-        GLX_DEPTH_SIZE,     24, 
+        GLX_DEPTH_SIZE,     24,
         GLX_STENCIL_SIZE,   8,
         GLX_STENCIL_SIZE,   8,
         GLX_RED_SIZE,       8,
         GLX_RED_SIZE,       8,
         GLX_GREEN_SIZE,     8,
         GLX_GREEN_SIZE,     8,
         GLX_BLUE_SIZE,      8,
         GLX_BLUE_SIZE,      8,
         GLX_DOUBLEBUFFER,   True,
         GLX_DOUBLEBUFFER,   True,
-        0 
+        0
     };
     };
     GLXFBConfig* configs;
     GLXFBConfig* configs;
     int configCount = 0;
     int configCount = 0;
     configs = glXChooseFBConfig(__display, DefaultScreen(__display), configAttribs, &configCount);
     configs = glXChooseFBConfig(__display, DefaultScreen(__display), configAttribs, &configCount);
-    if( configCount == 0 || configs == 0 )    
-    {    
+    if ( configCount == 0 || configs == 0 )
+    {
         perror( "glXChooseFBConfig" );
         perror( "glXChooseFBConfig" );
-        return NULL;    
+        return NULL;
     }
     }
 
 
     // Create the windows
     // Create the windows
@@ -439,8 +594,8 @@ Platform* Platform::create(Game* game, void* attachToWindow)
     XSetWindowAttributes winAttribs;
     XSetWindowAttributes winAttribs;
     long eventMask;
     long eventMask;
     eventMask = ExposureMask | VisibilityChangeMask | StructureNotifyMask |
     eventMask = ExposureMask | VisibilityChangeMask | StructureNotifyMask |
-                KeyPressMask | KeyReleaseMask | PointerMotionMask | 
-                ButtonPressMask | ButtonReleaseMask | 
+                KeyPressMask | KeyReleaseMask | PointerMotionMask |
+                ButtonPressMask | ButtonReleaseMask |
                 EnterWindowMask | LeaveWindowMask;
                 EnterWindowMask | LeaveWindowMask;
     winAttribs.event_mask = eventMask;
     winAttribs.event_mask = eventMask;
     winAttribs.border_pixel = 0;
     winAttribs.border_pixel = 0;
@@ -450,15 +605,40 @@ Platform* Platform::create(Game* game, void* attachToWindow)
     GLint winMask;
     GLint winMask;
     winMask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
     winMask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
    
    
-    __window = XCreateWindow(__display, DefaultRootWindow(__display), 0, 0, 1280, 720, 0, 
+    __window = XCreateWindow(__display, DefaultRootWindow(__display), __x, __y, __width, __height, 0,
                             visualInfo->depth, InputOutput, visualInfo->visual, winMask,
                             visualInfo->depth, InputOutput, visualInfo->visual, winMask,
-                            &winAttribs); 
-    
+                            &winAttribs);
+
+    // Tell the window manager that it should send the delete window notification through ClientMessage
+    __atomWmDeleteWindow = XInternAtom(__display, "WM_DELETE_WINDOW", False);
+    XSetWMProtocols(__display, __window, &__atomWmDeleteWindow, 1);
+
     XMapWindow(__display, __window);
     XMapWindow(__display, __window);
-    XStoreName(__display, __window, "");
+
+    // Send fullscreen atom message to the window; most window managers respect WM_STATE messages
+    // Note: fullscreen mode will use native desktop resolution and won't care about width/height specified
+    if (fullscreen)
+    {
+        XEvent xev;
+        Atom atomWm_state = XInternAtom(__display, "_NET_WM_STATE", False);
+        Atom atomFullscreen = XInternAtom(__display, "_NET_WM_STATE_FULLSCREEN", False);
+
+        memset(&xev, 0, sizeof(xev));
+        xev.type = ClientMessage;
+        xev.xclient.window = __window;
+        xev.xclient.message_type = atomWm_state;
+        xev.xclient.format = 32;
+        xev.xclient.data.l[0] = 1;
+        xev.xclient.data.l[1] = atomFullscreen;
+        xev.xclient.data.l[2] = 0;
+
+        XSendEvent(__display, DefaultRootWindow(__display), false, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
+    }
+    
+    XStoreName(__display, __window, title ? title : "");
 
 
     __context = glXCreateContext(__display, visualInfo, NULL, True);
     __context = glXCreateContext(__display, visualInfo, NULL, True);
-    if(!__context)
+    if (!__context)
     {
     {
         perror("glXCreateContext");
         perror("glXCreateContext");
         return NULL;
         return NULL;
@@ -468,7 +648,7 @@ Platform* Platform::create(Game* game, void* attachToWindow)
     // Use OpenGL 2.x with GLEW
     // Use OpenGL 2.x with GLEW
     glewExperimental = GL_TRUE;
     glewExperimental = GL_TRUE;
     GLenum glewStatus = glewInit();
     GLenum glewStatus = glewInit();
-    if(glewStatus != GLEW_OK)
+    if (glewStatus != GLEW_OK)
     {
     {
         perror("glewInit");
         perror("glewInit");
         return NULL;
         return NULL;
@@ -508,14 +688,14 @@ double timespec2millis(struct timespec *a)
     return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
     return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
 }
 }
 
 
-void updateWindowSize()    
-{    
-    GP_ASSERT(__display);    
+void updateWindowSize()
+{
+    GP_ASSERT(__display);
     GP_ASSERT(__window);
     GP_ASSERT(__window);
-    XWindowAttributes windowAttrs;    
-    XGetWindowAttributes(__display, __window, &windowAttrs);      
-    __windowSize[0] = windowAttrs.width;    
-    __windowSize[1] = windowAttrs.height;    
+    XWindowAttributes windowAttrs;
+    XGetWindowAttributes(__display, __window, &windowAttrs);
+    __windowSize[0] = windowAttrs.width;
+    __windowSize[1] = windowAttrs.height;
 }
 }
 
 
 int Platform::enterMessagePump()
 int Platform::enterMessagePump()
@@ -540,7 +720,7 @@ int Platform::enterMessagePump()
     // Run the game.
     // Run the game.
     _game->run();
     _game->run();
 
 
-    // Setup select for message handling (to allow non-blocking)    
+    // Setup select for message handling (to allow non-blocking)
     int x11_fd = ConnectionNumber(__display);
     int x11_fd = ConnectionNumber(__display);
     
     
     pollfd xpolls[1];
     pollfd xpolls[1];
@@ -550,15 +730,23 @@ int Platform::enterMessagePump()
     // Message loop.
     // Message loop.
     while (true)
     while (true)
     {
     {
-        int ret = poll( xpolls, 1, 16 );
-
-        // handle all pending events in one block 
-        while (ret && XPending(__display))
+        poll( xpolls, 1, 16 );
+        // handle all pending events in one block
+        while (XPending(__display))
         {
         {
            XNextEvent(__display, &evt);
            XNextEvent(__display, &evt);
         
         
-            switch (evt.type) 
+            switch (evt.type)
             {
             {
+            case ClientMessage:
+                {
+                    // Handle destroy window message correctly
+                    if (evt.xclient.data.l[0] == __atomWmDeleteWindow)
+                    {
+                        _game->exit();
+                    }
+                }
+                break;
             case DestroyNotify :
             case DestroyNotify :
                 {
                 {
                     cleanupX11();
                     cleanupX11();
@@ -566,7 +754,7 @@ int Platform::enterMessagePump()
                 }
                 }
                 break;
                 break;
 
 
-            case Expose: 
+            case Expose:
                 {
                 {
                     updateWindowSize();
                     updateWindowSize();
                 }
                 }
@@ -574,9 +762,25 @@ int Platform::enterMessagePump()
 
 
             case KeyPress:
             case KeyPress:
                 {
                 {
-                    KeySym sym = XLookupKeysym(&evt.xkey, 0);
+                    KeySym sym = XLookupKeysym(&evt.xkey, (evt.xkey.state & shiftDown) ? 1 : 0);
+
+
+                    //TempSym needed because XConvertCase operates on two keysyms: One lower and the other upper, we are only interested in the upper case
+                    KeySym tempSym;
+                    if (capsOn && !shiftDown)
+                        XConvertCase(sym,  &tempSym, &sym);
+
                     Keyboard::Key key = getKey(sym);
                     Keyboard::Key key = getKey(sym);
                     gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, key);
                     gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, key);
+
+                    if (key == Keyboard::KEY_CAPS_LOCK)
+                        capsOn = !capsOn;
+                    if (key == Keyboard::KEY_SHIFT)
+                        shiftDown = true;
+
+                    if (int character = getUnicode(key))
+                        gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, character);
+
                 }
                 }
                 break;
                 break;
 
 
@@ -584,10 +788,10 @@ int Platform::enterMessagePump()
                 {
                 {
                     //detect and drop repeating keystrokes (no other way to do this using the event interface)
                     //detect and drop repeating keystrokes (no other way to do this using the event interface)
                     XEvent next;
                     XEvent next;
-                    if( XPending(__display) )
+                    if ( XPending(__display) )
                     {
                     {
                         XPeekEvent(__display,&next);
                         XPeekEvent(__display,&next);
-                        if( next.type == KeyPress 
+                        if ( next.type == KeyPress
                             && next.xkey.time == evt.xkey.time
                             && next.xkey.time == evt.xkey.time
                             && next.xkey.keycode == evt.xkey.keycode )
                             && next.xkey.keycode == evt.xkey.keycode )
                         {
                         {
@@ -599,13 +803,16 @@ int Platform::enterMessagePump()
                     KeySym sym = XLookupKeysym(&evt.xkey, 0);
                     KeySym sym = XLookupKeysym(&evt.xkey, 0);
                     Keyboard::Key key = getKey(sym);
                     Keyboard::Key key = getKey(sym);
                     gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, key);
                     gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, key);
+
+                    if (key == Keyboard::KEY_SHIFT)
+                        shiftDown = false;
                 }
                 }
                 break;
                 break;
 
 
             case ButtonPress:
             case ButtonPress:
                 {
                 {
                     gameplay::Mouse::MouseEvent mouseEvt;
                     gameplay::Mouse::MouseEvent mouseEvt;
-                    switch(evt.xbutton.button)
+                    switch (evt.xbutton.button)
                     {
                     {
                         case 1:
                         case 1:
                             mouseEvt = gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON;
                             mouseEvt = gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON;
@@ -618,8 +825,8 @@ int Platform::enterMessagePump()
                             break;
                             break;
                         case 4:
                         case 4:
                         case 5:
                         case 5:
-                            gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL, 
-                                                                   evt.xbutton.x, evt.xbutton.y, 
+                            gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL,
+                                                                   evt.xbutton.x, evt.xbutton.y,
                                                                    evt.xbutton.button == Button4 ? 1 : -1);
                                                                    evt.xbutton.button == Button4 ? 1 : -1);
                             break;
                             break;
                         default:
                         default:
@@ -635,7 +842,7 @@ int Platform::enterMessagePump()
             case ButtonRelease:
             case ButtonRelease:
                 {
                 {
                     gameplay::Mouse::MouseEvent mouseEvt;
                     gameplay::Mouse::MouseEvent mouseEvt;
-                    switch(evt.xbutton.button)
+                    switch (evt.xbutton.button)
                     {
                     {
                         case 1:
                         case 1:
                             mouseEvt = gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON;
                             mouseEvt = gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON;
@@ -658,25 +865,45 @@ int Platform::enterMessagePump()
         
         
             case MotionNotify:
             case MotionNotify:
                 {
                 {
-                    if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, evt.xmotion.x, evt.xmotion.y, 0))
+                    int x = evt.xmotion.x;
+                    int y = evt.xmotion.y;
+
+                    if (__mouseCaptured)
+                    {
+                        if (x == __mouseCapturePointX && y == __mouseCapturePointY)
+                        {
+                            // Discard the first MotionNotify following capture
+                            // since it contains bogus x,y data.
+                            break;
+                        }
+
+                        // Convert to deltas
+                        x -= __mouseCapturePointX;
+                        y -= __mouseCapturePointY;
+
+                        // Warp mouse back to center of screen.
+                        XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+                    }
+
+                    if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, x, y, 0))
                     {
                     {
                         if (evt.xmotion.state & Button1Mask)
                         if (evt.xmotion.state & Button1Mask)
                         {
                         {
-                            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, evt.xmotion.x, evt.xmotion.y, 0);
+                            gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, x, y, 0);
                         }
                         }
                         else if (evt.xmotion.state & Button3Mask)
                         else if (evt.xmotion.state & Button3Mask)
                         {
                         {
                             // Update the pitch and roll by adding the scaled deltas.
                             // Update the pitch and roll by adding the scaled deltas.
-                            __roll += (float)(evt.xbutton.x - lx) * ACCELEROMETER_X_FACTOR;
-                            __pitch += -(float)(evt.xbutton.y - ly) * ACCELEROMETER_Y_FACTOR;
+                            __roll += (float)(x - lx) * ACCELEROMETER_X_FACTOR;
+                            __pitch += -(float)(y - ly) * ACCELEROMETER_Y_FACTOR;
 
 
                             // Clamp the values to the valid range.
                             // Clamp the values to the valid range.
                             __roll = max(min(__roll, 90.0f), -90.0f);
                             __roll = max(min(__roll, 90.0f), -90.0f);
                             __pitch = max(min(__pitch, 90.0f), -90.0f);
                             __pitch = max(min(__pitch, 90.0f), -90.0f);
 
 
                             // Update the last X/Y values.
                             // Update the last X/Y values.
-                            lx = evt.xbutton.x;
-                            ly = evt.xbutton.y;
+                            lx = x;
+                            ly = y;
                         }
                         }
                     }
                     }
                 }
                 }
@@ -688,7 +915,13 @@ int Platform::enterMessagePump()
         }
         }
 
 
         if (_game)
         if (_game)
+        {
+            // Game state will be uninitialized if game was closed through Game::exit()
+            if (_game->getState() == Game::UNINITIALIZED)
+                break;
+            
             _game->frame();
             _game->frame();
+        }
 
 
         glXSwapBuffers(__display, __window);
         glXSwapBuffers(__display, __window);
     }
     }
@@ -698,15 +931,15 @@ int Platform::enterMessagePump()
     return 0;
     return 0;
 }
 }
     
     
-void Platform::signalShutdown() 
-{ 
+void Platform::signalShutdown()
+{
     // nothing to do  
     // nothing to do  
 }
 }
-
-bool Platform::canExit()
-{
-    return true;
-}
+
+bool Platform::canExit()
+{
+    return true;
+}
     
     
 unsigned int Platform::getDisplayWidth()
 unsigned int Platform::getDisplayWidth()
 {
 {
@@ -782,13 +1015,31 @@ bool Platform::hasMouse()
 
 
 void Platform::setMouseCaptured(bool captured)
 void Platform::setMouseCaptured(bool captured)
 {
 {
-    // TODO
+    if (captured != __mouseCaptured)
+    {
+        if (captured)
+        {
+            // Hide the cursor and warp it to the center of the screen
+            __mouseCapturePointX = getDisplayWidth() / 2;
+            __mouseCapturePointY = getDisplayHeight() / 2;
+
+            setCursorVisible(false);
+            XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+        }
+        else
+        {
+            // Restore cursor
+            XWarpPointer(__display, None, __window, 0, 0, 0, 0, __mouseCapturePointX, __mouseCapturePointY);
+            setCursorVisible(true);
+        }
+
+        __mouseCaptured = captured;
+    }
 }
 }
 
 
 bool Platform::isMouseCaptured()
 bool Platform::isMouseCaptured()
 {
 {
-    // TODO
-    return false;
+    return __mouseCaptured;
 }
 }
 
 
 void Platform::setCursorVisible(bool visible)
 void Platform::setCursorVisible(bool visible)
@@ -797,7 +1048,17 @@ void Platform::setCursorVisible(bool visible)
     {
     {
         if (visible)
         if (visible)
         {
         {
-            XDefineCursor(__display, __window, None);
+            Cursor invisibleCursor;
+            Pixmap bitmapNoData;
+            XColor black;
+            static char noData[] = {0, 0, 0, 0, 0, 0, 0, 0};
+            black.red = black.green = black.blue = 0;
+            bitmapNoData = XCreateBitmapFromData(__display, __window, noData, 8, 8);
+            invisibleCursor = XCreatePixmapCursor(__display, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
+
+            XDefineCursor(__display, __window, invisibleCursor);
+            XFreeCursor(__display, invisibleCursor);
+            XFreePixmap(__display, bitmapNoData);
         }
         }
         else
         else
         {
         {
@@ -929,6 +1190,21 @@ float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int
     return 0.0f;
     return 0.0f;
 }
 }
 
 
+bool Platform::launchURL(const char* url)
+{
+    if (url == NULL || *url == '\0')
+        return false;
+
+    int len = strlen(url);
+    
+    char* cmd = new char[11 + len];
+    sprintf(cmd, "xdg-open %s", url);
+    int r = system(cmd);
+    SAFE_DELETE_ARRAY(cmd);
+    
+    return (r == 0);
+}
+
 }
 }
 
 
 #endif
 #endif

+ 205 - 39
gameplay/src/PlatformMacOSX.mm

@@ -48,6 +48,7 @@ static char* __title = NULL;
 static bool __fullscreen = false;
 static bool __fullscreen = false;
 static void* __attachToWindow = NULL;
 static void* __attachToWindow = NULL;
 static bool __mouseCaptured = false;
 static bool __mouseCaptured = false;
+static bool __mouseCapturedFirstPass = false;
 static CGPoint __mouseCapturePoint;
 static CGPoint __mouseCapturePoint;
 static bool __cursorVisible = true;
 static bool __cursorVisible = true;
 static View* __view = NULL;
 static View* __view = NULL;
@@ -582,7 +583,7 @@ double getMachTimeInMilliseconds()
 - (void)hidValueAvailable:(IOHIDValueRef)value
 - (void)hidValueAvailable:(IOHIDValueRef)value
 {
 {
     IOHIDElementRef element = IOHIDValueGetElement(value);
     IOHIDElementRef element = IOHIDValueGetElement(value);
-	IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
+    IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
     
     
     if(IOHIDValueGetLength(value) > 4) return; // saftey precaution for PS3 cotroller
     if(IOHIDValueGetLength(value) > 4) return; // saftey precaution for PS3 cotroller
     CFIndex integerValue = IOHIDValueGetIntegerValue(value);
     CFIndex integerValue = IOHIDValueGetIntegerValue(value);
@@ -848,8 +849,17 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 {
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     
     
+    float y;
     if (__mouseCaptured)
     if (__mouseCaptured)
     {
     {
+        if (__mouseCapturedFirstPass)
+        {
+            // Discard the first mouseMoved event following transition into capture
+            // since it contains bogus x,y data.
+            __mouseCapturedFirstPass = false;
+            return;
+        }
+
         point.x = [event deltaX];
         point.x = [event deltaX];
         point.y = [event deltaY];
         point.y = [event deltaY];
 
 
@@ -859,9 +869,14 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
         centerPoint.x = rect.origin.x + (rect.size.width / 2);
         centerPoint.x = rect.origin.x + (rect.size.width / 2);
         centerPoint.y = rect.origin.y + (rect.size.height / 2);
         centerPoint.y = rect.origin.y + (rect.size.height / 2);
         CGDisplayMoveCursorToPoint(CGDisplayPrimaryDisplay(NULL), centerPoint);
         CGDisplayMoveCursorToPoint(CGDisplayPrimaryDisplay(NULL), centerPoint);
+        y = point.y;
+    }
+    else
+    {
+        y = __height - point.y;
     }
     }
     
     
-    gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, __height - point.y, 0);
+    gameplay::Platform::mouseEventInternal(Mouse::MOUSE_MOVE, point.x, y, 0);
 }
 }
 
 
 - (void) mouseDragged: (NSEvent*) event
 - (void) mouseDragged: (NSEvent*) event
@@ -961,6 +976,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 int getKey(unsigned short keyCode, unsigned int modifierFlags)
 int getKey(unsigned short keyCode, unsigned int modifierFlags)
 {
 {
     __shiftDown = (modifierFlags & NSShiftKeyMask);
     __shiftDown = (modifierFlags & NSShiftKeyMask);
+    unsigned int caps = (__shiftDown ? 1 : 0) ^ ((modifierFlags & NSAlphaShiftKeyMask) ? 1 : 0);
     switch(keyCode)
     switch(keyCode)
     {
     {
         case 0x69:
         case 0x69:
@@ -1098,63 +1114,181 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
             return __shiftDown ? Keyboard::KEY_QUOTE : Keyboard::KEY_APOSTROPHE;
             return __shiftDown ? Keyboard::KEY_QUOTE : Keyboard::KEY_APOSTROPHE;
             
             
         case 0x00:
         case 0x00:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_A : Keyboard::KEY_A;
+            return caps ? Keyboard::KEY_CAPITAL_A : Keyboard::KEY_A;
         case 0x0B:
         case 0x0B:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_B : Keyboard::KEY_B;
+            return caps ? Keyboard::KEY_CAPITAL_B : Keyboard::KEY_B;
         case 0x08:
         case 0x08:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_C : Keyboard::KEY_C;
+            return caps ? Keyboard::KEY_CAPITAL_C : Keyboard::KEY_C;
         case 0x02:
         case 0x02:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_D : Keyboard::KEY_D;
+            return caps ? Keyboard::KEY_CAPITAL_D : Keyboard::KEY_D;
         case 0x0E:
         case 0x0E:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_E : Keyboard::KEY_E;
+            return caps ? Keyboard::KEY_CAPITAL_E : Keyboard::KEY_E;
         case 0x03:
         case 0x03:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_F : Keyboard::KEY_F;
+            return caps ? Keyboard::KEY_CAPITAL_F : Keyboard::KEY_F;
         case 0x05:
         case 0x05:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_G : Keyboard::KEY_G;
+            return caps ? Keyboard::KEY_CAPITAL_G : Keyboard::KEY_G;
         case 0x04:
         case 0x04:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_H : Keyboard::KEY_H;
+            return caps ? Keyboard::KEY_CAPITAL_H : Keyboard::KEY_H;
         case 0x22:
         case 0x22:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_I : Keyboard::KEY_I;
+            return caps ? Keyboard::KEY_CAPITAL_I : Keyboard::KEY_I;
         case 0x26:
         case 0x26:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_J : Keyboard::KEY_J;
+            return caps ? Keyboard::KEY_CAPITAL_J : Keyboard::KEY_J;
         case 0x28:
         case 0x28:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_K : Keyboard::KEY_K;
+            return caps ? Keyboard::KEY_CAPITAL_K : Keyboard::KEY_K;
         case 0x25:
         case 0x25:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_L : Keyboard::KEY_L;
+            return caps ? Keyboard::KEY_CAPITAL_L : Keyboard::KEY_L;
         case 0x2E:
         case 0x2E:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_M : Keyboard::KEY_M;
+            return caps ? Keyboard::KEY_CAPITAL_M : Keyboard::KEY_M;
         case 0x2D:
         case 0x2D:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_N : Keyboard::KEY_N;
+            return caps ? Keyboard::KEY_CAPITAL_N : Keyboard::KEY_N;
         case 0x1F:
         case 0x1F:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_O : Keyboard::KEY_O;
+            return caps ? Keyboard::KEY_CAPITAL_O : Keyboard::KEY_O;
         case 0x23:
         case 0x23:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_P : Keyboard::KEY_P;
+            return caps ? Keyboard::KEY_CAPITAL_P : Keyboard::KEY_P;
         case 0x0C:
         case 0x0C:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_Q : Keyboard::KEY_Q;
+            return caps ? Keyboard::KEY_CAPITAL_Q : Keyboard::KEY_Q;
         case 0x0F:
         case 0x0F:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_R : Keyboard::KEY_R;
+            return caps ? Keyboard::KEY_CAPITAL_R : Keyboard::KEY_R;
         case 0x01:
         case 0x01:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_S : Keyboard::KEY_S;
+            return caps ? Keyboard::KEY_CAPITAL_S : Keyboard::KEY_S;
         case 0x11:
         case 0x11:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_T : Keyboard::KEY_T;
+            return caps ? Keyboard::KEY_CAPITAL_T : Keyboard::KEY_T;
         case 0x20:
         case 0x20:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_U : Keyboard::KEY_U;
+            return caps ? Keyboard::KEY_CAPITAL_U : Keyboard::KEY_U;
         case 0x09:
         case 0x09:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_V : Keyboard::KEY_V;
+            return caps ? Keyboard::KEY_CAPITAL_V : Keyboard::KEY_V;
         case 0x0D:
         case 0x0D:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_W : Keyboard::KEY_W;
+            return caps ? Keyboard::KEY_CAPITAL_W : Keyboard::KEY_W;
         case 0x07:
         case 0x07:
-             return __shiftDown ? Keyboard::KEY_CAPITAL_X : Keyboard::KEY_X;
+            return caps ? Keyboard::KEY_CAPITAL_X : Keyboard::KEY_X;
         case 0x10:
         case 0x10:
-            return __shiftDown ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
+            return caps ? Keyboard::KEY_CAPITAL_Y : Keyboard::KEY_Y;
         case 0x06:
         case 0x06:
-            return __shiftDown ? Keyboard::KEY_CAPITAL_Z : Keyboard::KEY_Z;
+            return caps ? Keyboard::KEY_CAPITAL_Z : Keyboard::KEY_Z;
 
 
         default:
         default:
             return Keyboard::KEY_NONE;
             return Keyboard::KEY_NONE;
     }
     }
 }
 }
 
 
+/**
+ * Returns the unicode value for the given keycode or zero if the key is not a valid printable character.
+ */
+int getUnicode(int key)
+{
+    
+    switch (key)
+    {
+        case Keyboard::KEY_BACKSPACE:
+            return 0x0008;
+        case Keyboard::KEY_TAB:
+            return 0x0009;
+        case Keyboard::KEY_RETURN:
+        case Keyboard::KEY_KP_ENTER:
+            return 0x000A;
+        case Keyboard::KEY_ESCAPE:
+            return 0x001B;
+        case Keyboard::KEY_SPACE:
+        case Keyboard::KEY_EXCLAM:
+        case Keyboard::KEY_QUOTE:
+        case Keyboard::KEY_NUMBER:
+        case Keyboard::KEY_DOLLAR:
+        case Keyboard::KEY_PERCENT:
+        case Keyboard::KEY_CIRCUMFLEX:
+        case Keyboard::KEY_AMPERSAND:
+        case Keyboard::KEY_APOSTROPHE:
+        case Keyboard::KEY_LEFT_PARENTHESIS:
+        case Keyboard::KEY_RIGHT_PARENTHESIS:
+        case Keyboard::KEY_ASTERISK:
+        case Keyboard::KEY_PLUS:
+        case Keyboard::KEY_COMMA:
+        case Keyboard::KEY_MINUS:
+        case Keyboard::KEY_PERIOD:
+        case Keyboard::KEY_SLASH:
+        case Keyboard::KEY_ZERO:
+        case Keyboard::KEY_ONE:
+        case Keyboard::KEY_TWO:
+        case Keyboard::KEY_THREE:
+        case Keyboard::KEY_FOUR:
+        case Keyboard::KEY_FIVE:
+        case Keyboard::KEY_SIX:
+        case Keyboard::KEY_SEVEN:
+        case Keyboard::KEY_EIGHT:
+        case Keyboard::KEY_NINE:
+        case Keyboard::KEY_COLON:
+        case Keyboard::KEY_SEMICOLON:
+        case Keyboard::KEY_LESS_THAN:
+        case Keyboard::KEY_EQUAL:
+        case Keyboard::KEY_GREATER_THAN:
+        case Keyboard::KEY_QUESTION:
+        case Keyboard::KEY_AT:
+        case Keyboard::KEY_CAPITAL_A:
+        case Keyboard::KEY_CAPITAL_B:
+        case Keyboard::KEY_CAPITAL_C:
+        case Keyboard::KEY_CAPITAL_D:
+        case Keyboard::KEY_CAPITAL_E:
+        case Keyboard::KEY_CAPITAL_F:
+        case Keyboard::KEY_CAPITAL_G:
+        case Keyboard::KEY_CAPITAL_H:
+        case Keyboard::KEY_CAPITAL_I:
+        case Keyboard::KEY_CAPITAL_J:
+        case Keyboard::KEY_CAPITAL_K:
+        case Keyboard::KEY_CAPITAL_L:
+        case Keyboard::KEY_CAPITAL_M:
+        case Keyboard::KEY_CAPITAL_N:
+        case Keyboard::KEY_CAPITAL_O:
+        case Keyboard::KEY_CAPITAL_P:
+        case Keyboard::KEY_CAPITAL_Q:
+        case Keyboard::KEY_CAPITAL_R:
+        case Keyboard::KEY_CAPITAL_S:
+        case Keyboard::KEY_CAPITAL_T:
+        case Keyboard::KEY_CAPITAL_U:
+        case Keyboard::KEY_CAPITAL_V:
+        case Keyboard::KEY_CAPITAL_W:
+        case Keyboard::KEY_CAPITAL_X:
+        case Keyboard::KEY_CAPITAL_Y:
+        case Keyboard::KEY_CAPITAL_Z:
+        case Keyboard::KEY_LEFT_BRACKET:
+        case Keyboard::KEY_BACK_SLASH:
+        case Keyboard::KEY_RIGHT_BRACKET:
+        case Keyboard::KEY_UNDERSCORE:
+        case Keyboard::KEY_GRAVE:
+        case Keyboard::KEY_A:
+        case Keyboard::KEY_B:
+        case Keyboard::KEY_C:
+        case Keyboard::KEY_D:
+        case Keyboard::KEY_E:
+        case Keyboard::KEY_F:
+        case Keyboard::KEY_G:
+        case Keyboard::KEY_H:
+        case Keyboard::KEY_I:
+        case Keyboard::KEY_J:
+        case Keyboard::KEY_K:
+        case Keyboard::KEY_L:
+        case Keyboard::KEY_M:
+        case Keyboard::KEY_N:
+        case Keyboard::KEY_O:
+        case Keyboard::KEY_P:
+        case Keyboard::KEY_Q:
+        case Keyboard::KEY_R:
+        case Keyboard::KEY_S:
+        case Keyboard::KEY_T:
+        case Keyboard::KEY_U:
+        case Keyboard::KEY_V:
+        case Keyboard::KEY_W:
+        case Keyboard::KEY_X:
+        case Keyboard::KEY_Y:
+        case Keyboard::KEY_Z:
+        case Keyboard::KEY_LEFT_BRACE:
+        case Keyboard::KEY_BAR:
+        case Keyboard::KEY_RIGHT_BRACE:
+        case Keyboard::KEY_TILDE:
+            return key;
+        default:
+            return 0;
+    }
+}
+
 - (void)flagsChanged: (NSEvent*)event
 - (void)flagsChanged: (NSEvent*)event
 {
 {
     unsigned int keyCode = [event keyCode];
     unsigned int keyCode = [event keyCode];
@@ -1195,7 +1329,14 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
 {
 {
     if ([event isARepeat] == NO)
     if ([event isARepeat] == NO)
     {
     {
-        gameplay::Platform::keyEventInternal(Keyboard::KEY_PRESS, getKey([event keyCode], [event modifierFlags]));
+        int key = getKey([event keyCode], [event modifierFlags]);
+        gameplay::Platform::keyEventInternal(Keyboard::KEY_PRESS, key);
+        
+        int character = getUnicode(key);
+        if (character)
+        {
+            gameplay::Platform::keyEventInternal(Keyboard::KEY_CHAR, character);
+        }
     }
     }
 }
 }
 
 
@@ -1335,6 +1476,12 @@ int Platform::enterMessagePump()
 
 
             // Read fullscreen state.
             // Read fullscreen state.
             __fullscreen = config->getBool("fullscreen");
             __fullscreen = config->getBool("fullscreen");
+            if (__fullscreen && width == 0 && height == 0)
+            {
+                CGRect mainMonitor = CGDisplayBounds(CGMainDisplayID());
+                __width = CGRectGetWidth(mainMonitor);
+                __height = CGRectGetHeight(mainMonitor);
+            }
         }
         }
     }
     }
 
 
@@ -1477,6 +1624,7 @@ void Platform::setMouseCaptured(bool captured)
         if (captured)
         if (captured)
         {
         {
             [NSCursor hide];
             [NSCursor hide];
+            __mouseCapturedFirstPass = true;
         }
         }
         else
         else
         {   
         {   
@@ -1816,25 +1964,25 @@ CFMutableDictionaryRef IOHIDCreateDeviceMatchingDictionary(UInt32 inUsagePage, U
 
 
 CFStringRef IOHIDDeviceGetStringProperty(IOHIDDeviceRef deviceRef, CFStringRef key) 
 CFStringRef IOHIDDeviceGetStringProperty(IOHIDDeviceRef deviceRef, CFStringRef key) 
 {
 {
-	CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
-	if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) 
+    CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
+    if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) 
     {
     {
-		return NULL;
-	}
+        return NULL;
+    }
     return (CFStringRef)typeRef;
     return (CFStringRef)typeRef;
 }
 }
 
 
 int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key) 
 int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key) 
 {
 {
-	CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
-	if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) 
+    CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
+    if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) 
     {
     {
-		return 0;
-	}
+        return 0;
+    }
     
     
     int value;
     int value;
-	CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
-	return value;
+    CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
+    return value;
 }
 }
 
 
 static void hidDeviceDiscoveredCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) 
 static void hidDeviceDiscoveredCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) 
@@ -1881,4 +2029,22 @@ static void hidDeviceValueAvailableCallback(void* inContext, IOReturn inResult,
         CFRelease(valueRef); // Don't forget to release our HID value reference
         CFRelease(valueRef); // Don't forget to release our HID value reference
     } while (1);
     } while (1);
 }
 }
+
+bool Platform::launchURL(const char *url)
+{
+    if (url == NULL || *url == '\0')
+        return false;
+
+    CFURLRef urlRef = CFURLCreateWithBytes(
+        NULL,
+        (UInt8*)url,
+        strlen(url),
+        kCFStringEncodingASCII,
+        NULL
+    );
+    const OSStatus err = LSOpenCFURLRef(urlRef, 0);
+    CFRelease(urlRef);
+    return (err == noErr);
+}
+
 #endif
 #endif

+ 44 - 12
gameplay/src/PlatformWindows.cpp

@@ -9,6 +9,7 @@
 #include "ScriptController.h"
 #include "ScriptController.h"
 #include <GL/wglew.h>
 #include <GL/wglew.h>
 #include <windowsx.h>
 #include <windowsx.h>
+#include <shellapi.h>
 #ifdef USE_XINPUT
 #ifdef USE_XINPUT
 #include <XInput.h>
 #include <XInput.h>
 #endif
 #endif
@@ -404,7 +405,7 @@ static gameplay::Keyboard::Key getKey(WPARAM win32KeyCode, bool shiftDown)
     }
     }
 }
 }
 
 
-void UpdateCapture(LPARAM lParam)
+static void UpdateCapture(LPARAM lParam)
 {
 {
     if ((lParam & MK_LBUTTON) || (lParam & MK_MBUTTON) || (lParam & MK_RBUTTON))
     if ((lParam & MK_LBUTTON) || (lParam & MK_MBUTTON) || (lParam & MK_RBUTTON))
         SetCapture(__hwnd);
         SetCapture(__hwnd);
@@ -412,13 +413,27 @@ void UpdateCapture(LPARAM lParam)
         ReleaseCapture();
         ReleaseCapture();
 }
 }
 
 
-void WarpMouse(int clientX, int clientY)
+static void WarpMouse(int clientX, int clientY)
 {
 {
     POINT p = { clientX, clientY };
     POINT p = { clientX, clientY };
     ClientToScreen(__hwnd, &p);
     ClientToScreen(__hwnd, &p);
     SetCursorPos(p.x, p.y);
     SetCursorPos(p.x, p.y);
 }
 }
 
 
+
+/**
+ * Gets the width and height of the screen in pixels.
+ */
+static void getDesktopResolution(int& width, int& height)
+{
+   RECT desktop;
+   const HWND hDesktop = GetDesktopWindow();
+   // Get the size of screen to the variable desktop
+   GetWindowRect(hDesktop, &desktop);
+   width = desktop.right;
+   height = desktop.bottom;
+}
+
 LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
 {
     static gameplay::Game* game = gameplay::Game::getInstance();
     static gameplay::Game* game = gameplay::Game::getInstance();
@@ -871,6 +886,11 @@ Platform* Platform::create(Game* game, void* attachToWindow)
                 SAFE_DELETE_ARRAY(wtitle);
                 SAFE_DELETE_ARRAY(wtitle);
             }
             }
 
 
+            // Read fullscreen state.
+            params.fullscreen = config->getBool("fullscreen");
+            // Read multisampling state.
+            params.samples = config->getInt("samples");
+
             // Read window rect.
             // Read window rect.
             int x = config->getInt("x");
             int x = config->getInt("x");
             if (x != 0)
             if (x != 0)
@@ -879,17 +899,15 @@ Platform* Platform::create(Game* game, void* attachToWindow)
             if (y != 0)
             if (y != 0)
                 params.rect.top = y;
                 params.rect.top = y;
             int width = config->getInt("width");
             int width = config->getInt("width");
+            int height = config->getInt("height");
+
+            if (width == 0 && height == 0 && params.fullscreen)
+                getDesktopResolution(width, height);
+
             if (width != 0)
             if (width != 0)
                 params.rect.right = params.rect.left + width;
                 params.rect.right = params.rect.left + width;
-            int height = config->getInt("height");
             if (height != 0)
             if (height != 0)
                 params.rect.bottom = params.rect.top + height;
                 params.rect.bottom = params.rect.top + height;
-
-            // Read fullscreen state.
-            params.fullscreen = config->getBool("fullscreen");
-
-            // Read multisampling state.
-            params.samples = config->getInt("samples");
         }
         }
     }
     }
 
 
@@ -960,9 +978,9 @@ Platform* Platform::create(Game* game, void* attachToWindow)
             DEVMODE dm;
             DEVMODE dm;
             memset(&dm, 0, sizeof(dm));
             memset(&dm, 0, sizeof(dm));
             dm.dmSize= sizeof(dm);
             dm.dmSize= sizeof(dm);
-            dm.dmPelsWidth	= width;
-            dm.dmPelsHeight	= height;
-            dm.dmBitsPerPel	= DEFAULT_COLOR_BUFFER_SIZE;
+            dm.dmPelsWidth  = width;
+            dm.dmPelsHeight = height;
+            dm.dmBitsPerPel = DEFAULT_COLOR_BUFFER_SIZE;
             dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
             dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
 
 
             // Try to set selected mode and get results. NOTE: CDS_FULLSCREEN gets rid of start bar.
             // Try to set selected mode and get results. NOTE: CDS_FULLSCREEN gets rid of start bar.
@@ -1454,6 +1472,20 @@ bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheel
     }
     }
 }
 }
 
 
+bool Platform::launchURL(const char* url)
+{
+    if (url == NULL || *url == '\0')
+        return false;
+ 
+    // Success when result code > 32
+    int len = MultiByteToWideChar(CP_ACP, 0, url, -1, NULL, 0);
+    wchar_t* wurl = new wchar_t[len];
+    MultiByteToWideChar(CP_ACP, 0, url, -1, wurl, len);
+    int r = (int)ShellExecute(NULL, NULL, wurl, NULL, NULL, SW_SHOWNORMAL);
+    SAFE_DELETE_ARRAY(wurl);
+    return (r > 32);
+}
+
 }
 }
 
 
 #endif
 #endif

+ 141 - 2
gameplay/src/PlatformiOS.mm

@@ -48,6 +48,7 @@ static float __roll;
 double getMachTimeInMilliseconds();
 double getMachTimeInMilliseconds();
 
 
 int getKey(unichar keyCode);
 int getKey(unichar keyCode);
+int getUnicode(int key);
 
 
 @interface View : UIView <UIKeyInput>
 @interface View : UIView <UIKeyInput>
 {
 {
@@ -482,13 +483,21 @@ int getKey(unichar keyCode);
     assert([text length] == 1);
     assert([text length] == 1);
     unichar c = [text characterAtIndex:0];
     unichar c = [text characterAtIndex:0];
     int key = getKey(c);
     int key = getKey(c);
-    Platform::keyEventInternal(Keyboard::KEY_PRESS, key);    
-    Platform::keyEventInternal(Keyboard::KEY_RELEASE, key);    
+    Platform::keyEventInternal(Keyboard::KEY_PRESS, key);
+
+    int character = getUnicode(key);
+    if (character)
+    {
+        Platform::keyEventInternal(Keyboard::KEY_CHAR, /*character*/c);
+    }
+    
+    Platform::keyEventInternal(Keyboard::KEY_RELEASE, key);
 }
 }
 
 
 - (void)deleteBackward 
 - (void)deleteBackward 
 {
 {
     Platform::keyEventInternal(Keyboard::KEY_PRESS, Keyboard::KEY_BACKSPACE);    
     Platform::keyEventInternal(Keyboard::KEY_PRESS, Keyboard::KEY_BACKSPACE);    
+    Platform::keyEventInternal(Keyboard::KEY_CHAR, getUnicode(Keyboard::KEY_BACKSPACE));
     Platform::keyEventInternal(Keyboard::KEY_RELEASE, Keyboard::KEY_BACKSPACE);    
     Platform::keyEventInternal(Keyboard::KEY_RELEASE, Keyboard::KEY_BACKSPACE);    
 }
 }
 
 
@@ -845,6 +854,11 @@ int getKey(unichar keyCode)
 {
 {
     switch(keyCode) 
     switch(keyCode) 
     {
     {
+        case 0x0A:
+            return Keyboard::KEY_RETURN;
+        case 0x20:
+            return Keyboard::KEY_SPACE;
+            
         case 0x30:
         case 0x30:
             return Keyboard::KEY_ZERO;
             return Keyboard::KEY_ZERO;
         case 0x31:
         case 0x31:
@@ -1056,6 +1070,123 @@ int getKey(unichar keyCode)
     return Keyboard::KEY_NONE;
     return Keyboard::KEY_NONE;
 }
 }
 
 
+/**
+ * Returns the unicode value for the given keycode or zero if the key is not a valid printable character.
+ */
+int getUnicode(int key)
+{
+    
+    switch (key)
+    {
+        case Keyboard::KEY_BACKSPACE:
+            return 0x0008;
+        case Keyboard::KEY_TAB:
+            return 0x0009;
+        case Keyboard::KEY_RETURN:
+        case Keyboard::KEY_KP_ENTER:
+            return 0x000A;
+        case Keyboard::KEY_ESCAPE:
+            return 0x001B;
+        case Keyboard::KEY_SPACE:
+        case Keyboard::KEY_EXCLAM:
+        case Keyboard::KEY_QUOTE:
+        case Keyboard::KEY_NUMBER:
+        case Keyboard::KEY_DOLLAR:
+        case Keyboard::KEY_PERCENT:
+        case Keyboard::KEY_CIRCUMFLEX:
+        case Keyboard::KEY_AMPERSAND:
+        case Keyboard::KEY_APOSTROPHE:
+        case Keyboard::KEY_LEFT_PARENTHESIS:
+        case Keyboard::KEY_RIGHT_PARENTHESIS:
+        case Keyboard::KEY_ASTERISK:
+        case Keyboard::KEY_PLUS:
+        case Keyboard::KEY_COMMA:
+        case Keyboard::KEY_MINUS:
+        case Keyboard::KEY_PERIOD:
+        case Keyboard::KEY_SLASH:
+        case Keyboard::KEY_ZERO:
+        case Keyboard::KEY_ONE:
+        case Keyboard::KEY_TWO:
+        case Keyboard::KEY_THREE:
+        case Keyboard::KEY_FOUR:
+        case Keyboard::KEY_FIVE:
+        case Keyboard::KEY_SIX:
+        case Keyboard::KEY_SEVEN:
+        case Keyboard::KEY_EIGHT:
+        case Keyboard::KEY_NINE:
+        case Keyboard::KEY_COLON:
+        case Keyboard::KEY_SEMICOLON:
+        case Keyboard::KEY_LESS_THAN:
+        case Keyboard::KEY_EQUAL:
+        case Keyboard::KEY_GREATER_THAN:
+        case Keyboard::KEY_QUESTION:
+        case Keyboard::KEY_AT:
+        case Keyboard::KEY_CAPITAL_A:
+        case Keyboard::KEY_CAPITAL_B:
+        case Keyboard::KEY_CAPITAL_C:
+        case Keyboard::KEY_CAPITAL_D:
+        case Keyboard::KEY_CAPITAL_E:
+        case Keyboard::KEY_CAPITAL_F:
+        case Keyboard::KEY_CAPITAL_G:
+        case Keyboard::KEY_CAPITAL_H:
+        case Keyboard::KEY_CAPITAL_I:
+        case Keyboard::KEY_CAPITAL_J:
+        case Keyboard::KEY_CAPITAL_K:
+        case Keyboard::KEY_CAPITAL_L:
+        case Keyboard::KEY_CAPITAL_M:
+        case Keyboard::KEY_CAPITAL_N:
+        case Keyboard::KEY_CAPITAL_O:
+        case Keyboard::KEY_CAPITAL_P:
+        case Keyboard::KEY_CAPITAL_Q:
+        case Keyboard::KEY_CAPITAL_R:
+        case Keyboard::KEY_CAPITAL_S:
+        case Keyboard::KEY_CAPITAL_T:
+        case Keyboard::KEY_CAPITAL_U:
+        case Keyboard::KEY_CAPITAL_V:
+        case Keyboard::KEY_CAPITAL_W:
+        case Keyboard::KEY_CAPITAL_X:
+        case Keyboard::KEY_CAPITAL_Y:
+        case Keyboard::KEY_CAPITAL_Z:
+        case Keyboard::KEY_LEFT_BRACKET:
+        case Keyboard::KEY_BACK_SLASH:
+        case Keyboard::KEY_RIGHT_BRACKET:
+        case Keyboard::KEY_UNDERSCORE:
+        case Keyboard::KEY_GRAVE:
+        case Keyboard::KEY_A:
+        case Keyboard::KEY_B:
+        case Keyboard::KEY_C:
+        case Keyboard::KEY_D:
+        case Keyboard::KEY_E:
+        case Keyboard::KEY_F:
+        case Keyboard::KEY_G:
+        case Keyboard::KEY_H:
+        case Keyboard::KEY_I:
+        case Keyboard::KEY_J:
+        case Keyboard::KEY_K:
+        case Keyboard::KEY_L:
+        case Keyboard::KEY_M:
+        case Keyboard::KEY_N:
+        case Keyboard::KEY_O:
+        case Keyboard::KEY_P:
+        case Keyboard::KEY_Q:
+        case Keyboard::KEY_R:
+        case Keyboard::KEY_S:
+        case Keyboard::KEY_T:
+        case Keyboard::KEY_U:
+        case Keyboard::KEY_V:
+        case Keyboard::KEY_W:
+        case Keyboard::KEY_X:
+        case Keyboard::KEY_Y:
+        case Keyboard::KEY_Z:
+        case Keyboard::KEY_LEFT_BRACE:
+        case Keyboard::KEY_BAR:
+        case Keyboard::KEY_RIGHT_BRACE:
+        case Keyboard::KEY_TILDE:
+            return key;
+        default:
+            return 0;
+    }
+}
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -1319,6 +1450,14 @@ float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int
 {
 {
     return 0.0f;
     return 0.0f;
 }
 }
+
+bool Platform::launchURL(const char *url)
+{
+    if (url == NULL || *url == '\0')
+        return false;
+
+    return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithUTF8String: url]]];
+}
     
     
 }
 }
 
 

+ 48 - 35
gameplay/src/Properties.cpp

@@ -6,6 +6,19 @@
 namespace gameplay
 namespace gameplay
 {
 {
 
 
+/**
+ * Reads the next character from the stream. Returns EOF if the end of the stream is reached.
+ */
+static signed char readChar(Stream* stream)
+{
+    if (stream->eof())
+        return EOF;
+    signed char c;
+    if (stream->read(&c, 1, 1) != 1)
+        return EOF;
+    return c;
+}
+
 // Utility functions (shared with SceneLoader).
 // Utility functions (shared with SceneLoader).
 /** @script{ignore} */
 /** @script{ignore} */
 void calculateNamespacePath(const std::string& urlString, std::string& fileString, std::vector<std::string>& namespacePath);
 void calculateNamespacePath(const std::string& urlString, std::string& fileString, std::vector<std::string>& namespacePath);
@@ -29,13 +42,14 @@ Properties::Properties(const Properties& copy)
     rewind();
     rewind();
 }
 }
 
 
-Properties::Properties(FILE* file)
+
+Properties::Properties(Stream* stream)
 {
 {
-    readProperties(file);
+    readProperties(stream);
     rewind();
     rewind();
 }
 }
 
 
-Properties::Properties(FILE* file, const char* name, const char* id, const char* parentID) : _namespace(name)
+Properties::Properties(Stream* stream, const char* name, const char* id, const char* parentID) : _namespace(name)
 {
 {
     if (id)
     if (id)
     {
     {
@@ -45,7 +59,7 @@ Properties::Properties(FILE* file, const char* name, const char* id, const char*
     {
     {
         _parentID = parentID;
         _parentID = parentID;
     }
     }
-    readProperties(file);
+    readProperties(stream);
     rewind();
     rewind();
 }
 }
 
 
@@ -63,16 +77,16 @@ Properties* Properties::create(const char* url)
     std::vector<std::string> namespacePath;
     std::vector<std::string> namespacePath;
     calculateNamespacePath(urlString, fileString, namespacePath);
     calculateNamespacePath(urlString, fileString, namespacePath);
 
 
-    FILE* file = FileSystem::openFile(fileString.c_str(), "rb");
-    if (!file)
+    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_ERROR("Failed to open file '%s'.", fileString.c_str());
         return NULL;
         return NULL;
     }
     }
 
 
-    Properties* properties = new Properties(file);
+    Properties* properties = new Properties(stream.get());
     properties->resolveInheritance();
     properties->resolveInheritance();
-    fclose(file);
+    stream->close();
 
 
     // Get the specified properties object.
     // Get the specified properties object.
     Properties* p = getPropertiesFromNamespacePath(properties, namespacePath);
     Properties* p = getPropertiesFromNamespacePath(properties, namespacePath);
@@ -93,9 +107,9 @@ Properties* Properties::create(const char* url)
     return p;
     return p;
 }
 }
 
 
-void Properties::readProperties(FILE* file)
+void Properties::readProperties(Stream* stream)
 {
 {
-    GP_ASSERT(file);
+    GP_ASSERT(stream);
 
 
     char line[2048];
     char line[2048];
     int c;
     int c;
@@ -108,14 +122,14 @@ void Properties::readProperties(FILE* file)
 
 
     while (true)
     while (true)
     {
     {
-        skipWhiteSpace(file);
+        skipWhiteSpace(stream);
 
 
         // Stop when we have reached the end of the file.
         // Stop when we have reached the end of the file.
-        if (feof(file))
+        if (stream->eof())
             break;
             break;
 
 
         // Read the next line.
         // Read the next line.
-        rc = fgets(line, 2048, file);
+        rc = stream->readLine(line, 2048);
         if (rc == NULL)
         if (rc == NULL)
         {
         {
             GP_ERROR("Error reading line from file.");
             GP_ERROR("Error reading line from file.");
@@ -213,20 +227,20 @@ void Properties::readProperties(FILE* file)
                     // If the namespace ends on this line, seek back to right before the '}' character.
                     // If the namespace ends on this line, seek back to right before the '}' character.
                     if (rccc && rccc == lineEnd)
                     if (rccc && rccc == lineEnd)
                     {
                     {
-                        if (fseek(file, -1, SEEK_CUR) != 0)
+                        if (stream->seek(-1, SEEK_CUR) == false)
                         {
                         {
                             GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                             GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                             return;
                             return;
                         }
                         }
-                        while (fgetc(file) != '}')
+                        while (readChar(stream) != '}')
                         {
                         {
-                            if (fseek(file, -2, SEEK_CUR) != 0)
+                            if (stream->seek(-2, SEEK_CUR) == false)
                             {
                             {
                                 GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                 GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                 return;
                                 return;
                             }
                             }
                         }
                         }
-                        if (fseek(file, -1, SEEK_CUR) != 0)
+                        if (stream->seek(-1, SEEK_CUR) == false)
                         {
                         {
                             GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                             GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                             return;
                             return;
@@ -234,13 +248,13 @@ void Properties::readProperties(FILE* file)
                     }
                     }
 
 
                     // New namespace without an ID.
                     // New namespace without an ID.
-                    Properties* space = new Properties(file, name, NULL, parentID);
+                    Properties* space = new Properties(stream, name, NULL, parentID);
                     _namespaces.push_back(space);
                     _namespaces.push_back(space);
 
 
                     // If the namespace ends on this line, seek to right after the '}' character.
                     // If the namespace ends on this line, seek to right after the '}' character.
                     if (rccc && rccc == lineEnd)
                     if (rccc && rccc == lineEnd)
                     {
                     {
-                        if (fseek(file, 1, SEEK_CUR) != 0)
+                        if (stream->seek(1, SEEK_CUR) == false)
                         {
                         {
                             GP_ERROR("Failed to seek to immediately after a '}' character in properties file.");
                             GP_ERROR("Failed to seek to immediately after a '}' character in properties file.");
                             return;
                             return;
@@ -255,20 +269,20 @@ void Properties::readProperties(FILE* file)
                         // If the namespace ends on this line, seek back to right before the '}' character.
                         // If the namespace ends on this line, seek back to right before the '}' character.
                         if (rccc && rccc == lineEnd)
                         if (rccc && rccc == lineEnd)
                         {
                         {
-                            if (fseek(file, -1, SEEK_CUR) != 0)
+                            if (stream->seek(-1, SEEK_CUR) == false)
                             {
                             {
                                 GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                 GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                 return;
                                 return;
                             }
                             }
-                            while (fgetc(file) != '}')
+                            while (readChar(stream) != '}')
                             {
                             {
-                                if (fseek(file, -2, SEEK_CUR) != 0)
+                                if (stream->seek(-2, SEEK_CUR) == false)
                                 {
                                 {
                                     GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                     GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                     return;
                                     return;
                                 }
                                 }
                             }
                             }
-                            if (fseek(file, -1, SEEK_CUR) != 0)
+                            if (stream->seek(-1, SEEK_CUR) == false)
                             {
                             {
                                 GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                 GP_ERROR("Failed to seek back to before a '}' character in properties file.");
                                 return;
                                 return;
@@ -276,13 +290,13 @@ void Properties::readProperties(FILE* file)
                         }
                         }
 
 
                         // Create new namespace.
                         // Create new namespace.
-                        Properties* space = new Properties(file, name, value, parentID);
+                        Properties* space = new Properties(stream, name, value, parentID);
                         _namespaces.push_back(space);
                         _namespaces.push_back(space);
 
 
                         // If the namespace ends on this line, seek to right after the '}' character.
                         // If the namespace ends on this line, seek to right after the '}' character.
                         if (rccc && rccc == lineEnd)
                         if (rccc && rccc == lineEnd)
                         {
                         {
-                            if (fseek(file, 1, SEEK_CUR) != 0)
+                            if (stream->seek(1, SEEK_CUR) == false)
                             {
                             {
                                 GP_ERROR("Failed to seek to immediately after a '}' character in properties file.");
                                 GP_ERROR("Failed to seek to immediately after a '}' character in properties file.");
                                 return;
                                 return;
@@ -292,18 +306,18 @@ void Properties::readProperties(FILE* file)
                     else
                     else
                     {
                     {
                         // Find out if the next line starts with "{"
                         // Find out if the next line starts with "{"
-                        skipWhiteSpace(file);
-                        c = fgetc(file);
+                        skipWhiteSpace(stream);
+                        c = readChar(stream);
                         if (c == '{')
                         if (c == '{')
                         {
                         {
                             // Create new namespace.
                             // Create new namespace.
-                            Properties* space = new Properties(file, name, value, parentID);
+                            Properties* space = new Properties(stream, name, value, parentID);
                             _namespaces.push_back(space);
                             _namespaces.push_back(space);
                         }
                         }
                         else
                         else
                         {
                         {
                             // Back up from fgetc()
                             // Back up from fgetc()
-                            if (fseek(file, -1, SEEK_CUR) != 0)
+                            if (stream->seek(-1, SEEK_CUR) == false)
                                 GP_ERROR("Failed to seek backwards a single character after testing if the next line starts with '{'.");
                                 GP_ERROR("Failed to seek backwards a single character after testing if the next line starts with '{'.");
 
 
                             // Store "name value" as a name/value pair, or even just "name".
                             // Store "name value" as a name/value pair, or even just "name".
@@ -331,20 +345,19 @@ Properties::~Properties()
     }
     }
 }
 }
 
 
-void Properties::skipWhiteSpace(FILE* file)
+void Properties::skipWhiteSpace(Stream* stream)
 {
 {
-    int c;
-
+    signed char c;
     do
     do
     {
     {
-        c = fgetc(file);
-    } while (isspace(c));
+        c = readChar(stream);
+    } while (isspace(c) && c != EOF);
 
 
     // If we are not at the end of the file, then since we found a
     // If we are not at the end of the file, then since we found a
     // non-whitespace character, we put the cursor back in front of it.
     // non-whitespace character, we put the cursor back in front of it.
     if (c != EOF)
     if (c != EOF)
     {
     {
-        if (fseek(file, -1, SEEK_CUR) != 0)
+        if (stream->seek(-1, SEEK_CUR) == false)
         {
         {
             GP_ERROR("Failed to seek backwards one character after skipping whitespace.");
             GP_ERROR("Failed to seek backwards one character after skipping whitespace.");
         }
         }

+ 5 - 4
gameplay/src/Properties.h

@@ -4,6 +4,7 @@
 #include "Base.h"
 #include "Base.h"
 #include "Matrix.h"
 #include "Matrix.h"
 #include "Vector2.h"
 #include "Vector2.h"
+#include "Stream.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -383,17 +384,17 @@ private:
      * Constructors.
      * Constructors.
      */
      */
     Properties();
     Properties();
-    Properties(FILE* file);
+    Properties(Stream* stream);
     Properties(const Properties& copy);
     Properties(const Properties& copy);
 
 
     /**
     /**
      * Constructor. Read from the beginning of namespace specified
      * Constructor. Read from the beginning of namespace specified
      */
      */
-    Properties(FILE* file, const char* name, const char* id = NULL, const char* parentID = NULL);
+    Properties(Stream* stream, const char* name, const char* id = NULL, const char* parentID = NULL);
 
 
-    void readProperties(FILE* file);
+    void readProperties(Stream* stream);
 
 
-    void skipWhiteSpace(FILE* file);
+    void skipWhiteSpace(Stream* stream);
 
 
     char* trimWhiteSpace(char* str);
     char* trimWhiteSpace(char* str);
 
 

+ 5 - 5
gameplay/src/RenderState.h

@@ -92,7 +92,7 @@ public:
      *
      *
      * Functions matching this callback signature can be registered via the 
      * Functions matching this callback signature can be registered via the 
      * RenderState::registerAutoBindingResolver method to extend or override the set
      * RenderState::registerAutoBindingResolver method to extend or override the set
-     * of built-in material paramter auto bindings.
+     * of built-in material parameter auto bindings.
      *
      *
      * @param autoBinding Name of the auto binding to resolve.
      * @param autoBinding Name of the auto binding to resolve.
      * @param node Node that is bound to the material of the specified parameter.
      * @param node Node that is bound to the material of the specified parameter.
@@ -309,11 +309,11 @@ public:
     /**
     /**
      * Registers a custom auto binding resolver.
      * Registers a custom auto binding resolver.
      *
      *
-     * Implementing a custom auto binding reolver allows the set of built-in parameter auto
+     * Implementing a custom auto binding resolver allows the set of built-in parameter auto
      * bindings to be extended or overridden. Any parameter auto binding that is set on a
      * bindings to be extended or overridden. Any parameter auto binding that is set on a
      * material will be forwarded to any custom auto binding resolvers, in the order in which
      * material will be forwarded to any custom auto binding resolvers, in the order in which
      * they are registered. If a registered resolver returns true (specifying that it handles
      * they are registered. If a registered resolver returns true (specifying that it handles
-     * the specified autoBinding), no further code will be exeucted for that autoBinding.
+     * the specified autoBinding), no further code will be executed for that autoBinding.
      * This allows auto binding resolvers to not only implement new/custom binding strings,
      * This allows auto binding resolvers to not only implement new/custom binding strings,
      * but it also lets them override existing/built-in ones. For this reason, you should
      * but it also lets them override existing/built-in ones. For this reason, you should
      * ensure that you ONLY return true if you explicitly handle a custom auto binding; return
      * ensure that you ONLY return true if you explicitly handle a custom auto binding; return
@@ -324,7 +324,7 @@ public:
      * Model that belongs to a Node. The resolver is NOT called each frame or each time
      * Model that belongs to a Node. The resolver is NOT called each frame or each time
      * the RenderState is bound. Therefore, when implementing custom auto bindings for values
      * the RenderState is bound. Therefore, when implementing custom auto bindings for values
      * that change over time, the you should bind a method pointer onto the passed in
      * that change over time, the you should bind a method pointer onto the passed in
-     * MaterialParaemter using the MaterialParameter::bindValue mehtod. This way, the bound 
+     * MaterialParaemter using the MaterialParameter::bindValue method. This way, the bound
      * method will be called each frame to set an updated value into the MaterialParameter.
      * method will be called each frame to set an updated value into the MaterialParameter.
      *
      *
      * If no registered resolvers explicitly handle an auto binding, the binding will attempt
      * If no registered resolvers explicitly handle an auto binding, the binding will attempt
@@ -436,7 +436,7 @@ protected:
     RenderState* _parent;
     RenderState* _parent;
 
 
     /**
     /**
-     * Map of custom auto binding resolverss.
+     * Map of custom auto binding resolvers.
      */
      */
     static std::vector<ResolveAutoBindingCallback> _customAutoBindingResolvers;
     static std::vector<ResolveAutoBindingCallback> _customAutoBindingResolvers;
 };
 };

+ 2 - 2
gameplay/src/Scene.h

@@ -74,7 +74,7 @@ public:
      * @param id The ID of the node to find.
      * @param id The ID of the node to find.
      * @param nodes Vector of nodes to be populated with matches.
      * @param nodes Vector of nodes to be populated with matches.
      * @param recursive true if a recursive search should be performed, false otherwise.
      * @param recursive true if a recursive search should be performed, false otherwise.
-     * @param exactMatch true if only nodes whos ID exactly matches the specified ID are returned,
+     * @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.
      *      or false if nodes that start with the given ID are returned.
      * 
      * 
      * @return The number of matches found.
      * @return The number of matches found.
@@ -212,7 +212,7 @@ public:
     /**
     /**
      * Draws debugging information (bounding volumes, etc.) for the scene.
      * Draws debugging information (bounding volumes, etc.) for the scene.
      *
      *
-     * @param debugFlags Bitwise combination of debug flags from mthe DebugFlags 
+     * @param debugFlags Bitwise combination of debug flags from the DebugFlags
      *        enumeration, specifying which debugging information to draw.
      *        enumeration, specifying which debugging information to draw.
      */
      */
     void drawDebug(unsigned int debugFlags);
     void drawDebug(unsigned int debugFlags);

+ 47 - 23
gameplay/src/ScriptController.cpp

@@ -372,76 +372,100 @@ std::string ScriptController::loadUrl(const char* url)
     return id;
     return id;
 }
 }
 
 
-bool ScriptController::getBool(const char* name)
+bool ScriptController::getBool(const char* name, bool defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return ScriptUtil::luaCheckBool(_lua, -1);
+    bool b = lua_isboolean(_lua, -1) ? ScriptUtil::luaCheckBool(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return b;
 }
 }
 
 
-char ScriptController::getChar(const char* name)
+char ScriptController::getChar(const char* name, char defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (char)luaL_checkint(_lua, -1);
+    char c = lua_isnumber(_lua, -1) ?  (char)luaL_checkint(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return c;
 }
 }
 
 
-short ScriptController::getShort(const char* name)
+short ScriptController::getShort(const char* name, short defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (short)luaL_checkint(_lua, -1);
+    short n = lua_isnumber(_lua, -1) ? (short)luaL_checkint(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
-int ScriptController::getInt(const char* name)
+int ScriptController::getInt(const char* name, int defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return luaL_checkint(_lua, -1);
+    int n = lua_isnumber(_lua, -1) ? luaL_checkint(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
-long ScriptController::getLong(const char* name)
+long ScriptController::getLong(const char* name, long defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return luaL_checklong(_lua, -1);
+    long n = lua_isnumber(_lua, -1) ? luaL_checklong(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
-unsigned char ScriptController::getUnsignedChar(const char* name)
+unsigned char ScriptController::getUnsignedChar(const char* name, unsigned char defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (unsigned char)luaL_checkunsigned(_lua, -1);
+    unsigned char c = lua_isnumber(_lua, -1) ? (unsigned char)luaL_checkunsigned(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return c;
 }
 }
 
 
-unsigned short ScriptController::getUnsignedShort(const char* name)
+unsigned short ScriptController::getUnsignedShort(const char* name, unsigned short defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (unsigned short)luaL_checkunsigned(_lua, -1);
+    unsigned short n = lua_isnumber(_lua, -1) ? (unsigned short)luaL_checkunsigned(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
-unsigned int ScriptController::getUnsignedInt(const char* name)
+unsigned int ScriptController::getUnsignedInt(const char* name, unsigned int defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (unsigned int)luaL_checkunsigned(_lua, -1);
+    unsigned int n = lua_isnumber(_lua, -1) ? (unsigned int)luaL_checkunsigned(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
-unsigned long ScriptController::getUnsignedLong(const char* name)
+unsigned long ScriptController::getUnsignedLong(const char* name, unsigned long defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (unsigned long)luaL_checkunsigned(_lua, -1);
+    unsigned long n = lua_isnumber(_lua, -1) ? (unsigned long)luaL_checkunsigned(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
-float ScriptController::getFloat(const char* name)
+float ScriptController::getFloat(const char* name, float defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (float)luaL_checknumber(_lua, -1);
+    float f = lua_isnumber(_lua, -1) ? (float)luaL_checknumber(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return f;
 }
 }
 
 
-double ScriptController::getDouble(const char* name)
+double ScriptController::getDouble(const char* name, double defaultValue)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return (double)luaL_checknumber(_lua, -1);
+    double n = lua_isnumber(_lua, -1) ? (double)luaL_checknumber(_lua, -1) : defaultValue;
+    lua_pop(_lua, 1);
+    return n;
 }
 }
 
 
 const char* ScriptController::getString(const char* name)
 const char* ScriptController::getString(const char* name)
 {
 {
     lua_getglobal(_lua, name);
     lua_getglobal(_lua, name);
-    return luaL_checkstring(_lua, -1);
+    const char* s = lua_isstring(_lua, -1) ? luaL_checkstring(_lua, -1) : NULL;
+    lua_pop(_lua, 1);
+    return s;
 }
 }
 
 
 void ScriptController::setBool(const char* name, bool v)
 void ScriptController::setBool(const char* name, bool v)

+ 107 - 17
gameplay/src/ScriptController.h

@@ -1,5 +1,5 @@
-#ifndef SCRIPTCONTROLLER_H
-#define SCRIPTCONTROLLER_H
+#ifndef SCRIPTCONTROLLER_H_
+#define SCRIPTCONTROLLER_H_
 
 
 #include "Base.h"
 #include "Base.h"
 #include "Game.h"
 #include "Game.h"
@@ -19,6 +19,7 @@ namespace ScriptUtil
 
 
 /**
 /**
  * Represents a C++ object from within Lua.
  * Represents a C++ object from within Lua.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 struct LuaObject
 struct LuaObject
@@ -32,6 +33,7 @@ struct LuaObject
 /**
 /**
  * Stores a Lua parameter of an array/pointer type that is passed from Lua to C.
  * Stores a Lua parameter of an array/pointer type that is passed from Lua to C.
  * Handles automatic cleanup of any temporary memory associated with the array.
  * Handles automatic cleanup of any temporary memory associated with the array.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 template <typename T>
 template <typename T>
@@ -55,7 +57,7 @@ public:
     LuaArray(int count);
     LuaArray(int count);
 
 
     /**
     /**
-     * Copy construcotr.
+     * Copy constructor.
      */
      */
     LuaArray(const LuaArray<T>& copy);
     LuaArray(const LuaArray<T>& copy);
 
 
@@ -102,6 +104,7 @@ private:
  * 
  * 
  * @param name The name of the library from within Lua.
  * @param name The name of the library from within Lua.
  * @param functions The library function mapping (Lua function names to C++ functions).
  * @param functions The library function mapping (Lua function names to C++ functions).
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void registerLibrary(const char* name, const luaL_Reg* functions);
 void registerLibrary(const char* name, const luaL_Reg* functions);
@@ -112,6 +115,7 @@ void registerLibrary(const char* name, const luaL_Reg* functions);
  * @param name The name of the constant (what the user would use from Lua).
  * @param name The name of the constant (what the user would use from Lua).
  * @param value The constant's value.
  * @param value The constant's value.
  * @param scopePath The list of containing classes, going inward from the most outer class.
  * @param scopePath The list of containing classes, going inward from the most outer class.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void registerConstantBool(const std::string& name, bool value, const std::vector<std::string>& scopePath);
 void registerConstantBool(const std::string& name, bool value, const std::vector<std::string>& scopePath);
@@ -122,6 +126,7 @@ void registerConstantBool(const std::string& name, bool value, const std::vector
  * @param name The name of the constant (what the user would use from Lua).
  * @param name The name of the constant (what the user would use from Lua).
  * @param value The constant's value.
  * @param value The constant's value.
  * @param scopePath The list of containing classes, going inward from the most outer class.
  * @param scopePath The list of containing classes, going inward from the most outer class.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void registerConstantNumber(const std::string& name, double value, const std::vector<std::string>& scopePath);
 void registerConstantNumber(const std::string& name, double value, const std::vector<std::string>& scopePath);
@@ -132,6 +137,7 @@ void registerConstantNumber(const std::string& name, double value, const std::ve
  * @param name The name of the constant (what the user would use from Lua).
  * @param name The name of the constant (what the user would use from Lua).
  * @param value The constant's value.
  * @param value The constant's value.
  * @param scopePath The list of containing classes, going inward from the most outer class.
  * @param scopePath The list of containing classes, going inward from the most outer class.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void registerConstantString(const std::string& name, const std::string& value, const std::vector<std::string>& scopePath);
 void registerConstantString(const std::string& name, const std::string& value, const std::vector<std::string>& scopePath);
@@ -145,6 +151,7 @@ void registerConstantString(const std::string& name, const std::string& value, c
  * @param deleteFunction The function to call that destroys an instance of the class.
  * @param deleteFunction The function to call that destroys an instance of the class.
  * @param statics The library function mapping for all the static functions (Lua function names to C++ functions).
  * @param statics The library function mapping for all the static functions (Lua function names to C++ functions).
  * @param scopePath For an inner class, this is a list of its containing classes, going inward from the most outer class.
  * @param scopePath For an inner class, this is a list of its containing classes, going inward from the most outer class.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void registerClass(const char* name, const luaL_Reg* members, lua_CFunction newFunction, lua_CFunction deleteFunction, const luaL_Reg* statics,
 void registerClass(const char* name, const luaL_Reg* members, lua_CFunction newFunction, lua_CFunction deleteFunction, const luaL_Reg* statics,
@@ -155,6 +162,7 @@ void registerClass(const char* name, const luaL_Reg* members, lua_CFunction newF
  * 
  * 
  * @param luaFunction The name of the function from within Lua.
  * @param luaFunction The name of the function from within Lua.
  * @param cppFunction The C++ function pointer.
  * @param cppFunction The C++ function pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void registerFunction(const char* luaFunction, lua_CFunction cppFunction);
 void registerFunction(const char* luaFunction, lua_CFunction cppFunction);
@@ -164,6 +172,7 @@ void registerFunction(const char* luaFunction, lua_CFunction cppFunction);
  * 
  * 
  * @param base The base class of the inheritance pair.
  * @param base The base class of the inheritance pair.
  * @param derived The derived class of the inheritance pair.
  * @param derived The derived class of the inheritance pair.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void setGlobalHierarchyPair(const std::string& base, const std::string& derived);
 void setGlobalHierarchyPair(const std::string& base, const std::string& derived);
@@ -172,6 +181,7 @@ void setGlobalHierarchyPair(const std::string& base, const std::string& derived)
  * Adds the given function as a string-from-enumerated value conversion function.
  * Adds the given function as a string-from-enumerated value conversion function.
  * 
  * 
  * @param stringFromEnum The pointer to the string-from-enum conversion function.
  * @param stringFromEnum The pointer to the string-from-enum conversion function.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 void addStringFromEnumConversionFunction(luaStringEnumConversionFunction stringFromEnum);
 void addStringFromEnumConversionFunction(luaStringEnumConversionFunction stringFromEnum);
@@ -180,7 +190,9 @@ void addStringFromEnumConversionFunction(luaStringEnumConversionFunction stringF
  * Gets a pointer to a bool (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to a bool (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<bool> getBoolPointer(int index);
 LuaArray<bool> getBoolPointer(int index);
@@ -189,7 +201,9 @@ LuaArray<bool> getBoolPointer(int index);
  * Gets a pointer to a short (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to a short (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<short> getShortPointer(int index);
 LuaArray<short> getShortPointer(int index);
@@ -198,7 +212,9 @@ LuaArray<short> getShortPointer(int index);
  * Gets a pointer to an int (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to an int (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<int> getIntPointer(int index);
 LuaArray<int> getIntPointer(int index);
@@ -207,7 +223,9 @@ LuaArray<int> getIntPointer(int index);
  * Gets a pointer to a long (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to a long (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<long> getLongPointer(int index);
 LuaArray<long> getLongPointer(int index);
@@ -216,7 +234,9 @@ LuaArray<long> getLongPointer(int index);
  * Gets a pointer to an unsigned char (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to an unsigned char (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<unsigned char> getUnsignedCharPointer(int index);
 LuaArray<unsigned char> getUnsignedCharPointer(int index);
@@ -225,7 +245,9 @@ LuaArray<unsigned char> getUnsignedCharPointer(int index);
  * Gets a pointer to an unsigned short (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to an unsigned short (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<unsigned short> getUnsignedShortPointer(int index);
 LuaArray<unsigned short> getUnsignedShortPointer(int index);
@@ -234,7 +256,9 @@ LuaArray<unsigned short> getUnsignedShortPointer(int index);
  * Gets a pointer to an unsigned int (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to an unsigned int (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<unsigned int> getUnsignedIntPointer(int index);
 LuaArray<unsigned int> getUnsignedIntPointer(int index);
@@ -243,7 +267,9 @@ LuaArray<unsigned int> getUnsignedIntPointer(int index);
  * Gets a pointer to an unsigned long (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to an unsigned long (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<unsigned long> getUnsignedLongPointer(int index);
 LuaArray<unsigned long> getUnsignedLongPointer(int index);
@@ -252,7 +278,9 @@ LuaArray<unsigned long> getUnsignedLongPointer(int index);
  * Gets a pointer to a float (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to a float (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<float> getFloatPointer(int index);
 LuaArray<float> getFloatPointer(int index);
@@ -261,7 +289,9 @@ LuaArray<float> getFloatPointer(int index);
  * Gets a pointer to a double (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * Gets a pointer to a double (as an array-use SAFE_DELETE_ARRAY to clean up) for the given stack index.
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
+ * 
  * @return The pointer.
  * @return The pointer.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 LuaArray<double> getDoublePointer(int index);
 LuaArray<double> getDoublePointer(int index);
@@ -275,8 +305,10 @@ LuaArray<double> getDoublePointer(int index);
  *      are retrieving is actually a reference or by-value parameter).
  *      are retrieving is actually a reference or by-value parameter).
  * @param success An out parameter that is set to true if the Lua parameter was successfully
  * @param success An out parameter that is set to true if the Lua parameter was successfully
  *      converted to a valid object, or false if it was unable to perform a valid conversion.
  *      converted to a valid object, or false if it was unable to perform a valid conversion.
+ * 
  * @return The object pointer or <code>NULL</code> if the data at the stack index
  * @return The object pointer or <code>NULL</code> if the data at the stack index
  *      is not an object or if the object is not derived from the given type.
  *      is not an object or if the object is not derived from the given type.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 template <typename T>
 template <typename T>
@@ -287,7 +319,9 @@ LuaArray<T> getObjectPointer(int index, const char* type, bool nonNull, bool* su
  * 
  * 
  * @param index The stack index.
  * @param index The stack index.
  * @param isStdString Whether the string being retrieved is a std::string object or not.
  * @param isStdString Whether the string being retrieved is a std::string object or not.
+ * 
  * @return The string or <code>NULL</code>.
  * @return The string or <code>NULL</code>.
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 const char* getString(int index, bool isStdString);
 const char* getString(int index, bool isStdString);
@@ -297,14 +331,15 @@ const char* getString(int index, bool isStdString);
  * 
  * 
  * @param state The Lua state.
  * @param state The Lua state.
  * @param n The stack index.
  * @param n The stack index.
+ * 
  * @return The boolean (if successful; otherwise it logs an error).
  * @return The boolean (if successful; otherwise it logs an error).
+ * 
  * @script{ignore}
  * @script{ignore}
  */
  */
 bool luaCheckBool(lua_State* state, int n);
 bool luaCheckBool(lua_State* state, int n);
 
 
 }
 }
 
 
-
 /**
 /**
  * Controls and manages all scripts.
  * Controls and manages all scripts.
  */
  */
@@ -326,6 +361,7 @@ public:
      * Given a URL, loads the referenced file and returns the referenced function name.
      * Given a URL, loads the referenced file and returns the referenced function name.
      * 
      * 
      * @param url The url to load.
      * @param url The url to load.
+     * 
      * @return The function that the URL references.
      * @return The function that the URL references.
      */
      */
     std::string loadUrl(const char* url);
     std::string loadUrl(const char* url);
@@ -334,6 +370,7 @@ public:
      * Calls the specified no-parameter Lua function.
      * Calls the specified no-parameter Lua function.
      * 
      * 
      * @param func The name of the function to call.
      * @param func The name of the function to call.
+     * 
      * @return The return value of the executed Lua function.
      * @return The return value of the executed Lua function.
      */
      */
     template<typename T> T executeFunction(const char* func);
     template<typename T> T executeFunction(const char* func);
@@ -358,6 +395,7 @@ public:
      *      - 'p' - pointer
      *      - 'p' - pointer
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
+     * 
      * @return The return value of the executed Lua function.
      * @return The return value of the executed Lua function.
      */
      */
     template<typename T> T executeFunction(const char* func, const char* args, ...);
     template<typename T> T executeFunction(const char* func, const char* args, ...);
@@ -383,6 +421,7 @@ public:
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '<object-type>' - a <b>pointer</b> to an object of the given type (where the qualified type name is enclosed by angle brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
      *      - '[enum-type]' - an enumerated value of the given type (where the qualified type name is enclosed by square brackets).
      * @param list The variable argument list containing the function's parameters.
      * @param list The variable argument list containing the function's parameters.
+     * 
      * @return The return value of the executed Lua function.
      * @return The return value of the executed Lua function.
      */
      */
     template<typename T> T executeFunction(const char* func, const char* args, va_list* list);
     template<typename T> T executeFunction(const char* func, const char* args, va_list* list);
@@ -391,106 +430,141 @@ public:
      * Gets the global boolean script variable with the given name.
      * Gets the global boolean script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a bool.
+     * 
      * @return The global boolean script variable.
      * @return The global boolean script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    bool getBool(const char* name);
+    bool getBool(const char* name, bool defaultValue = false);
 
 
     /**
     /**
      * Gets the global char script variable with the given name.
      * Gets the global char script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global char script variable.
      * @return The global char script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    char getChar(const char* name);
+    char getChar(const char* name, char defaultValue = 0);
 
 
     /**
     /**
      * Gets the global short script variable with the given name.
      * Gets the global short script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global short script variable.
      * @return The global short script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    short getShort(const char* name);
+    short getShort(const char* name, short defaultValue = 0);
 
 
     /**
     /**
      * Gets the global int script variable with the given name.
      * Gets the global int script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global int script variable.
      * @return The global int script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    int getInt(const char* name);
+    int getInt(const char* name, int defaultValue = 0);
 
 
     /**
     /**
      * Gets the global long script variable with the given name.
      * Gets the global long script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global long script variable.
      * @return The global long script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    long getLong(const char* name);
+    long getLong(const char* name, long defaultValue = 0);
 
 
     /**
     /**
      * Gets the global unsigned char script variable with the given name.
      * Gets the global unsigned char script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global unsigned char script variable.
      * @return The global unsigned char script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    unsigned char getUnsignedChar(const char* name);
+    unsigned char getUnsignedChar(const char* name, unsigned char defaultValue = 0);
 
 
     /**
     /**
      * Gets the global unsigned short script variable with the given name.
      * Gets the global unsigned short script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global unsigned short script variable.
      * @return The global unsigned short script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    unsigned short getUnsignedShort(const char* name);
+    unsigned short getUnsignedShort(const char* name, unsigned short defaultValue = 0);
 
 
     /**
     /**
      * Gets the global unsigned int script variable with the given name.
      * Gets the global unsigned int script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global unsigned int script variable.
      * @return The global unsigned int script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    unsigned int getUnsignedInt(const char* name);
+    unsigned int getUnsignedInt(const char* name, unsigned int defaultValue = 0);
 
 
     /**
     /**
      * Gets the global unsigned long script variable with the given name.
      * Gets the global unsigned long script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global unsigned long script variable.
      * @return The global unsigned long script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    unsigned long getUnsignedLong(const char* name);
+    unsigned long getUnsignedLong(const char* name, unsigned long defaultValue = 0);
 
 
     /**
     /**
      * Gets the global float script variable with the given name.
      * Gets the global float script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global float script variable.
      * @return The global float script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    float getFloat(const char* name);
+    float getFloat(const char* name, float defaultValue = 0);
 
 
     /**
     /**
      * Gets the global double script variable with the given name.
      * Gets the global double script variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * @param defaultValue The default value to return if the variable is not a number.
+     * 
      * @return The global double script variable.
      * @return The global double script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
-    double getDouble(const char* name);
+    double getDouble(const char* name, double defaultValue = 0);
 
 
     /**
     /**
-     * Gets the global string script variable with the given name.
+     * Gets the global string variable with the given name.
      * 
      * 
      * @param name The name of the variable.
      * @param name The name of the variable.
-     * @return The global string script variable.
+     * 
+     * @return The string variable or NULL if the variable is not a string.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     const char* getString(const char* name);
     const char* getString(const char* name);
@@ -500,7 +574,9 @@ public:
      * 
      * 
      * @param type The type of the variable in Lua.
      * @param type The type of the variable in Lua.
      * @param name The name of the variable.
      * @param name The name of the variable.
+     * 
      * @return The global pointer script variable.
      * @return The global pointer script variable.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     template<typename T>T* getObjectPointer(const char* type, const char* name);
     template<typename T>T* getObjectPointer(const char* type, const char* name);
@@ -510,6 +586,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The boolean value.
      * @param v The boolean value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setBool(const char* name, bool v);
     void setBool(const char* name, bool v);
@@ -519,6 +596,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The char value.
      * @param v The char value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setChar(const char* name, char v);
     void setChar(const char* name, char v);
@@ -528,6 +606,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The short value.
      * @param v The short value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setShort(const char* name, short v);
     void setShort(const char* name, short v);
@@ -537,6 +616,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The int value.
      * @param v The int value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setInt(const char* name, int v);
     void setInt(const char* name, int v);
@@ -546,6 +626,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The long value.
      * @param v The long value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setLong(const char* name, long v);
     void setLong(const char* name, long v);
@@ -555,6 +636,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The unsigned char value.
      * @param v The unsigned char value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setUnsignedChar(const char* name, unsigned char v);
     void setUnsignedChar(const char* name, unsigned char v);
@@ -564,6 +646,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The unsigned short value.
      * @param v The unsigned short value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setUnsignedShort(const char* name, unsigned short v);
     void setUnsignedShort(const char* name, unsigned short v);
@@ -573,6 +656,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The unsigned int value.
      * @param v The unsigned int value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setUnsignedInt(const char* name, unsigned int v);
     void setUnsignedInt(const char* name, unsigned int v);
@@ -582,6 +666,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The unsigned long value.
      * @param v The unsigned long value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setUnsignedLong(const char* name, unsigned long v);
     void setUnsignedLong(const char* name, unsigned long v);
@@ -591,6 +676,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The float value.
      * @param v The float value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setFloat(const char* name, float v);
     void setFloat(const char* name, float v);
@@ -600,6 +686,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The double value.
      * @param v The double value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setDouble(const char* name, double v);
     void setDouble(const char* name, double v);
@@ -609,6 +696,7 @@ public:
      * 
      * 
      * @param name The name of the script variable.
      * @param name The name of the script variable.
      * @param v The string value.
      * @param v The string value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     void setString(const char* name, const char* v);
     void setString(const char* name, const char* v);
@@ -619,6 +707,7 @@ public:
      * @param type The type of the script variable.
      * @param type The type of the script variable.
      * @param name The name of the variable.
      * @param name The name of the variable.
      * @param v The pointer value.
      * @param v The pointer value.
+     * 
      * @script{ignore}
      * @script{ignore}
      */
      */
     template<typename T>void setObjectPointer(const char* type, const char* name, T* v);
     template<typename T>void setObjectPointer(const char* type, const char* name, T* v);
@@ -790,6 +879,7 @@ private:
      * or to ScriptController::INVALID_CALLBACK if there is no valid conversion.
      * or to ScriptController::INVALID_CALLBACK if there is no valid conversion.
      * 
      * 
      * @param name The name of the callback.
      * @param name The name of the callback.
+     * 
      * @return The corresponding callback enumeration value.
      * @return The corresponding callback enumeration value.
      */
      */
     static ScriptController::ScriptCallback toCallback(const char* name);
     static ScriptController::ScriptCallback toCallback(const char* name);

+ 8 - 7
gameplay/src/SpriteBatch.cpp

@@ -73,12 +73,12 @@ SpriteBatch::~SpriteBatch()
 SpriteBatch* SpriteBatch::create(const char* texturePath, Effect* effect, unsigned int initialCapacity)
 SpriteBatch* SpriteBatch::create(const char* texturePath, Effect* effect, unsigned int initialCapacity)
 {
 {
     Texture* texture = Texture::create(texturePath);
     Texture* texture = Texture::create(texturePath);
-    SpriteBatch* batch = SpriteBatch::create(texture);
+    SpriteBatch* batch = SpriteBatch::create(texture, effect, initialCapacity);
     SAFE_RELEASE(texture);
     SAFE_RELEASE(texture);
     return batch;
     return batch;
 }
 }
 
 
-SpriteBatch* SpriteBatch::create(Texture* texture, Effect* effect, unsigned int initialCapacity)
+SpriteBatch* SpriteBatch::create(Texture* texture,  Effect* effect, unsigned int initialCapacity)
 {
 {
     GP_ASSERT(texture != NULL);
     GP_ASSERT(texture != NULL);
 
 
@@ -154,10 +154,11 @@ SpriteBatch* SpriteBatch::create(Texture* texture, Effect* effect, unsigned int
     batch->_textureWidthRatio = 1.0f / (float)texture->getWidth();
     batch->_textureWidthRatio = 1.0f / (float)texture->getWidth();
     batch->_textureHeightRatio = 1.0f / (float)texture->getHeight();
     batch->_textureHeightRatio = 1.0f / (float)texture->getHeight();
 
 
-    // Bind an ortho projection to the material by default (user can override with setProjectionMatrix)
-    Game* game = Game::getInstance();
-    Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &batch->_projectionMatrix);
-    material->getParameter("u_projectionMatrix")->bindValue(batch, &SpriteBatch::getProjectionMatrix);
+	// Bind an ortho projection to the material by default (user can override with setProjectionMatrix)
+	Game* game = Game::getInstance();
+	Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &batch->_projectionMatrix);
+	material->getParameter("u_projectionMatrix")->bindValue(batch, &SpriteBatch::getProjectionMatrix);
+	
     return batch;
     return batch;
 }
 }
 
 
@@ -185,7 +186,7 @@ void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2&
     float u2 = u1 + _textureWidthRatio * src.width;
     float u2 = u1 + _textureWidthRatio * src.width;
     float v2 = v1 - _textureHeightRatio * src.height;
     float v2 = v1 - _textureHeightRatio * src.height;
 
 
-    draw(dst.x, dst.y, dst.z, scale.x, scale.y, u2, v2, u1, v1, color);
+    draw(dst.x, dst.y, dst.z, scale.x, scale.y, u1, v1, u2, v2, color);
 }
 }
 
 
 void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2& scale, const Vector4& color,
 void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2& scale, const Vector4& color,

+ 167 - 0
gameplay/src/Stream.h

@@ -0,0 +1,167 @@
+#ifndef Stream_H_
+#define Stream_H_
+
+namespace gameplay
+{
+
+/**
+ * Stream is an interface for reading and writing a sequence of bytes.
+ * 
+ * Use FileSystem::open() to create a stream.
+ * 
+ * @script{ignore}
+ */
+class Stream
+{
+public:
+
+    /**
+     * Destructor. The stream should be closed when it is destroyed.
+     */
+    virtual ~Stream() {};
+
+    /**
+     * Returns true if this stream can perform read operations.
+     * 
+     * @return True if the stream can read, false otherwise.
+     */
+    virtual bool canRead() = 0;
+
+    /**
+     * Returns true if this stream can perform write operations.
+     * 
+     * @return True if the stream can write, false otherwise.
+     */
+    virtual bool canWrite() = 0;
+
+    /**
+     * Returns true if this stream can seek.
+     * 
+     * @return True if the stream can seek, false otherwise.
+     */
+    virtual bool canSeek() = 0;
+
+    /**
+     * Closes this stream.
+     */
+    virtual void close() = 0;
+    
+    /**
+     * Reads an array of <code>count</code> elements, each of size <code>size</code>.
+     * 
+     * \code
+     * int numbers[3];
+     * if (stream->read(numbers, sizeof(int), 3) != 3)
+     *     print("Error reading from file");
+     * \endcode
+     * 
+     * @param ptr   The pointer to the memory to copy into.
+     *              The available size should be at least (<code>size * count</code>) bytes.
+     * @param size  The size of each element to be read, in bytes.
+     * @param count The number of elements to read.
+     * 
+     * @return The number of elements read.
+     * 
+     * @see canRead()
+     */
+    virtual size_t read(void* ptr, size_t size, size_t count) = 0;
+
+    /**
+     * Reads a line from the stream.
+     * 
+     * A new line is denoted by by either "\n", "\r" or "\r\n".
+     * The line break character is included in the string.
+     * The terminating null character is added to the end of the string.
+     * 
+     * @param str The array of chars to copy the string to.
+     * @param num The maximum number of characters to be copied.
+     * 
+     * @return On success, str is returned. On error, NULL is returned.
+     * 
+     * @see canRead()
+     */
+    virtual char* readLine(char* str, int num) = 0;
+    
+    /**
+     * Writes an array of <code>count</code> elements, each of size <code>size</code>.
+     * 
+     * \code
+     * int numbers[] = {1, 2, 3};
+     * if (stream->write(numbers, sizeof(int), 3) != 3)
+     *     print("Error writing to file");
+     * \endcode
+     * 
+     * @param ptr   The pointer to the array of elements to be written.
+     * @param size  The size of each element to be written, in bytes.
+     * @param count The number of elements to write.
+     * 
+     * @return The number of elements written.
+     * 
+     * @see canWrite()
+     */
+    virtual size_t write(const void* ptr, size_t size, size_t count) = 0;
+
+    /**
+     * Returns true if the end of the stream has been reached.
+     * 
+     * @return True if end of stream reached, false otherwise.
+     */
+    virtual bool eof() = 0;
+
+    /**
+     * Returns the length of the stream in bytes.
+     * 
+     * Zero is returned if the length of the stream is unknown and/or it cannot be seeked. 
+     * 
+     * Example: The length of a network stream is unknown and cannot be seeked.
+     * 
+     * @return The length of the stream in bytes.
+     */
+    virtual size_t length() = 0;
+
+    /**
+     * Returns the position of the file pointer. Zero is the start of the stream.
+     * 
+     * @return The file indicator offset in bytes. 
+     */
+    virtual long int position() = 0;
+
+    /**
+     * Sets the position of the file pointer.
+     * 
+     * Use canSeek() to determine if this method is supported.
+     * 
+     * @param offset The number of bytes to offset from origin.
+     * @param origin The position used as a reference for offset.
+     *               The supported values are the same as fseek().
+     *                - <code>SEEK_SET</code> relative to the beginning of the file.
+     *                - <code>SEEK_CUR</code> relative to the current position of the file pointer.
+     *                - <code>SEEK_END</code> relative to the end of file.
+     * 
+     * @return True if successful, false otherwise.
+     * 
+     * @see canSeek()
+     */
+    virtual bool seek(long int offset, int origin) = 0;
+
+    /**
+     * Moves the file pointer to the start of the file.
+     * 
+     * Use canSeek() to determine if this method is supported.
+     * 
+     * @return True if successful, false otherwise.
+     * 
+     * @see canSeek()
+     */
+    virtual bool rewind() = 0;
+
+protected:
+    Stream() {};
+private:
+    Stream(const Stream&);            // Hidden copy constructor.
+    Stream& operator=(const Stream&); // Hidden copy assignment operator.
+};
+
+}
+
+#endif

+ 2 - 3
gameplay/src/TextBox.cpp

@@ -289,7 +289,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         // Always check that the text still fits within the clip region.
                         // Always check that the text still fits within the clip region.
                         Rectangle textBounds;
                         Rectangle textBounds;
                         font->measureText(_text.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
                         font->measureText(_text.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
-                        if (textBounds.x <= _textBounds.x || textBounds.y <= _textBounds.y ||
+                        if (textBounds.x < _textBounds.x || textBounds.y < _textBounds.y ||
                             textBounds.width >= _textBounds.width || textBounds.height >= _textBounds.height)
                             textBounds.width >= _textBounds.width || textBounds.height >= _textBounds.height)
                         {
                         {
                             // If not, undo the character insertion.
                             // If not, undo the character insertion.
@@ -329,10 +329,9 @@ void TextBox::update(const Control* container, const Vector2& offset)
 
 
 void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
 void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
 {
 {
-    if (_state == ACTIVE || _state == FOCUS)
+    if (_caretImage && (_state == ACTIVE || _state == FOCUS))
     {
     {
         // Draw the cursor at its current location.
         // Draw the cursor at its current location.
-        GP_ASSERT(_caretImage);
         const Rectangle& region = _caretImage->getRegion();
         const Rectangle& region = _caretImage->getRegion();
         if (!region.isEmpty())
         if (!region.isEmpty())
         {
         {

+ 21 - 89
gameplay/src/Texture.cpp

@@ -220,8 +220,8 @@ static unsigned int computePVRTCDataSize(int width, int height, int bpp)
 
 
 Texture* Texture::createCompressedPVRTC(const char* path)
 Texture* Texture::createCompressedPVRTC(const char* path)
 {
 {
-    FILE* file = FileSystem::openFile(path, "rb");
-    if (file == NULL)
+    std::auto_ptr<Stream> stream(FileSystem::open(path));
+    if (stream.get() == NULL || !stream->canRead())
     {
     {
         GP_ERROR("Failed to load file '%s'.", path);
         GP_ERROR("Failed to load file '%s'.", path);
         return NULL;
         return NULL;
@@ -230,27 +230,17 @@ Texture* Texture::createCompressedPVRTC(const char* path)
     // Read first 4 bytes to determine PVRTC format.
     // Read first 4 bytes to determine PVRTC format.
     size_t read;
     size_t read;
     unsigned int version;
     unsigned int version;
-    read = fread(&version, sizeof(unsigned int), 1, file);
+    read = stream->read(&version, sizeof(unsigned int), 1);
     if (read != 1)
     if (read != 1)
     {
     {
         GP_ERROR("Failed to read PVR version.");
         GP_ERROR("Failed to read PVR version.");
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close PVR file '%s'.", path);
-            return NULL;
-        }
         return NULL;
         return NULL;
     }
     }
 
 
     // Rewind to start of header.
     // Rewind to start of header.
-    if (fseek(file, 0, SEEK_SET) != 0)
+    if (stream->seek(0, SEEK_SET) == false)
     {
     {
         GP_ERROR("Failed to seek backwards to beginning of file after reading PVR version.");
         GP_ERROR("Failed to seek backwards to beginning of file after reading PVR version.");
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close PVR file '%s'.", path);
-            return NULL;
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -263,29 +253,19 @@ Texture* Texture::createCompressedPVRTC(const char* path)
     if (version == 0x03525650)
     if (version == 0x03525650)
     {
     {
         // Modern PVR file format.
         // Modern PVR file format.
-        data = readCompressedPVRTC(path, file, &width, &height, &format, &mipMapCount);
+        data = readCompressedPVRTC(path, stream.get(), &width, &height, &format, &mipMapCount);
     }
     }
     else
     else
     {
     {
         // Legacy PVR file format.
         // Legacy PVR file format.
-        data = readCompressedPVRTCLegacy(path, file, &width, &height, &format, &mipMapCount);
+        data = readCompressedPVRTCLegacy(path, stream.get(), &width, &height, &format, &mipMapCount);
     }
     }
     if (data == NULL)
     if (data == NULL)
     {
     {
         GP_ERROR("Failed to read texture data from PVR file '%s'.", path);
         GP_ERROR("Failed to read texture data from PVR file '%s'.", path);
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close PVR file '%s'.", path);
-            return NULL;
-        }
-        return NULL;
-    }
-
-    if (fclose(file) != 0)
-    {
-        GP_ERROR("Failed to close PVR file '%s'.", path);
         return NULL;
         return NULL;
     }
     }
+    stream->close();
 
 
     int bpp = (format == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG) ? 2 : 4;
     int bpp = (format == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG) ? 2 : 4;
 
 
@@ -322,9 +302,9 @@ Texture* Texture::createCompressedPVRTC(const char* path)
     return texture;
     return texture;
 }
 }
 
 
-GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount)
+GLubyte* Texture::readCompressedPVRTC(const char* path, Stream* stream, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount)
 {
 {
-    GP_ASSERT(file);
+    GP_ASSERT(stream);
     GP_ASSERT(path);
     GP_ASSERT(path);
     GP_ASSERT(width);
     GP_ASSERT(width);
     GP_ASSERT(height);
     GP_ASSERT(height);
@@ -351,7 +331,7 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
 
 
     // Read header data.
     // Read header data.
     pvrtc_file_header header;
     pvrtc_file_header header;
-    read = fread(&header, sizeof(pvrtc_file_header), 1, file);
+    read = stream->read(&header, sizeof(pvrtc_file_header), 1);
     if (read != 1)
     if (read != 1)
     {
     {
         GP_ERROR("Failed to read PVR header data for file '%s'.", path);
         GP_ERROR("Failed to read PVR header data for file '%s'.", path);
@@ -395,7 +375,7 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
     *mipMapCount = header.mipMapCount;
     *mipMapCount = header.mipMapCount;
 
 
     // Skip meta-data.
     // Skip meta-data.
-    if (fseek(file, header.metaDataSize, SEEK_CUR) != 0)
+    if (stream->seek(header.metaDataSize, SEEK_CUR) == false)
     {
     {
         GP_ERROR("Failed to seek past header meta data in PVR file '%s'.", path);
         GP_ERROR("Failed to seek past header meta data in PVR file '%s'.", path);
         return NULL;
         return NULL;
@@ -414,7 +394,7 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
 
 
     // Read data.
     // Read data.
     GLubyte* data = new GLubyte[dataSize];
     GLubyte* data = new GLubyte[dataSize];
-    read = fread(data, 1, dataSize, file);
+    read = stream->read(data, 1, dataSize);
     if (read != dataSize)
     if (read != dataSize)
     {
     {
         SAFE_DELETE_ARRAY(data);
         SAFE_DELETE_ARRAY(data);
@@ -425,7 +405,7 @@ GLubyte* Texture::readCompressedPVRTC(const char* path, FILE* file, GLsizei* wid
     return data;
     return data;
 }
 }
 
 
-GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount)
+GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, Stream* stream, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount)
 {
 {
     char PVRTCIdentifier[] = "PVR!";
     char PVRTCIdentifier[] = "PVR!";
 
 
@@ -449,14 +429,10 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
     // Read the file header.
     // Read the file header.
     unsigned int size = sizeof(pvrtc_file_header_legacy);
     unsigned int size = sizeof(pvrtc_file_header_legacy);
     pvrtc_file_header_legacy header;
     pvrtc_file_header_legacy header;
-    unsigned int read = (int)fread(&header, 1, size, file);
+    unsigned int read = (int)stream->read(&header, 1, size);
     if (read != size)
     if (read != size)
     {
     {
         GP_ERROR("Failed to read file header for pvrtc file '%s'.", path);
         GP_ERROR("Failed to read file header for pvrtc file '%s'.", path);
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -467,10 +443,6 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
         PVRTCIdentifier[3] != (char)((header.pvrtcTag >> 24) & 0xff))
         PVRTCIdentifier[3] != (char)((header.pvrtcTag >> 24) & 0xff))
      {
      {
         GP_ERROR("Failed to load pvrtc file '%s': invalid header.", path);
         GP_ERROR("Failed to load pvrtc file '%s': invalid header.", path);
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -486,10 +458,6 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
     else
     else
     {
     {
         GP_ERROR("Failed to load pvrtc file '%s': invalid pvrtc compressed texture format flags.", path);
         GP_ERROR("Failed to load pvrtc file '%s': invalid pvrtc compressed texture format flags.", path);
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -498,14 +466,10 @@ GLubyte* Texture::readCompressedPVRTCLegacy(const char* path, FILE* file, GLsize
     *mipMapCount = header.mipmapCount + 1; // +1 because mipmapCount does not include the base level
     *mipMapCount = header.mipmapCount + 1; // +1 because mipmapCount does not include the base level
 
 
     GLubyte* data = new GLubyte[header.dataSize];
     GLubyte* data = new GLubyte[header.dataSize];
-    read = (int)fread(data, 1, header.dataSize, file);
+    read = (int)stream->read(data, 1, header.dataSize);
     if (read != header.dataSize)
     if (read != header.dataSize)
     {
     {
         GP_ERROR("Failed to load texture data for pvrtc file '%s'.", path);
         GP_ERROR("Failed to load texture data for pvrtc file '%s'.", path);
-        if (fclose(file) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         SAFE_DELETE_ARRAY(data);
         SAFE_DELETE_ARRAY(data);
         return NULL;
         return NULL;
     }
     }
@@ -559,8 +523,8 @@ Texture* Texture::createCompressedDDS(const char* path)
     Texture* texture = NULL;
     Texture* texture = NULL;
 
 
     // Read DDS file.
     // Read DDS file.
-    FILE* fp = FileSystem::openFile(path, "rb");
-    if (fp == NULL)
+    std::auto_ptr<Stream> stream(FileSystem::open(path));
+    if (stream.get() == NULL || !stream->canRead())
     {
     {
         GP_ERROR("Failed to open file '%s'.", path);
         GP_ERROR("Failed to open file '%s'.", path);
         return NULL;
         return NULL;
@@ -568,25 +532,17 @@ Texture* Texture::createCompressedDDS(const char* path)
 
 
     // Validate DDS magic number.
     // Validate DDS magic number.
     char code[4];
     char code[4];
-    if (fread(code, 1, 4, fp) != 4 || strncmp(code, "DDS ", 4) != 0)
+    if (stream->read(code, 1, 4) != 4 || strncmp(code, "DDS ", 4) != 0)
     {
     {
         GP_ERROR("Failed to read DDS file '%s': invalid DDS magic number.", path);
         GP_ERROR("Failed to read DDS file '%s': invalid DDS magic number.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
     // Read DDS header.
     // Read DDS header.
     dds_header header;
     dds_header header;
-    if (fread(&header, sizeof(dds_header), 1, fp) != 1)
+    if (stream->read(&header, sizeof(dds_header), 1) != 1)
     {
     {
         GP_ERROR("Failed to read header for DDS file '%s'.", path);
         GP_ERROR("Failed to read header for DDS file '%s'.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         return NULL;
         return NULL;
     }
     }
 
 
@@ -639,10 +595,6 @@ Texture* Texture::createCompressedDDS(const char* path)
             break;
             break;
         default:
         default:
             GP_ERROR("Unsupported compressed texture format (%d) for DDS file '%s'.", header.ddspf.dwFourCC, path);
             GP_ERROR("Unsupported compressed texture format (%d) for DDS file '%s'.", header.ddspf.dwFourCC, path);
-            if (fclose(fp) != 0)
-            {
-                GP_ERROR("Failed to close file '%s'.", path);
-            }
             SAFE_DELETE_ARRAY(mipLevels);
             SAFE_DELETE_ARRAY(mipLevels);
             return NULL;
             return NULL;
         }
         }
@@ -654,7 +606,7 @@ Texture* Texture::createCompressedDDS(const char* path)
             mipLevels[i].size =  std::max(1, (width+3) >> 2) * std::max(1, (height+3) >> 2) * bytesPerBlock;
             mipLevels[i].size =  std::max(1, (width+3) >> 2) * std::max(1, (height+3) >> 2) * bytesPerBlock;
             mipLevels[i].data = new GLubyte[mipLevels[i].size];
             mipLevels[i].data = new GLubyte[mipLevels[i].size];
 
 
-            if (fread(mipLevels[i].data, 1, mipLevels[i].size, fp) != (unsigned int)mipLevels[i].size)
+            if (stream->read(mipLevels[i].data, 1, mipLevels[i].size) != (unsigned int)mipLevels[i].size)
             {
             {
                 GP_ERROR("Failed to load dds compressed texture bytes for texture: %s", path);
                 GP_ERROR("Failed to load dds compressed texture bytes for texture: %s", path);
                 
                 
@@ -662,11 +614,6 @@ Texture* Texture::createCompressedDDS(const char* path)
                 for (unsigned int i = 0; i < header.dwMipMapCount; ++i)
                 for (unsigned int i = 0; i < header.dwMipMapCount; ++i)
                     SAFE_DELETE_ARRAY(mipLevels[i].data);
                     SAFE_DELETE_ARRAY(mipLevels[i].data);
                 SAFE_DELETE_ARRAY(mipLevels);
                 SAFE_DELETE_ARRAY(mipLevels);
-
-                if (fclose(fp) != 0)
-                {
-                    GP_ERROR("Failed to close file '%s'.", path);
-                }
                 return texture;
                 return texture;
             }
             }
 
 
@@ -679,10 +626,6 @@ Texture* Texture::createCompressedDDS(const char* path)
         // RGB (uncompressed)
         // RGB (uncompressed)
         // Note: Use GL_BGR as internal format to flip bytes.
         // Note: Use GL_BGR as internal format to flip bytes.
         GP_ERROR("Failed to create texture from DDS file '%s': uncompressed RGB format is not supported.", path);
         GP_ERROR("Failed to create texture from DDS file '%s': uncompressed RGB format is not supported.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         SAFE_DELETE_ARRAY(mipLevels);
         SAFE_DELETE_ARRAY(mipLevels);
         return NULL;
         return NULL;
     }
     }
@@ -691,10 +634,6 @@ Texture* Texture::createCompressedDDS(const char* path)
         // RGBA (uncompressed)
         // RGBA (uncompressed)
         // Note: Use GL_BGRA as internal format to flip bytes.
         // Note: Use GL_BGRA as internal format to flip bytes.
         GP_ERROR("Failed to create texture from DDS file '%s': uncompressed RGBA format is not supported.", path);
         GP_ERROR("Failed to create texture from DDS file '%s': uncompressed RGBA format is not supported.", path);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         SAFE_DELETE_ARRAY(mipLevels);
         SAFE_DELETE_ARRAY(mipLevels);
         return NULL;
         return NULL;
     }
     }
@@ -702,19 +641,12 @@ Texture* Texture::createCompressedDDS(const char* path)
     {
     {
         // Unsupported.
         // Unsupported.
         GP_ERROR("Failed to create texture from DDS file '%s': unsupported flags (%d).", path, header.ddspf.dwFlags);
         GP_ERROR("Failed to create texture from DDS file '%s': unsupported flags (%d).", path, header.ddspf.dwFlags);
-        if (fclose(fp) != 0)
-        {
-            GP_ERROR("Failed to close file '%s'.", path);
-        }
         SAFE_DELETE_ARRAY(mipLevels);
         SAFE_DELETE_ARRAY(mipLevels);
         return NULL;
         return NULL;
     }
     }
     
     
     // Close file.
     // Close file.
-    if (fclose(fp) != 0)
-    {
-        GP_ERROR("Failed to close file '%s'.", path);
-    }
+    stream->close();
 
 
     // Generate GL texture.
     // Generate GL texture.
     GLuint textureId;
     GLuint textureId;

+ 3 - 2
gameplay/src/Texture.h

@@ -2,6 +2,7 @@
 #define TEXTURE_H_
 #define TEXTURE_H_
 
 
 #include "Ref.h"
 #include "Ref.h"
+#include "Stream.h"
 
 
 namespace gameplay
 namespace gameplay
 {
 {
@@ -285,9 +286,9 @@ private:
 
 
     static Texture* createCompressedDDS(const char* path);
     static Texture* createCompressedDDS(const char* path);
 
 
-    static GLubyte* readCompressedPVRTC(const char* path, FILE* file, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount);
+    static GLubyte* readCompressedPVRTC(const char* path, Stream* stream, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount);
 
 
-    static GLubyte* readCompressedPVRTCLegacy(const char* path, FILE* file, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount);
+    static GLubyte* readCompressedPVRTCLegacy(const char* path, Stream* stream, GLsizei* width, GLsizei* height, GLenum* format, unsigned int* mipMapCount);
 
 
     std::string _path;
     std::string _path;
     TextureHandle _handle;
     TextureHandle _handle;

+ 3 - 1
gameplay/src/Transform.h

@@ -682,7 +682,7 @@ public:
     void translateUp(float amount);
     void translateUp(float amount);
 
 
     /**
     /**
-     * Translates the camera foward by the specified amount in the z-axis.
+     * Translates the camera forward by the specified amount in the z-axis.
      *
      *
      * @param amount The amount to translate.
      * @param amount The amount to translate.
      */
      */
@@ -757,6 +757,8 @@ public:
 
 
     /**
     /**
      * Removes a transform listener.
      * Removes a transform listener.
+     * 
+     * @param listener The listener to remove.
      */
      */
     void removeListener(Transform::Listener* listener);
     void removeListener(Transform::Listener* listener);
     
     

+ 1 - 1
gameplay/src/Vector2.cpp

@@ -171,7 +171,7 @@ Vector2& Vector2::normalize()
     return *this;
     return *this;
 }
 }
 
 
-void Vector2::normalize(Vector2* dst)
+void Vector2::normalize(Vector2* dst) const
 {
 {
     GP_ASSERT(dst);
     GP_ASSERT(dst);
 
 

+ 1 - 1
gameplay/src/Vector2.h

@@ -245,7 +245,7 @@ public:
      *
      *
      * @param dst The destination vector.
      * @param dst The destination vector.
      */
      */
-    void normalize(Vector2* dst);
+    void normalize(Vector2* dst) const;
 
 
     /**
     /**
      * Scales all elements of this vector by the specified value.
      * Scales all elements of this vector by the specified value.

+ 4 - 1
gameplay/src/Vector3.cpp

@@ -173,7 +173,10 @@ void Vector3::cross(const Vector3& v1, const Vector3& v2, Vector3* dst)
 {
 {
     GP_ASSERT(dst);
     GP_ASSERT(dst);
 
 
-    MathUtil::crossVector3((const float*)&v1, (const float*)&v2, (float*)dst);
+    // NOTE: This code assumes Vector3 struct members are contiguous floats in memory.
+    // We might want to revisit this (and other areas of code that make this assumption)
+    // later to guarantee 100% safety/compatibility.
+    MathUtil::crossVector3(&v1.x, &v2.x, &dst->x);
 }
 }
 
 
 float Vector3::distance(const Vector3& v) const
 float Vector3::distance(const Vector3& v) const

+ 1 - 1
gameplay/src/Vector4.cpp

@@ -239,7 +239,7 @@ Vector4& Vector4::normalize()
     return *this;
     return *this;
 }
 }
 
 
-void Vector4::normalize(Vector4* dst)
+void Vector4::normalize(Vector4* dst) const
 {
 {
     GP_ASSERT(dst);
     GP_ASSERT(dst);
 
 

+ 1 - 1
gameplay/src/Vector4.h

@@ -283,7 +283,7 @@ public:
      *
      *
      * @param dst The destination vector.
      * @param dst The destination vector.
      */
      */
-    void normalize(Vector4* dst);
+    void normalize(Vector4* dst) const;
 
 
     /**
     /**
      * Scales all elements of this vector by the specified value.
      * Scales all elements of this vector by the specified value.

+ 153 - 66
gameplay/src/lua/lua_Button.cpp

@@ -32,8 +32,6 @@ void luaRegister_Button()
         {"createAnimationFromBy", lua_Button_createAnimationFromBy},
         {"createAnimationFromBy", lua_Button_createAnimationFromBy},
         {"createAnimationFromTo", lua_Button_createAnimationFromTo},
         {"createAnimationFromTo", lua_Button_createAnimationFromTo},
         {"destroyAnimation", lua_Button_destroyAnimation},
         {"destroyAnimation", lua_Button_destroyAnimation},
-        {"disable", lua_Button_disable},
-        {"enable", lua_Button_enable},
         {"getAlignment", lua_Button_getAlignment},
         {"getAlignment", lua_Button_getAlignment},
         {"getAnimation", lua_Button_getAnimation},
         {"getAnimation", lua_Button_getAnimation},
         {"getAnimationPropertyComponentCount", lua_Button_getAnimationPropertyComponentCount},
         {"getAnimationPropertyComponentCount", lua_Button_getAnimationPropertyComponentCount},
@@ -74,7 +72,9 @@ void luaRegister_Button()
         {"getZIndex", lua_Button_getZIndex},
         {"getZIndex", lua_Button_getZIndex},
         {"isContainer", lua_Button_isContainer},
         {"isContainer", lua_Button_isContainer},
         {"isEnabled", lua_Button_isEnabled},
         {"isEnabled", lua_Button_isEnabled},
+        {"isVisible", lua_Button_isVisible},
         {"release", lua_Button_release},
         {"release", lua_Button_release},
+        {"removeListener", lua_Button_removeListener},
         {"removeScriptCallback", lua_Button_removeScriptCallback},
         {"removeScriptCallback", lua_Button_removeScriptCallback},
         {"setAlignment", lua_Button_setAlignment},
         {"setAlignment", lua_Button_setAlignment},
         {"setAnimationPropertyValue", lua_Button_setAnimationPropertyValue},
         {"setAnimationPropertyValue", lua_Button_setAnimationPropertyValue},
@@ -85,6 +85,7 @@ void luaRegister_Button()
         {"setConsumeInputEvents", lua_Button_setConsumeInputEvents},
         {"setConsumeInputEvents", lua_Button_setConsumeInputEvents},
         {"setCursorColor", lua_Button_setCursorColor},
         {"setCursorColor", lua_Button_setCursorColor},
         {"setCursorRegion", lua_Button_setCursorRegion},
         {"setCursorRegion", lua_Button_setCursorRegion},
+        {"setEnabled", lua_Button_setEnabled},
         {"setFocusIndex", lua_Button_setFocusIndex},
         {"setFocusIndex", lua_Button_setFocusIndex},
         {"setFont", lua_Button_setFont},
         {"setFont", lua_Button_setFont},
         {"setFontSize", lua_Button_setFontSize},
         {"setFontSize", lua_Button_setFontSize},
@@ -104,6 +105,7 @@ void luaRegister_Button()
         {"setTextAlignment", lua_Button_setTextAlignment},
         {"setTextAlignment", lua_Button_setTextAlignment},
         {"setTextColor", lua_Button_setTextColor},
         {"setTextColor", lua_Button_setTextColor},
         {"setTextRightToLeft", lua_Button_setTextRightToLeft},
         {"setTextRightToLeft", lua_Button_setTextRightToLeft},
+        {"setVisible", lua_Button_setVisible},
         {"setWidth", lua_Button_setWidth},
         {"setWidth", lua_Button_setWidth},
         {"setZIndex", lua_Button_setZIndex},
         {"setZIndex", lua_Button_setZIndex},
         {NULL, NULL}
         {NULL, NULL}
@@ -677,70 +679,6 @@ int lua_Button_destroyAnimation(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
-int lua_Button_disable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                Button* instance = getInstance(state);
-                instance->disable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_Button_disable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
-int lua_Button_enable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                Button* instance = getInstance(state);
-                instance->enable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_Button_enable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
 int lua_Button_getAlignment(lua_State* state)
 int lua_Button_getAlignment(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2618,6 +2556,41 @@ int lua_Button_isEnabled(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Button_isVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                Button* instance = getInstance(state);
+                bool result = instance->isVisible();
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Button_isVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Button_release(lua_State* state)
 int lua_Button_release(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2650,6 +2623,48 @@ int lua_Button_release(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Button_removeListener(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                bool param1Valid;
+                ScriptUtil::LuaArray<Control::Listener> param1 = ScriptUtil::getObjectPointer<Control::Listener>(2, "ControlListener", false, &param1Valid);
+                if (!param1Valid)
+                {
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'Control::Listener'.");
+                    lua_error(state);
+                }
+
+                Button* instance = getInstance(state);
+                instance->removeListener(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Button_removeListener - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Button_removeScriptCallback(lua_State* state)
 int lua_Button_removeScriptCallback(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -3128,6 +3143,42 @@ int lua_Button_setCursorRegion(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Button_setEnabled(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                Button* instance = getInstance(state);
+                instance->setEnabled(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Button_setEnabled - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Button_setFocusIndex(lua_State* state)
 int lua_Button_setFocusIndex(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -4158,6 +4209,42 @@ int lua_Button_setTextRightToLeft(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Button_setVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                Button* instance = getInstance(state);
+                instance->setVisible(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Button_setVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Button_setWidth(lua_State* state)
 int lua_Button_setWidth(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.

+ 4 - 2
gameplay/src/lua/lua_Button.h

@@ -13,8 +13,6 @@ int lua_Button_createAnimation(lua_State* state);
 int lua_Button_createAnimationFromBy(lua_State* state);
 int lua_Button_createAnimationFromBy(lua_State* state);
 int lua_Button_createAnimationFromTo(lua_State* state);
 int lua_Button_createAnimationFromTo(lua_State* state);
 int lua_Button_destroyAnimation(lua_State* state);
 int lua_Button_destroyAnimation(lua_State* state);
-int lua_Button_disable(lua_State* state);
-int lua_Button_enable(lua_State* state);
 int lua_Button_getAlignment(lua_State* state);
 int lua_Button_getAlignment(lua_State* state);
 int lua_Button_getAnimation(lua_State* state);
 int lua_Button_getAnimation(lua_State* state);
 int lua_Button_getAnimationPropertyComponentCount(lua_State* state);
 int lua_Button_getAnimationPropertyComponentCount(lua_State* state);
@@ -55,7 +53,9 @@ int lua_Button_getY(lua_State* state);
 int lua_Button_getZIndex(lua_State* state);
 int lua_Button_getZIndex(lua_State* state);
 int lua_Button_isContainer(lua_State* state);
 int lua_Button_isContainer(lua_State* state);
 int lua_Button_isEnabled(lua_State* state);
 int lua_Button_isEnabled(lua_State* state);
+int lua_Button_isVisible(lua_State* state);
 int lua_Button_release(lua_State* state);
 int lua_Button_release(lua_State* state);
+int lua_Button_removeListener(lua_State* state);
 int lua_Button_removeScriptCallback(lua_State* state);
 int lua_Button_removeScriptCallback(lua_State* state);
 int lua_Button_setAlignment(lua_State* state);
 int lua_Button_setAlignment(lua_State* state);
 int lua_Button_setAnimationPropertyValue(lua_State* state);
 int lua_Button_setAnimationPropertyValue(lua_State* state);
@@ -66,6 +66,7 @@ int lua_Button_setBounds(lua_State* state);
 int lua_Button_setConsumeInputEvents(lua_State* state);
 int lua_Button_setConsumeInputEvents(lua_State* state);
 int lua_Button_setCursorColor(lua_State* state);
 int lua_Button_setCursorColor(lua_State* state);
 int lua_Button_setCursorRegion(lua_State* state);
 int lua_Button_setCursorRegion(lua_State* state);
+int lua_Button_setEnabled(lua_State* state);
 int lua_Button_setFocusIndex(lua_State* state);
 int lua_Button_setFocusIndex(lua_State* state);
 int lua_Button_setFont(lua_State* state);
 int lua_Button_setFont(lua_State* state);
 int lua_Button_setFontSize(lua_State* state);
 int lua_Button_setFontSize(lua_State* state);
@@ -85,6 +86,7 @@ int lua_Button_setText(lua_State* state);
 int lua_Button_setTextAlignment(lua_State* state);
 int lua_Button_setTextAlignment(lua_State* state);
 int lua_Button_setTextColor(lua_State* state);
 int lua_Button_setTextColor(lua_State* state);
 int lua_Button_setTextRightToLeft(lua_State* state);
 int lua_Button_setTextRightToLeft(lua_State* state);
+int lua_Button_setVisible(lua_State* state);
 int lua_Button_setWidth(lua_State* state);
 int lua_Button_setWidth(lua_State* state);
 int lua_Button_setZIndex(lua_State* state);
 int lua_Button_setZIndex(lua_State* state);
 int lua_Button_static_ANIMATE_OPACITY(lua_State* state);
 int lua_Button_static_ANIMATE_OPACITY(lua_State* state);

+ 153 - 66
gameplay/src/lua/lua_CheckBox.cpp

@@ -33,8 +33,6 @@ void luaRegister_CheckBox()
         {"createAnimationFromBy", lua_CheckBox_createAnimationFromBy},
         {"createAnimationFromBy", lua_CheckBox_createAnimationFromBy},
         {"createAnimationFromTo", lua_CheckBox_createAnimationFromTo},
         {"createAnimationFromTo", lua_CheckBox_createAnimationFromTo},
         {"destroyAnimation", lua_CheckBox_destroyAnimation},
         {"destroyAnimation", lua_CheckBox_destroyAnimation},
-        {"disable", lua_CheckBox_disable},
-        {"enable", lua_CheckBox_enable},
         {"getAlignment", lua_CheckBox_getAlignment},
         {"getAlignment", lua_CheckBox_getAlignment},
         {"getAnimation", lua_CheckBox_getAnimation},
         {"getAnimation", lua_CheckBox_getAnimation},
         {"getAnimationPropertyComponentCount", lua_CheckBox_getAnimationPropertyComponentCount},
         {"getAnimationPropertyComponentCount", lua_CheckBox_getAnimationPropertyComponentCount},
@@ -78,7 +76,9 @@ void luaRegister_CheckBox()
         {"isChecked", lua_CheckBox_isChecked},
         {"isChecked", lua_CheckBox_isChecked},
         {"isContainer", lua_CheckBox_isContainer},
         {"isContainer", lua_CheckBox_isContainer},
         {"isEnabled", lua_CheckBox_isEnabled},
         {"isEnabled", lua_CheckBox_isEnabled},
+        {"isVisible", lua_CheckBox_isVisible},
         {"release", lua_CheckBox_release},
         {"release", lua_CheckBox_release},
+        {"removeListener", lua_CheckBox_removeListener},
         {"removeScriptCallback", lua_CheckBox_removeScriptCallback},
         {"removeScriptCallback", lua_CheckBox_removeScriptCallback},
         {"setAlignment", lua_CheckBox_setAlignment},
         {"setAlignment", lua_CheckBox_setAlignment},
         {"setAnimationPropertyValue", lua_CheckBox_setAnimationPropertyValue},
         {"setAnimationPropertyValue", lua_CheckBox_setAnimationPropertyValue},
@@ -90,6 +90,7 @@ void luaRegister_CheckBox()
         {"setConsumeInputEvents", lua_CheckBox_setConsumeInputEvents},
         {"setConsumeInputEvents", lua_CheckBox_setConsumeInputEvents},
         {"setCursorColor", lua_CheckBox_setCursorColor},
         {"setCursorColor", lua_CheckBox_setCursorColor},
         {"setCursorRegion", lua_CheckBox_setCursorRegion},
         {"setCursorRegion", lua_CheckBox_setCursorRegion},
+        {"setEnabled", lua_CheckBox_setEnabled},
         {"setFocusIndex", lua_CheckBox_setFocusIndex},
         {"setFocusIndex", lua_CheckBox_setFocusIndex},
         {"setFont", lua_CheckBox_setFont},
         {"setFont", lua_CheckBox_setFont},
         {"setFontSize", lua_CheckBox_setFontSize},
         {"setFontSize", lua_CheckBox_setFontSize},
@@ -110,6 +111,7 @@ void luaRegister_CheckBox()
         {"setTextAlignment", lua_CheckBox_setTextAlignment},
         {"setTextAlignment", lua_CheckBox_setTextAlignment},
         {"setTextColor", lua_CheckBox_setTextColor},
         {"setTextColor", lua_CheckBox_setTextColor},
         {"setTextRightToLeft", lua_CheckBox_setTextRightToLeft},
         {"setTextRightToLeft", lua_CheckBox_setTextRightToLeft},
+        {"setVisible", lua_CheckBox_setVisible},
         {"setWidth", lua_CheckBox_setWidth},
         {"setWidth", lua_CheckBox_setWidth},
         {"setZIndex", lua_CheckBox_setZIndex},
         {"setZIndex", lua_CheckBox_setZIndex},
         {NULL, NULL}
         {NULL, NULL}
@@ -683,70 +685,6 @@ int lua_CheckBox_destroyAnimation(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
-int lua_CheckBox_disable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                CheckBox* instance = getInstance(state);
-                instance->disable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_CheckBox_disable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
-int lua_CheckBox_enable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                CheckBox* instance = getInstance(state);
-                instance->enable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_CheckBox_enable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
 int lua_CheckBox_getAlignment(lua_State* state)
 int lua_CheckBox_getAlignment(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2738,6 +2676,41 @@ int lua_CheckBox_isEnabled(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_CheckBox_isVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                CheckBox* instance = getInstance(state);
+                bool result = instance->isVisible();
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_CheckBox_isVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_CheckBox_release(lua_State* state)
 int lua_CheckBox_release(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2770,6 +2743,48 @@ int lua_CheckBox_release(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_CheckBox_removeListener(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                bool param1Valid;
+                ScriptUtil::LuaArray<Control::Listener> param1 = ScriptUtil::getObjectPointer<Control::Listener>(2, "ControlListener", false, &param1Valid);
+                if (!param1Valid)
+                {
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'Control::Listener'.");
+                    lua_error(state);
+                }
+
+                CheckBox* instance = getInstance(state);
+                instance->removeListener(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_CheckBox_removeListener - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_CheckBox_removeScriptCallback(lua_State* state)
 int lua_CheckBox_removeScriptCallback(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -3284,6 +3299,42 @@ int lua_CheckBox_setCursorRegion(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_CheckBox_setEnabled(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                CheckBox* instance = getInstance(state);
+                instance->setEnabled(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_CheckBox_setEnabled - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_CheckBox_setFocusIndex(lua_State* state)
 int lua_CheckBox_setFocusIndex(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -4354,6 +4405,42 @@ int lua_CheckBox_setTextRightToLeft(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_CheckBox_setVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                CheckBox* instance = getInstance(state);
+                instance->setVisible(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_CheckBox_setVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_CheckBox_setWidth(lua_State* state)
 int lua_CheckBox_setWidth(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.

+ 4 - 2
gameplay/src/lua/lua_CheckBox.h

@@ -13,8 +13,6 @@ int lua_CheckBox_createAnimation(lua_State* state);
 int lua_CheckBox_createAnimationFromBy(lua_State* state);
 int lua_CheckBox_createAnimationFromBy(lua_State* state);
 int lua_CheckBox_createAnimationFromTo(lua_State* state);
 int lua_CheckBox_createAnimationFromTo(lua_State* state);
 int lua_CheckBox_destroyAnimation(lua_State* state);
 int lua_CheckBox_destroyAnimation(lua_State* state);
-int lua_CheckBox_disable(lua_State* state);
-int lua_CheckBox_enable(lua_State* state);
 int lua_CheckBox_getAlignment(lua_State* state);
 int lua_CheckBox_getAlignment(lua_State* state);
 int lua_CheckBox_getAnimation(lua_State* state);
 int lua_CheckBox_getAnimation(lua_State* state);
 int lua_CheckBox_getAnimationPropertyComponentCount(lua_State* state);
 int lua_CheckBox_getAnimationPropertyComponentCount(lua_State* state);
@@ -58,7 +56,9 @@ int lua_CheckBox_getZIndex(lua_State* state);
 int lua_CheckBox_isChecked(lua_State* state);
 int lua_CheckBox_isChecked(lua_State* state);
 int lua_CheckBox_isContainer(lua_State* state);
 int lua_CheckBox_isContainer(lua_State* state);
 int lua_CheckBox_isEnabled(lua_State* state);
 int lua_CheckBox_isEnabled(lua_State* state);
+int lua_CheckBox_isVisible(lua_State* state);
 int lua_CheckBox_release(lua_State* state);
 int lua_CheckBox_release(lua_State* state);
+int lua_CheckBox_removeListener(lua_State* state);
 int lua_CheckBox_removeScriptCallback(lua_State* state);
 int lua_CheckBox_removeScriptCallback(lua_State* state);
 int lua_CheckBox_setAlignment(lua_State* state);
 int lua_CheckBox_setAlignment(lua_State* state);
 int lua_CheckBox_setAnimationPropertyValue(lua_State* state);
 int lua_CheckBox_setAnimationPropertyValue(lua_State* state);
@@ -70,6 +70,7 @@ int lua_CheckBox_setChecked(lua_State* state);
 int lua_CheckBox_setConsumeInputEvents(lua_State* state);
 int lua_CheckBox_setConsumeInputEvents(lua_State* state);
 int lua_CheckBox_setCursorColor(lua_State* state);
 int lua_CheckBox_setCursorColor(lua_State* state);
 int lua_CheckBox_setCursorRegion(lua_State* state);
 int lua_CheckBox_setCursorRegion(lua_State* state);
+int lua_CheckBox_setEnabled(lua_State* state);
 int lua_CheckBox_setFocusIndex(lua_State* state);
 int lua_CheckBox_setFocusIndex(lua_State* state);
 int lua_CheckBox_setFont(lua_State* state);
 int lua_CheckBox_setFont(lua_State* state);
 int lua_CheckBox_setFontSize(lua_State* state);
 int lua_CheckBox_setFontSize(lua_State* state);
@@ -90,6 +91,7 @@ int lua_CheckBox_setText(lua_State* state);
 int lua_CheckBox_setTextAlignment(lua_State* state);
 int lua_CheckBox_setTextAlignment(lua_State* state);
 int lua_CheckBox_setTextColor(lua_State* state);
 int lua_CheckBox_setTextColor(lua_State* state);
 int lua_CheckBox_setTextRightToLeft(lua_State* state);
 int lua_CheckBox_setTextRightToLeft(lua_State* state);
+int lua_CheckBox_setVisible(lua_State* state);
 int lua_CheckBox_setWidth(lua_State* state);
 int lua_CheckBox_setWidth(lua_State* state);
 int lua_CheckBox_setZIndex(lua_State* state);
 int lua_CheckBox_setZIndex(lua_State* state);
 int lua_CheckBox_static_ANIMATE_OPACITY(lua_State* state);
 int lua_CheckBox_static_ANIMATE_OPACITY(lua_State* state);

+ 153 - 66
gameplay/src/lua/lua_Container.cpp

@@ -45,8 +45,6 @@ void luaRegister_Container()
         {"createAnimationFromBy", lua_Container_createAnimationFromBy},
         {"createAnimationFromBy", lua_Container_createAnimationFromBy},
         {"createAnimationFromTo", lua_Container_createAnimationFromTo},
         {"createAnimationFromTo", lua_Container_createAnimationFromTo},
         {"destroyAnimation", lua_Container_destroyAnimation},
         {"destroyAnimation", lua_Container_destroyAnimation},
-        {"disable", lua_Container_disable},
-        {"enable", lua_Container_enable},
         {"getAlignment", lua_Container_getAlignment},
         {"getAlignment", lua_Container_getAlignment},
         {"getAnimation", lua_Container_getAnimation},
         {"getAnimation", lua_Container_getAnimation},
         {"getAnimationPropertyComponentCount", lua_Container_getAnimationPropertyComponentCount},
         {"getAnimationPropertyComponentCount", lua_Container_getAnimationPropertyComponentCount},
@@ -93,8 +91,10 @@ void luaRegister_Container()
         {"isEnabled", lua_Container_isEnabled},
         {"isEnabled", lua_Container_isEnabled},
         {"isScrollBarsAutoHide", lua_Container_isScrollBarsAutoHide},
         {"isScrollBarsAutoHide", lua_Container_isScrollBarsAutoHide},
         {"isScrolling", lua_Container_isScrolling},
         {"isScrolling", lua_Container_isScrolling},
+        {"isVisible", lua_Container_isVisible},
         {"release", lua_Container_release},
         {"release", lua_Container_release},
         {"removeControl", lua_Container_removeControl},
         {"removeControl", lua_Container_removeControl},
+        {"removeListener", lua_Container_removeListener},
         {"removeScriptCallback", lua_Container_removeScriptCallback},
         {"removeScriptCallback", lua_Container_removeScriptCallback},
         {"setAlignment", lua_Container_setAlignment},
         {"setAlignment", lua_Container_setAlignment},
         {"setAnimationPropertyValue", lua_Container_setAnimationPropertyValue},
         {"setAnimationPropertyValue", lua_Container_setAnimationPropertyValue},
@@ -105,6 +105,7 @@ void luaRegister_Container()
         {"setConsumeInputEvents", lua_Container_setConsumeInputEvents},
         {"setConsumeInputEvents", lua_Container_setConsumeInputEvents},
         {"setCursorColor", lua_Container_setCursorColor},
         {"setCursorColor", lua_Container_setCursorColor},
         {"setCursorRegion", lua_Container_setCursorRegion},
         {"setCursorRegion", lua_Container_setCursorRegion},
+        {"setEnabled", lua_Container_setEnabled},
         {"setFocusIndex", lua_Container_setFocusIndex},
         {"setFocusIndex", lua_Container_setFocusIndex},
         {"setFont", lua_Container_setFont},
         {"setFont", lua_Container_setFont},
         {"setFontSize", lua_Container_setFontSize},
         {"setFontSize", lua_Container_setFontSize},
@@ -125,6 +126,7 @@ void luaRegister_Container()
         {"setTextAlignment", lua_Container_setTextAlignment},
         {"setTextAlignment", lua_Container_setTextAlignment},
         {"setTextColor", lua_Container_setTextColor},
         {"setTextColor", lua_Container_setTextColor},
         {"setTextRightToLeft", lua_Container_setTextRightToLeft},
         {"setTextRightToLeft", lua_Container_setTextRightToLeft},
+        {"setVisible", lua_Container_setVisible},
         {"setWidth", lua_Container_setWidth},
         {"setWidth", lua_Container_setWidth},
         {"setZIndex", lua_Container_setZIndex},
         {"setZIndex", lua_Container_setZIndex},
         {NULL, NULL}
         {NULL, NULL}
@@ -744,70 +746,6 @@ int lua_Container_destroyAnimation(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
-int lua_Container_disable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                Container* instance = getInstance(state);
-                instance->disable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_Container_disable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
-int lua_Container_enable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                Container* instance = getInstance(state);
-                instance->enable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_Container_enable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
 int lua_Container_getAlignment(lua_State* state)
 int lua_Container_getAlignment(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2958,6 +2896,41 @@ int lua_Container_isScrolling(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Container_isVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                Container* instance = getInstance(state);
+                bool result = instance->isVisible();
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Container_isVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Container_release(lua_State* state)
 int lua_Container_release(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -3062,6 +3035,48 @@ int lua_Container_removeControl(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Container_removeListener(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                bool param1Valid;
+                ScriptUtil::LuaArray<Control::Listener> param1 = ScriptUtil::getObjectPointer<Control::Listener>(2, "ControlListener", false, &param1Valid);
+                if (!param1Valid)
+                {
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'Control::Listener'.");
+                    lua_error(state);
+                }
+
+                Container* instance = getInstance(state);
+                instance->removeListener(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Container_removeListener - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Container_removeScriptCallback(lua_State* state)
 int lua_Container_removeScriptCallback(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -3540,6 +3555,42 @@ int lua_Container_setCursorRegion(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Container_setEnabled(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                Container* instance = getInstance(state);
+                instance->setEnabled(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Container_setEnabled - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Container_setFocusIndex(lua_State* state)
 int lua_Container_setFocusIndex(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -4606,6 +4657,42 @@ int lua_Container_setTextRightToLeft(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Container_setVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                Container* instance = getInstance(state);
+                instance->setVisible(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Container_setVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Container_setWidth(lua_State* state)
 int lua_Container_setWidth(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.

+ 4 - 2
gameplay/src/lua/lua_Container.h

@@ -14,8 +14,6 @@ int lua_Container_createAnimation(lua_State* state);
 int lua_Container_createAnimationFromBy(lua_State* state);
 int lua_Container_createAnimationFromBy(lua_State* state);
 int lua_Container_createAnimationFromTo(lua_State* state);
 int lua_Container_createAnimationFromTo(lua_State* state);
 int lua_Container_destroyAnimation(lua_State* state);
 int lua_Container_destroyAnimation(lua_State* state);
-int lua_Container_disable(lua_State* state);
-int lua_Container_enable(lua_State* state);
 int lua_Container_getAlignment(lua_State* state);
 int lua_Container_getAlignment(lua_State* state);
 int lua_Container_getAnimation(lua_State* state);
 int lua_Container_getAnimation(lua_State* state);
 int lua_Container_getAnimationPropertyComponentCount(lua_State* state);
 int lua_Container_getAnimationPropertyComponentCount(lua_State* state);
@@ -62,8 +60,10 @@ int lua_Container_isContainer(lua_State* state);
 int lua_Container_isEnabled(lua_State* state);
 int lua_Container_isEnabled(lua_State* state);
 int lua_Container_isScrollBarsAutoHide(lua_State* state);
 int lua_Container_isScrollBarsAutoHide(lua_State* state);
 int lua_Container_isScrolling(lua_State* state);
 int lua_Container_isScrolling(lua_State* state);
+int lua_Container_isVisible(lua_State* state);
 int lua_Container_release(lua_State* state);
 int lua_Container_release(lua_State* state);
 int lua_Container_removeControl(lua_State* state);
 int lua_Container_removeControl(lua_State* state);
+int lua_Container_removeListener(lua_State* state);
 int lua_Container_removeScriptCallback(lua_State* state);
 int lua_Container_removeScriptCallback(lua_State* state);
 int lua_Container_setAlignment(lua_State* state);
 int lua_Container_setAlignment(lua_State* state);
 int lua_Container_setAnimationPropertyValue(lua_State* state);
 int lua_Container_setAnimationPropertyValue(lua_State* state);
@@ -74,6 +74,7 @@ int lua_Container_setBounds(lua_State* state);
 int lua_Container_setConsumeInputEvents(lua_State* state);
 int lua_Container_setConsumeInputEvents(lua_State* state);
 int lua_Container_setCursorColor(lua_State* state);
 int lua_Container_setCursorColor(lua_State* state);
 int lua_Container_setCursorRegion(lua_State* state);
 int lua_Container_setCursorRegion(lua_State* state);
+int lua_Container_setEnabled(lua_State* state);
 int lua_Container_setFocusIndex(lua_State* state);
 int lua_Container_setFocusIndex(lua_State* state);
 int lua_Container_setFont(lua_State* state);
 int lua_Container_setFont(lua_State* state);
 int lua_Container_setFontSize(lua_State* state);
 int lua_Container_setFontSize(lua_State* state);
@@ -94,6 +95,7 @@ int lua_Container_setStyle(lua_State* state);
 int lua_Container_setTextAlignment(lua_State* state);
 int lua_Container_setTextAlignment(lua_State* state);
 int lua_Container_setTextColor(lua_State* state);
 int lua_Container_setTextColor(lua_State* state);
 int lua_Container_setTextRightToLeft(lua_State* state);
 int lua_Container_setTextRightToLeft(lua_State* state);
+int lua_Container_setVisible(lua_State* state);
 int lua_Container_setWidth(lua_State* state);
 int lua_Container_setWidth(lua_State* state);
 int lua_Container_setZIndex(lua_State* state);
 int lua_Container_setZIndex(lua_State* state);
 int lua_Container_static_ANIMATE_OPACITY(lua_State* state);
 int lua_Container_static_ANIMATE_OPACITY(lua_State* state);

+ 153 - 66
gameplay/src/lua/lua_Control.cpp

@@ -30,8 +30,6 @@ void luaRegister_Control()
         {"createAnimationFromBy", lua_Control_createAnimationFromBy},
         {"createAnimationFromBy", lua_Control_createAnimationFromBy},
         {"createAnimationFromTo", lua_Control_createAnimationFromTo},
         {"createAnimationFromTo", lua_Control_createAnimationFromTo},
         {"destroyAnimation", lua_Control_destroyAnimation},
         {"destroyAnimation", lua_Control_destroyAnimation},
-        {"disable", lua_Control_disable},
-        {"enable", lua_Control_enable},
         {"getAlignment", lua_Control_getAlignment},
         {"getAlignment", lua_Control_getAlignment},
         {"getAnimation", lua_Control_getAnimation},
         {"getAnimation", lua_Control_getAnimation},
         {"getAnimationPropertyComponentCount", lua_Control_getAnimationPropertyComponentCount},
         {"getAnimationPropertyComponentCount", lua_Control_getAnimationPropertyComponentCount},
@@ -72,7 +70,9 @@ void luaRegister_Control()
         {"getZIndex", lua_Control_getZIndex},
         {"getZIndex", lua_Control_getZIndex},
         {"isContainer", lua_Control_isContainer},
         {"isContainer", lua_Control_isContainer},
         {"isEnabled", lua_Control_isEnabled},
         {"isEnabled", lua_Control_isEnabled},
+        {"isVisible", lua_Control_isVisible},
         {"release", lua_Control_release},
         {"release", lua_Control_release},
+        {"removeListener", lua_Control_removeListener},
         {"removeScriptCallback", lua_Control_removeScriptCallback},
         {"removeScriptCallback", lua_Control_removeScriptCallback},
         {"setAlignment", lua_Control_setAlignment},
         {"setAlignment", lua_Control_setAlignment},
         {"setAnimationPropertyValue", lua_Control_setAnimationPropertyValue},
         {"setAnimationPropertyValue", lua_Control_setAnimationPropertyValue},
@@ -83,6 +83,7 @@ void luaRegister_Control()
         {"setConsumeInputEvents", lua_Control_setConsumeInputEvents},
         {"setConsumeInputEvents", lua_Control_setConsumeInputEvents},
         {"setCursorColor", lua_Control_setCursorColor},
         {"setCursorColor", lua_Control_setCursorColor},
         {"setCursorRegion", lua_Control_setCursorRegion},
         {"setCursorRegion", lua_Control_setCursorRegion},
+        {"setEnabled", lua_Control_setEnabled},
         {"setFocusIndex", lua_Control_setFocusIndex},
         {"setFocusIndex", lua_Control_setFocusIndex},
         {"setFont", lua_Control_setFont},
         {"setFont", lua_Control_setFont},
         {"setFontSize", lua_Control_setFontSize},
         {"setFontSize", lua_Control_setFontSize},
@@ -101,6 +102,7 @@ void luaRegister_Control()
         {"setTextAlignment", lua_Control_setTextAlignment},
         {"setTextAlignment", lua_Control_setTextAlignment},
         {"setTextColor", lua_Control_setTextColor},
         {"setTextColor", lua_Control_setTextColor},
         {"setTextRightToLeft", lua_Control_setTextRightToLeft},
         {"setTextRightToLeft", lua_Control_setTextRightToLeft},
+        {"setVisible", lua_Control_setVisible},
         {"setWidth", lua_Control_setWidth},
         {"setWidth", lua_Control_setWidth},
         {"setZIndex", lua_Control_setZIndex},
         {"setZIndex", lua_Control_setZIndex},
         {NULL, NULL}
         {NULL, NULL}
@@ -673,70 +675,6 @@ int lua_Control_destroyAnimation(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
-int lua_Control_disable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                Control* instance = getInstance(state);
-                instance->disable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_Control_disable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
-int lua_Control_enable(lua_State* state)
-{
-    // Get the number of parameters.
-    int paramCount = lua_gettop(state);
-
-    // Attempt to match the parameters to a valid binding.
-    switch (paramCount)
-    {
-        case 1:
-        {
-            if ((lua_type(state, 1) == LUA_TUSERDATA))
-            {
-                Control* instance = getInstance(state);
-                instance->enable();
-                
-                return 0;
-            }
-
-            lua_pushstring(state, "lua_Control_enable - Failed to match the given parameters to a valid function signature.");
-            lua_error(state);
-            break;
-        }
-        default:
-        {
-            lua_pushstring(state, "Invalid number of parameters (expected 1).");
-            lua_error(state);
-            break;
-        }
-    }
-    return 0;
-}
-
 int lua_Control_getAlignment(lua_State* state)
 int lua_Control_getAlignment(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2614,6 +2552,41 @@ int lua_Control_isEnabled(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Control_isVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 1:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA))
+            {
+                Control* instance = getInstance(state);
+                bool result = instance->isVisible();
+
+                // Push the return value onto the stack.
+                lua_pushboolean(state, result);
+
+                return 1;
+            }
+
+            lua_pushstring(state, "lua_Control_isVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 1).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Control_release(lua_State* state)
 int lua_Control_release(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -2646,6 +2619,48 @@ int lua_Control_release(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Control_removeListener(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                (lua_type(state, 2) == LUA_TUSERDATA || lua_type(state, 2) == LUA_TTABLE || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                bool param1Valid;
+                ScriptUtil::LuaArray<Control::Listener> param1 = ScriptUtil::getObjectPointer<Control::Listener>(2, "ControlListener", false, &param1Valid);
+                if (!param1Valid)
+                {
+                    lua_pushstring(state, "Failed to convert parameter 1 to type 'Control::Listener'.");
+                    lua_error(state);
+                }
+
+                Control* instance = getInstance(state);
+                instance->removeListener(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Control_removeListener - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Control_removeScriptCallback(lua_State* state)
 int lua_Control_removeScriptCallback(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -3124,6 +3139,42 @@ int lua_Control_setCursorRegion(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Control_setEnabled(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                Control* instance = getInstance(state);
+                instance->setEnabled(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Control_setEnabled - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Control_setFocusIndex(lua_State* state)
 int lua_Control_setFocusIndex(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.
@@ -4118,6 +4169,42 @@ int lua_Control_setTextRightToLeft(lua_State* state)
     return 0;
     return 0;
 }
 }
 
 
+int lua_Control_setVisible(lua_State* state)
+{
+    // Get the number of parameters.
+    int paramCount = lua_gettop(state);
+
+    // Attempt to match the parameters to a valid binding.
+    switch (paramCount)
+    {
+        case 2:
+        {
+            if ((lua_type(state, 1) == LUA_TUSERDATA) &&
+                lua_type(state, 2) == LUA_TBOOLEAN)
+            {
+                // Get parameter 1 off the stack.
+                bool param1 = ScriptUtil::luaCheckBool(state, 2);
+
+                Control* instance = getInstance(state);
+                instance->setVisible(param1);
+                
+                return 0;
+            }
+
+            lua_pushstring(state, "lua_Control_setVisible - Failed to match the given parameters to a valid function signature.");
+            lua_error(state);
+            break;
+        }
+        default:
+        {
+            lua_pushstring(state, "Invalid number of parameters (expected 2).");
+            lua_error(state);
+            break;
+        }
+    }
+    return 0;
+}
+
 int lua_Control_setWidth(lua_State* state)
 int lua_Control_setWidth(lua_State* state)
 {
 {
     // Get the number of parameters.
     // Get the number of parameters.

Некоторые файлы не были показаны из-за большого количества измененных файлов