ソースを参照

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

Adam Blake 12 年 前
コミット
31432062f0

+ 1 - 0
gameplay/CMakeLists.txt

@@ -492,6 +492,7 @@ set(GAMEPLAY_LUA
     src/lua/lua_RenderStateAutoBinding.h
     src/lua/lua_RenderStateBlend.cpp
     src/lua/lua_RenderStateBlend.h
+    src/lua/lua_RenderStateCullFaceSide.cpp
     src/lua/lua_RenderStateDepthFunction.cpp
     src/lua/lua_RenderStateDepthFunction.h
     src/lua/lua_RenderStateStateBlock.cpp

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

@@ -237,6 +237,7 @@ LOCAL_SRC_FILES := \
     lua/lua_RenderState.cpp \
     lua/lua_RenderStateAutoBinding.cpp \
     lua/lua_RenderStateBlend.cpp \
+    lua/lua_RenderStateCullFaceSide.cpp \
     lua/lua_RenderStateDepthFunction.cpp \
     lua/lua_RenderStateStateBlock.cpp \
     lua/lua_RenderTarget.cpp \

+ 3 - 1
gameplay/gameplay.vcxproj

@@ -229,6 +229,7 @@
     <ClCompile Include="src\lua\lua_RenderState.cpp" />
     <ClCompile Include="src\lua\lua_RenderStateAutoBinding.cpp" />
     <ClCompile Include="src\lua\lua_RenderStateBlend.cpp" />
+    <ClCompile Include="src\lua\lua_RenderStateCullFaceSide.cpp" />
     <ClCompile Include="src\lua\lua_RenderStateDepthFunction.cpp" />
     <ClCompile Include="src\lua\lua_RenderStateStateBlock.cpp" />
     <ClCompile Include="src\lua\lua_RenderTarget.cpp" />
@@ -509,6 +510,7 @@
     <ClInclude Include="src\lua\lua_RenderState.h" />
     <ClInclude Include="src\lua\lua_RenderStateAutoBinding.h" />
     <ClInclude Include="src\lua\lua_RenderStateBlend.h" />
+    <ClInclude Include="stc\lua\lua_RenderStateCullFaceSide.h" />
     <ClInclude Include="src\lua\lua_RenderStateDepthFunction.h" />
     <ClInclude Include="src\lua\lua_RenderStateStateBlock.h" />
     <ClInclude Include="src\lua\lua_RenderTarget.h" />
@@ -1094,4 +1096,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>

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

@@ -1155,6 +1155,10 @@
 		BD26373616CF865B00CFE15F /* Vector2.inl in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E39147D8FF50000361E /* Vector2.inl */; settings = {ATTRIBUTES = (Public, ); }; };
 		BD26373716CF865B00CFE15F /* Vector3.inl in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E3C147D8FF50000361E /* Vector3.inl */; settings = {ATTRIBUTES = (Public, ); }; };
 		BD26373816CF865B00CFE15F /* Vector4.inl in Headers */ = {isa = PBXBuildFile; fileRef = 42CD0E3F147D8FF50000361E /* Vector4.inl */; settings = {ATTRIBUTES = (Public, ); }; };
+		C054CBE5172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C054CBE3172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp */; };
+		C054CBE6172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C054CBE3172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp */; };
+		C054CBE7172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h in Headers */ = {isa = PBXBuildFile; fileRef = C054CBE4172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h */; };
+		C054CBE8172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h in Headers */ = {isa = PBXBuildFile; fileRef = C054CBE4172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h */; };
 		DD1FF47216DBD8F9000B42EF /* Platform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD1FF47116DBD8F9000B42EF /* Platform.cpp */; };
 		DD1FF47316DBD8F9000B42EF /* Platform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD1FF47116DBD8F9000B42EF /* Platform.cpp */; };
 		F1616ABC1614E24B008DD8B7 /* MathUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */; };
@@ -1766,6 +1770,8 @@
 		BD2636E216CF5B7400CFE15F /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/OpenGLES.framework; sourceTree = DEVELOPER_DIR; };
 		BD2636E316CF5B7400CFE15F /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
 		BD2636E416CF5B7400CFE15F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+		C054CBE3172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_RenderStateCullFaceSide.cpp; sourceTree = "<group>"; };
+		C054CBE4172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua_RenderStateCullFaceSide.h; sourceTree = "<group>"; };
 		DD1FF47116DBD8F9000B42EF /* Platform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Platform.cpp; path = src/Platform.cpp; sourceTree = SOURCE_ROOT; };
 		F1616ABB1614E24B008DD8B7 /* MathUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MathUtil.cpp; path = src/MathUtil.cpp; sourceTree = SOURCE_ROOT; };
 		F18024A31627000D001BFF87 /* gameplay-main-ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "gameplay-main-ios.mm"; path = "src/gameplay-main-ios.mm"; sourceTree = SOURCE_ROOT; };
@@ -2341,6 +2347,8 @@
 				42BCD41215EFD0F300C0E076 /* lua_RenderStateAutoBinding.h */,
 				42BCD41315EFD0F300C0E076 /* lua_RenderStateBlend.cpp */,
 				42BCD41415EFD0F300C0E076 /* lua_RenderStateBlend.h */,
+				C054CBE3172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp */,
+				C054CBE4172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h */,
 				B661732D16A61A4B0083A307 /* lua_RenderStateDepthFunction.cpp */,
 				B661732E16A61A4B0083A307 /* lua_RenderStateDepthFunction.h */,
 				42BCD41515EFD0F300C0E076 /* lua_RenderStateStateBlock.cpp */,
@@ -2792,6 +2800,7 @@
 				42A5031316E8F06500F0246C /* ImageControl.h in Headers */,
 				42A5031916E8F08900F0246C /* lua_ImageControl.h in Headers */,
 				42A5031F16E8F0B800F0246C /* lua_TerrainListener.h in Headers */,
+				C054CBE7172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3098,6 +3107,7 @@
 				42A5031416E8F06500F0246C /* ImageControl.h in Headers */,
 				42A5031A16E8F08900F0246C /* lua_ImageControl.h in Headers */,
 				42A5032016E8F0B800F0246C /* lua_TerrainListener.h in Headers */,
+				C054CBE8172EF541000B7DC3 /* lua_RenderStateCullFaceSide.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3473,6 +3483,7 @@
 				42A5031116E8F06500F0246C /* ImageControl.cpp in Sources */,
 				42A5031716E8F08900F0246C /* lua_ImageControl.cpp in Sources */,
 				42A5031D16E8F0B800F0246C /* lua_TerrainListener.cpp in Sources */,
+				C054CBE5172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3753,6 +3764,7 @@
 				42A5031216E8F06500F0246C /* ImageControl.cpp in Sources */,
 				42A5031816E8F08900F0246C /* lua_ImageControl.cpp in Sources */,
 				42A5031E16E8F0B800F0246C /* lua_TerrainListener.cpp in Sources */,
+				C054CBE6172EF541000B7DC3 /* lua_RenderStateCullFaceSide.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 1 - 1
gameplay/src/FileSystem.cpp

@@ -339,7 +339,7 @@ bool FileSystem::fileExists(const char* filePath)
     GP_ASSERT(filePath);
 
 #ifdef __ANDROID__
-    if (androidFileExists(filePath))
+    if (androidFileExists(resolvePath(filePath)))
     {
         return true;
     }

+ 14 - 0
gameplay/src/Game.h

@@ -527,6 +527,20 @@ public:
      */
     inline void getAccelerometerValues(float* pitch, float* roll);
 
+    /**
+     * Gets raw sensor values, if equipped, allowing a distinction between device acceleration
+     * and rotation rate. Returns zeros on platforms with no corresponding support. See also
+     * hasAccelerometer() and getAccelerometerValues().
+     *
+     * @param accelX The x-coordinate of the raw accelerometer data.
+     * @param accelY The y-coordinate of the raw accelerometer data.
+     * @param accelZ The z-coordinate of the raw accelerometer data.
+     * @param gyroX The x-coordinate of the raw gyroscope data.
+     * @param gyroY The y-coordinate of the raw gyroscope data.
+     * @param gyroZ The z-coordinate of the raw gyroscope data.
+     */
+    inline void getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ);
+
     /**
      * Gets the command line arguments.
      * 

+ 5 - 0
gameplay/src/Game.inl

@@ -131,6 +131,11 @@ inline void Game::getAccelerometerValues(float* pitch, float* roll)
     Platform::getAccelerometerValues(pitch, roll);
 }
 
+inline void Game::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    return Platform::getRawSensorValues(accelX, accelY, accelZ, gyroX, gyroY, gyroZ);
+}
+
 inline unsigned int Game::getGamepadCount() const
 {
     return Gamepad::getGamepadCount();

+ 14 - 0
gameplay/src/Platform.h

@@ -217,6 +217,20 @@ private:
      */
     static void getAccelerometerValues(float* pitch, float* roll);
 
+    /**
+     * Gets raw sensor values, if equipped, allowing a distinction between device acceleration
+     * and rotation rate. Returns zeros on platforms with no corresponding support. See also
+     * hasAccelerometer() and getAccelerometerValues().
+     *
+     * @param accelX The x-coordinate of the raw accelerometer data.
+     * @param accelY The y-coordinate of the raw accelerometer data.
+     * @param accelZ The z-coordinate of the raw accelerometer data.
+     * @param gyroX The x-coordinate of the raw gyroscope data.
+     * @param gyroY The y-coordinate of the raw gyroscope data.
+     * @param gyroZ The z-coordinate of the raw gyroscope data.
+     */
+    static void getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ);
+
     /**
      * Gets the command line arguments.
      * 

+ 77 - 12
gameplay/src/PlatformAndroid.cpp

@@ -31,6 +31,13 @@ static ASensorManager* __sensorManager;
 static ASensorEventQueue* __sensorEventQueue;
 static ASensorEvent __sensorEvent;
 static const ASensor* __accelerometerSensor;
+static const ASensor* __gyroscopeSensor;
+static float __accelRawX;
+static float __accelRawY;
+static float __accelRawZ;
+static float __gyroRawX;
+static float __gyroRawY;
+static float __gyroRawZ;
 static int __orientationAngle = 90;
 static bool __multiSampling = false;
 static bool __multiTouch = false;
@@ -905,13 +912,19 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             __initialized = false;
             break;
         case APP_CMD_GAINED_FOCUS:
-            // When our app gains focus, we start monitoring the accelerometer.
+            // When our app gains focus, we start monitoring the sensors.
             if (__accelerometerSensor != NULL) 
             {
                 ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
                 // We'd like to get 60 events per second (in microseconds).
                 ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
             }
+            if (__gyroscopeSensor != NULL)
+            {
+                ASensorEventQueue_enableSensor(__sensorEventQueue, __gyroscopeSensor);
+                // We'd like to get 60 events per second (in microseconds).
+                ASensorEventQueue_setEventRate(__sensorEventQueue, __gyroscopeSensor, (1000L/60)*1000);
+            }
 
             if (Game::getInstance()->getState() == Game::UNINITIALIZED)
             {
@@ -934,12 +947,16 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             __suspended = true;
             break;
         case APP_CMD_LOST_FOCUS:
-            // When our app loses focus, we stop monitoring the accelerometer.
+            // When our app loses focus, we stop monitoring the sensors.
             // This is to avoid consuming battery while not being used.
             if (__accelerometerSensor != NULL) 
             {
                 ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
             }
+            if (__gyroscopeSensor != NULL) 
+            {
+                ASensorEventQueue_disableSensor(__sensorEventQueue, __gyroscopeSensor);
+            }
             break;
     }
 }
@@ -1018,6 +1035,7 @@ int Platform::enterMessagePump()
     // Prepare to monitor accelerometer.
     __sensorManager = ASensorManager_getInstance();
     __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
+    __gyroscopeSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_GYROSCOPE);
     __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
     
     // Get the initial time.
@@ -1040,8 +1058,22 @@ int Platform::enterMessagePump()
             
             // If a sensor has data, process it now.
             if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
+            {
                 ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
-            
+                if (__sensorEvent.type == ASENSOR_TYPE_ACCELEROMETER)
+                {
+                    __accelRawX = __sensorEvent.acceleration.x;
+                    __accelRawY = __sensorEvent.acceleration.y;
+                    __accelRawZ = __sensorEvent.acceleration.z;
+                }
+                else if (__sensorEvent.type == ASENSOR_TYPE_GYROSCOPE)
+                {
+                    __gyroRawX = __sensorEvent.vector.x;
+                    __gyroRawY = __sensorEvent.vector.y;
+                    __gyroRawZ = __sensorEvent.vector.z;
+                }
+            }
+
             if (__state->destroyRequested != 0)
             {
                 return 0;
@@ -1192,23 +1224,23 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     switch (__orientationAngle)
     {
     case 90:
-        tx = -__sensorEvent.acceleration.y;
-        ty = __sensorEvent.acceleration.x;
+        tx = -__accelRawY;
+        ty = __accelRawX;
         break;
     case 180:
-        tx = -__sensorEvent.acceleration.x;
-        ty = -__sensorEvent.acceleration.y;
+        tx = -__accelRawX;
+        ty = -__accelRawY;
         break;
     case 270:
-        tx = __sensorEvent.acceleration.y;
-        ty = -__sensorEvent.acceleration.x;
+        tx = __accelRawY;
+        ty = -__accelRawX;
         break;
     default:
-        tx = __sensorEvent.acceleration.x;
-        ty = __sensorEvent.acceleration.y;
+        tx = __accelRawX;
+        ty = __accelRawY;
         break;
     }
-    tz = __sensorEvent.acceleration.z;
+    tz = __accelRawZ;
 
     if (pitch != NULL)
     {
@@ -1222,6 +1254,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     }
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    if (accelX)
+    {
+        *accelX = __accelRawX;
+    }
+
+    if (accelY)
+    {
+        *accelY = __accelRawY;
+    }
+
+    if (accelZ)
+    {
+        *accelZ = __accelRawZ;
+    }
+
+    if (gyroX)
+    {
+        *gyroX = __gyroRawX;
+    }
+
+    if (gyroY)
+    {
+        *gyroY = __gyroRawY;
+    }
+
+    if (gyroZ)
+    {
+        *gyroZ = __gyroRawZ;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 54 - 1
gameplay/src/PlatformBlackBerry.cpp

@@ -46,6 +46,12 @@ static bool __multiTouch = false;
 static bool __multiSampling = false;
 static float __pitch;
 static float __roll;
+static float __accelRawX;
+static float __accelRawY;
+static float __accelRawZ;
+static float __gyroRawX;
+static float __gyroRawY;
+static float __gyroRawZ;
 static const char* __glExtensions;
 static struct gestures_set * __gestureSet;
 static bitset<3> __gestureEventsProcessed;
@@ -704,10 +710,16 @@ Platform* Platform::create(Game* game, void* attachToWindow)
     bps_initialize();
 
     // Initialize navigator and orientation
-    static const int SENSOR_RATE = 25000;
+    static const int SENSOR_RATE = 25000; // (25000 microseconds = 40 Hz)
     sensor_set_rate(SENSOR_TYPE_AZIMUTH_PITCH_ROLL, SENSOR_RATE);
+    sensor_set_rate(SENSOR_TYPE_ACCELEROMETER, SENSOR_RATE);
+    sensor_set_rate(SENSOR_TYPE_GYROSCOPE, SENSOR_RATE);
     sensor_set_skip_duplicates(SENSOR_TYPE_AZIMUTH_PITCH_ROLL, true);
+    sensor_set_skip_duplicates(SENSOR_TYPE_ACCELEROMETER, true);
+    sensor_set_skip_duplicates(SENSOR_TYPE_GYROSCOPE, true);
     sensor_request_events(SENSOR_TYPE_AZIMUTH_PITCH_ROLL);
+    sensor_request_events(SENSOR_TYPE_ACCELEROMETER);
+    sensor_request_events(SENSOR_TYPE_GYROSCOPE);
     navigator_request_events(0);
     navigator_rotation_lock(true);
     __orientationAngle = atoi(getenv("ORIENTATION"));
@@ -1311,6 +1323,14 @@ int Platform::enterMessagePump()
                     float azimuth;
                     sensor_event_get_apr(event, &azimuth, &__pitch, &__roll);
                 }
+                else if (bps_event_get_code(event) == SENSOR_ACCELEROMETER_READING)
+                {
+                    sensor_event_get_xyz(event, &__accelRawX, &__accelRawY, &__accelRawZ);
+                }
+                else if (bps_event_get_code(event) == SENSOR_GYROSCOPE_READING)
+                {
+                    sensor_event_get_xyz(event, &__gyroRawX, &__gyroRawY, &__gyroRawZ);
+                }
             }
         }
 
@@ -1481,6 +1501,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     }
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+	if (accelX)
+	{
+		*accelX = __accelRawX;
+	}
+
+	if (accelY)
+	{
+		*accelY = __accelRawY;
+	}
+
+	if (accelZ)
+	{
+		*accelZ = __accelRawZ;
+	}
+
+	if (gyroX)
+	{
+		*gyroX = __gyroRawX;
+	}
+
+	if (gyroY)
+	{
+		*gyroY = __gyroRawY;
+	}
+
+	if (gyroZ)
+	{
+		*gyroZ = __gyroRawZ;
+	}
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 33 - 0
gameplay/src/PlatformLinux.cpp

@@ -1422,6 +1422,39 @@ namespace gameplay
         *roll = 0;
     }
 
+    void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+    {
+        if (accelX)
+        {
+            *accelX = 0;
+        }
+
+        if (accelY)
+        {
+            *accelY = 0;
+        }
+
+        if (accelZ)
+        {
+            *accelZ = 0;
+        }
+
+        if (gyroX)
+        {
+            *gyroX = 0;
+        }
+
+        if (gyroY)
+        {
+            *gyroY = 0;
+        }
+
+        if (gyroZ)
+        {
+            *gyroZ = 0;
+        }
+    }
+
     void Platform::getArguments(int* argc, char*** argv)
     {
         if (argc)

+ 28 - 0
gameplay/src/PlatformMacOSX.mm

@@ -1813,6 +1813,34 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     *roll = 0;
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    if (accelX)
+    {
+        *accelX = 0;
+    }
+    if (accelY)
+    {
+        *accelY = 0;
+    }
+    if (accelZ)
+    {
+        *accelZ = 0;
+    }
+    if (gyroX)
+    {
+        *gyroX = 0;
+    }
+    if (gyroY)
+    {
+        *gyroY = 0;
+    }
+    if (gyroZ)
+    {
+        *gyroZ = 0;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 33 - 0
gameplay/src/PlatformWindows.cpp

@@ -1115,6 +1115,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     *roll = 0;
 }
 
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    if (accelX)
+    {
+        *accelX = 0;
+    }
+
+    if (accelY)
+    {
+        *accelY = 0;
+    }
+
+    if (accelZ)
+    {
+        *accelZ = 0;
+    }
+
+    if (gyroX)
+    {
+        *gyroX = 0;
+    }
+
+    if (gyroY)
+    {
+        *gyroY = 0;
+    }
+
+    if (gyroZ)
+    {
+        *gyroZ = 0;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 61 - 2
gameplay/src/PlatformiOS.mm

@@ -850,7 +850,12 @@ int getUnicode(int key);
         motionManager.accelerometerUpdateInterval = 1 / 40.0;    // 40Hz
         [motionManager startAccelerometerUpdates];
     }
-        
+    if([motionManager isGyroAvailable] == YES)
+    {
+        motionManager.gyroUpdateInterval = 1 / 40.0;    // 40Hz
+        [motionManager startGyroUpdates];
+    }
+    
     window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
     viewController = [[ViewController alloc] init];
     [window setRootViewController:viewController];
@@ -901,6 +906,28 @@ int getUnicode(int key);
         *roll = r;
 }
 
+- (void)getRawAccelX:(float*)x Y:(float*)y Z:(float*)z
+{
+    CMAccelerometerData* accelerometerData = motionManager.accelerometerData;
+    if(accelerometerData != nil)
+    {
+        *x = -9.81f * accelerometerData.acceleration.x;
+        *y = -9.81f * accelerometerData.acceleration.y;
+        *z = -9.81f * accelerometerData.acceleration.z;
+    }
+}
+
+- (void)getRawGyroX:(float*)x Y:(float*)y Z:(float*)z
+{
+    CMGyroData* gyroData = motionManager.gyroData;
+    if(gyroData != nil)
+    {
+        *x = gyroData.rotationRate.x;
+        *y = gyroData.rotationRate.y;
+        *z = gyroData.rotationRate.z;
+    }
+}
+
 - (void)applicationWillResignActive:(UIApplication*)application
 {    
     [viewController stopUpdating];
@@ -1389,7 +1416,39 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
 {
     [__appDelegate getAccelerometerPitch:pitch roll:roll];
 }
-    
+
+void Platform::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    float x, y, z;
+    [__appDelegate getRawAccelX:&x Y:&y Z:&z];
+    if (accelX)
+    {
+        *accelX = x;
+    }
+    if (accelY)
+    {
+        *accelY = y;
+    }
+    if (accelZ)
+    {
+        *accelZ = z;
+    }
+
+    [__appDelegate getRawGyroX:&x Y:&y Z:&z];
+    if (gyroX)
+    {
+        *gyroX = x;
+    }
+    if (gyroY)
+    {
+        *gyroY = y;
+    }
+    if (gyroZ)
+    {
+        *gyroZ = z;
+    }
+}
+
 void Platform::getArguments(int* argc, char*** argv)
 {
     if (argc)

+ 51 - 0
gameplay/src/RenderState.cpp

@@ -13,6 +13,7 @@
 #define RS_DEPTH_TEST 8
 #define RS_DEPTH_WRITE 16
 #define RS_DEPTH_FUNC 32
+#define RS_CULL_FACE_SIDE 64
 
 namespace gameplay
 {
@@ -557,6 +558,11 @@ void RenderState::StateBlock::bindNoRestore()
             GL_ASSERT( glDisable(GL_CULL_FACE) );
         _defaultState->_cullFaceEnabled = _cullFaceEnabled;
     }
+    if ((_bits & RS_CULL_FACE_SIDE) && (_cullFaceSide != _defaultState->_cullFaceSide))
+    {
+        GL_ASSERT( glCullFace((GLenum)_cullFaceSide) );
+        _defaultState->_cullFaceSide = _cullFaceSide;
+    }
     if ((_bits & RS_DEPTH_TEST) && (_depthTestEnabled != _defaultState->_depthTestEnabled))
     {
         if (_depthTestEnabled) 
@@ -609,6 +615,12 @@ void RenderState::StateBlock::restore(long stateOverrideBits)
         _defaultState->_bits &= ~RS_CULL_FACE;
         _defaultState->_cullFaceEnabled = false;
     }
+    if (!(stateOverrideBits & RS_CULL_FACE_SIDE) && (_defaultState->_bits & RS_CULL_FACE_SIDE))
+    {
+        GL_ASSERT( glCullFace((GLenum)GL_BACK) );
+        _defaultState->_bits &= ~RS_CULL_FACE_SIDE;
+        _defaultState->_cullFaceSide = RenderState::CULL_FACE_SIDE_BACK;
+    }
     if (!(stateOverrideBits & RS_DEPTH_TEST) && (_defaultState->_bits & RS_DEPTH_TEST))
     {
         GL_ASSERT( glDisable(GL_DEPTH_TEST) );
@@ -655,6 +667,7 @@ void RenderState::StateBlock::cloneInto(StateBlock* state)
     state->_blendEnabled = _blendEnabled;
     state->_blendSrc = _blendSrc;
     state->_blendDst = _blendDst;
+    state->_cullFaceSide = _cullFaceSide;
     state->_bits = _bits;
 }
 
@@ -744,6 +757,26 @@ static RenderState::DepthFunction parseDepthFunc(const char* value)
     }
 }
 
+static RenderState::CullFaceSide parseCullFaceSide(const char* value)
+{
+    GP_ASSERT(value);
+
+    // Convert string to uppercase for comparison
+    std::string upper(value);
+    std::transform(upper.begin(), upper.end(), upper.begin(), (int(*)(int))toupper);
+    if (upper == "BACK")
+        return RenderState::CULL_FACE_SIDE_BACK;
+    else if (upper == "FRONT")
+        return RenderState::CULL_FACE_SIDE_FRONT;
+    else if (upper == "FRONT_AND_BACK")
+        return RenderState::CULL_FACE_SIDE_FRONT_AND_BACK;
+    else
+    {
+        GP_ERROR("Unsupported cull face side value (%s). Will default to BACK if errors are treated as warnings)", value);
+        return RenderState::CULL_FACE_SIDE_BACK;
+    }
+}
+
 void RenderState::StateBlock::setState(const char* name, const char* value)
 {
     GP_ASSERT(name);
@@ -764,6 +797,10 @@ void RenderState::StateBlock::setState(const char* name, const char* value)
     {
         setCullFace(parseBoolean(value));
     }
+    else if (strcmp(name, "cullFaceSide") == 0)
+    {
+        setCullFaceSide(parseCullFaceSide(value));
+    }
     else if (strcmp(name, "depthTest") == 0)
     {
         setDepthTest(parseBoolean(value));
@@ -836,6 +873,20 @@ void RenderState::StateBlock::setCullFace(bool enabled)
     }
 }
 
+void RenderState::StateBlock::setCullFaceSide(CullFaceSide side)
+{
+    _cullFaceSide = side;
+    if (_cullFaceSide == CULL_FACE_SIDE_BACK)
+    {
+        // Default cull side
+        _bits &= ~RS_CULL_FACE_SIDE;
+    }
+    else
+    {
+        _bits |= RS_CULL_FACE_SIDE;
+    }
+}
+
 void RenderState::StateBlock::setDepthTest(bool enabled)
 {
     _depthTestEnabled = enabled;

+ 20 - 0
gameplay/src/RenderState.h

@@ -169,6 +169,17 @@ public:
         DEPTH_ALWAYS = GL_ALWAYS
     };
 
+    /**
+     * Defines culling criteria for front-facing, back-facing and both-side 
+     * facets.
+     */
+    enum CullFaceSide
+    {
+        CULL_FACE_SIDE_BACK = GL_BACK,
+        CULL_FACE_SIDE_FRONT = GL_FRONT,
+        CULL_FACE_SIDE_FRONT_AND_BACK = GL_FRONT_AND_BACK
+    };
+
     /**
      * Defines a block of fixed-function render states that can be applied to a
      * RenderState object.
@@ -226,6 +237,14 @@ public:
          */
         void setCullFace(bool enabled);
 
+        /**
+         * Sets the side of the facets to cull.
+         *
+         * When not explicitly set, the default is to cull back-facing facets.
+         * @param side The side to cull.
+         */
+        void setCullFaceSide(CullFaceSide side);
+
         /**
          * Toggles depth testing.
          *
@@ -297,6 +316,7 @@ public:
         bool _blendEnabled;
         Blend _blendSrc;
         Blend _blendDst;
+        CullFaceSide _cullFaceSide;
         long _bits;
 
         static StateBlock* _defaultState;

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

@@ -753,6 +753,15 @@ void luaRegister_lua_Global()
         gameplay::ScriptUtil::registerConstantString("BLEND_ONE_MINUS_CONSTANT_ALPHA", "BLEND_ONE_MINUS_CONSTANT_ALPHA", scopePath);
         gameplay::ScriptUtil::registerConstantString("BLEND_SRC_ALPHA_SATURATE", "BLEND_SRC_ALPHA_SATURATE", scopePath);
     }
+    
+    // Register enumeration RenderState::CullFaceSide
+    {
+        std::vector<std::string> scopePath;
+        scopePath.push_back("RenderState");
+        gameplay::ScriptUtil::registerConstantString("CULL_FACE_SIDE_BACK", "CULL_FACE_SIDE_BACK", scopePath);
+        gameplay::ScriptUtil::registerConstantString("CULL_FACE_SIDE_FRONT", "CULL_FACE_SIDE_FRONT", scopePath);
+        gameplay::ScriptUtil::registerConstantString("CULL_FACE_SIDE_FRONT_AND_BACK", "CULL_FACE_SIDE_FRONT_AND_BACK", scopePath);
+    }
 
     // Register enumeration RenderState::DepthFunction.
     {
@@ -920,6 +929,8 @@ const char* lua_stringFromEnumGlobal(std::string& enumname, unsigned int value)
         return lua_stringFromEnum_RenderStateAutoBinding((RenderState::AutoBinding)value);
     if (enumname == "RenderState::Blend")
         return lua_stringFromEnum_RenderStateBlend((RenderState::Blend)value);
+    if (enumname == "RenderState::CullFaceSide")
+        return lua_stringFromEnum_RenderStateCullFaceSide((RenderState::CullFaceSide)value);
     if (enumname == "RenderState::DepthFunction")
         return lua_stringFromEnum_RenderStateDepthFunction((RenderState::DepthFunction)value);
     if (enumname == "Scene::DebugFlags")

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

@@ -36,6 +36,7 @@
 #include "lua_PropertiesType.h"
 #include "lua_RenderStateAutoBinding.h"
 #include "lua_RenderStateBlend.h"
+#include "lua_RenderStateCullFaceSide.h"
 #include "lua_RenderStateDepthFunction.h"
 #include "lua_SceneDebugFlags.h"
 #include "lua_TerrainFlags.h"

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

@@ -12,6 +12,7 @@
 #include "lua_RenderStateAutoBinding.h"
 #include "lua_RenderStateBlend.h"
 #include "lua_RenderStateDepthFunction.h"
+#include "lua_RenderStateCullFaceSide.h"
 
 namespace gameplay
 {

+ 35 - 0
gameplay/src/lua/lua_RenderStateCullFaceSide.cpp

@@ -0,0 +1,35 @@
+#include "Base.h"
+#include "lua_RenderStateCullFaceSide.h"
+
+namespace gameplay
+{
+
+static const char* enumStringEmpty = "";
+
+static const char* luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_BACK = "CULL_FACE_SIDE_BACK";
+static const char* luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_FRONT = "CULL_FACE_SIDE_FRONT";
+static const char* luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_FRONT_AND_BACK = "CULL_FACE_SIDE_FRONT_AND_BACK";
+
+RenderState::CullFaceSide lua_enumFromString_RenderStateCullFaceSide(const char* s)
+{
+    if (strcmp(s, luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_BACK) == 0)
+        return RenderState::CULL_FACE_SIDE_BACK;
+    if (strcmp(s, luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_FRONT) == 0)
+        return RenderState::CULL_FACE_SIDE_FRONT;
+    if (strcmp(s, luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_FRONT_AND_BACK) == 0)
+        return RenderState::CULL_FACE_SIDE_FRONT_AND_BACK;
+    return RenderState::CULL_FACE_SIDE_BACK;
+}
+
+const char* lua_stringFromEnum_RenderStateCullFaceSide(RenderState::CullFaceSide e)
+{
+    if (e == RenderState::CULL_FACE_SIDE_BACK)
+        return luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_BACK;
+    if (e == RenderState::CULL_FACE_SIDE_FRONT)
+        return luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_FRONT;
+    if (e == RenderState::CULL_FACE_SIDE_FRONT_AND_BACK)
+        return luaEnumString_RenderStateCullFaceSide_CULL_FACE_SIDE_FRONT_AND_BACK;
+    return enumStringEmpty;
+}
+
+}

+ 15 - 0
gameplay/src/lua/lua_RenderStateCullFaceSide.h

@@ -0,0 +1,15 @@
+#ifndef LUA_RENDERSTATECULLFACESIDE_H_
+#define LUA_RENDERSTATECULLFACESIDE_H_
+
+#include "RenderState.h"
+
+namespace gameplay
+{
+
+// Lua bindings for enum conversion functions for RenderState::CullFaceSide.
+RenderState::CullFaceSide lua_enumFromString_RenderStateCullFaceSide(const char* s);
+const char* lua_stringFromEnum_RenderStateCullFaceSide(RenderState::CullFaceSide e);
+
+}
+
+#endif

+ 38 - 0
gameplay/src/lua/lua_RenderStateStateBlock.cpp

@@ -12,6 +12,7 @@
 #include "lua_RenderStateAutoBinding.h"
 #include "lua_RenderStateBlend.h"
 #include "lua_RenderStateDepthFunction.h"
+#include "lua_RenderStateCullFaceSide.h"
 
 namespace gameplay
 {
@@ -28,6 +29,7 @@ void luaRegister_RenderStateStateBlock()
         {"setBlendDst", lua_RenderStateStateBlock_setBlendDst},
         {"setBlendSrc", lua_RenderStateStateBlock_setBlendSrc},
         {"setCullFace", lua_RenderStateStateBlock_setCullFace},
+        {"setCullFaceSide", lua_RenderStateStateBlock_setCullFaceSide},
         {"setDepthFunction", lua_RenderStateStateBlock_setDepthFunction},
         {"setDepthTest", lua_RenderStateStateBlock_setDepthTest},
         {"setDepthWrite", lua_RenderStateStateBlock_setDepthWrite},
@@ -365,6 +367,42 @@ int lua_RenderStateStateBlock_setCullFace(lua_State* state)
     return 0;
 }
 
+int lua_RenderStateStateBlock_setCullFaceSide(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_TSTRING || lua_type(state, 2) == LUA_TNIL))
+            {
+                // Get parameter 1 off the stack.
+                RenderState::CullFaceSide param1 = (RenderState::CullFaceSide)lua_enumFromString_RenderStateCullFaceSide(luaL_checkstring(state, 2));
+
+                RenderState::StateBlock* instance = getInstance(state);
+                instance->setCullFaceSide(param1);
+
+                return 0;
+            }
+
+
+            lua_pushstring(state, "lua_RenderStateStateBlock_setCullFaceSide - 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_RenderStateStateBlock_setDepthFunction(lua_State* state)
 {
     // Get the number of parameters.

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

@@ -14,6 +14,7 @@ int lua_RenderStateStateBlock_setBlend(lua_State* state);
 int lua_RenderStateStateBlock_setBlendDst(lua_State* state);
 int lua_RenderStateStateBlock_setBlendSrc(lua_State* state);
 int lua_RenderStateStateBlock_setCullFace(lua_State* state);
+int lua_RenderStateStateBlock_setCullFaceSide(lua_State* state);
 int lua_RenderStateStateBlock_setDepthFunction(lua_State* state);
 int lua_RenderStateStateBlock_setDepthTest(lua_State* state);
 int lua_RenderStateStateBlock_setDepthWrite(lua_State* state);

+ 60 - 1
samples/browser/src/InputSample.cpp

@@ -11,7 +11,8 @@
 static const char* keyString(int key);
 
 InputSample::InputSample()
-    :  _mouseString("No Mouse"), _font(NULL), _inputSampleControls(NULL), _mouseWheel(0), _crosshair(NULL)
+    :  _mouseString("No Mouse"), _font(NULL), _inputSampleControls(NULL), _mouseWheel(0), _crosshair(NULL),
+       _scene(NULL), _formNode(NULL), _formNodeParent(NULL)
 {
 }
 
@@ -44,6 +45,32 @@ void InputSample::initialize()
     _inputSampleControls->getControl("restoreMouseLabel")->setVisible(false);
 
     _mousePoint.set(-100, -100);
+
+    // Create a 3D form that responds to raw sensor inputs.
+    // For this, we will need a scene with a camera node.
+    Camera* camera = Camera::createPerspective(45.0f, (float)getWidth() / (float)getHeight(), 0.25f, 100.0f);
+    _scene = Scene::create();
+    Node* cameraNode = _scene->addNode("Camera");
+    cameraNode->setCamera(camera);
+    _scene->setActiveCamera(camera);
+    SAFE_RELEASE(camera);
+    _formNodeParent = _scene->addNode("FormParent");
+    _formNode = Node::create("Form");
+    _formNodeParent->addChild(_formNode);
+    Theme* theme = _inputSampleControls->getTheme();
+    Form* form = Form::create("testForm", theme->getStyle("basicContainer"));
+    form->setSize(225, 100);
+    Label* label = Label::create("sensorLabel", theme->getStyle("iconNoBorder"));
+    label->setPosition(25, 15);
+    label->setSize(175, 50);
+    label->setText("Raw sensor response (accel/gyro)");
+    form->addControl(label);
+    label->release();
+    _formNode->setScale(0.0015f, 0.0015f, 1.0f);
+    _formNodeRestPosition.set(0, 0, -1.5f);
+    _formNodeParent->setTranslation(_formNodeRestPosition);
+    _formNode->setTranslation(-0.2f, -0.2f, 0);
+    _formNode->setForm(form);
 }
 
 void InputSample::finalize()
@@ -54,6 +81,8 @@ void InputSample::finalize()
         displayKeyboard(false);
     }
 
+    SAFE_RELEASE(_scene);
+    SAFE_RELEASE(_formNode);
     SAFE_RELEASE(_inputSampleControls);
     SAFE_DELETE(_crosshair);
     SAFE_RELEASE(_font);
@@ -61,6 +90,34 @@ void InputSample::finalize()
 
 void InputSample::update(float elapsedTime)
 {
+    if (hasAccelerometer())
+    {
+        Vector3 accelRaw, gyroRaw;
+        getRawSensorValues(&accelRaw.x, &accelRaw.y, &accelRaw.z, &gyroRaw.x, &gyroRaw.y, &gyroRaw.z);
+
+        // Adjust for landscape mode
+        float temp = accelRaw.x;
+        accelRaw.x = -accelRaw.y;
+        accelRaw.y = temp;
+        temp = gyroRaw.x;
+        gyroRaw.x = -gyroRaw.y;
+        gyroRaw.y = temp;
+
+        // Respond to raw accelerometer inputs
+        Vector3 position;
+        _formNodeParent->getTranslation(&position);
+        position.smooth(_formNodeRestPosition - accelRaw*0.04f, elapsedTime, 100);
+        _formNodeParent->setTranslation(position);
+
+        // Respond to raw gyroscope inputs
+        Vector3 rotation;
+        float angle = _formNodeParent->getRotation(&rotation);
+        rotation *= angle;
+        rotation.smooth(gyroRaw*(-0.18f), elapsedTime, 220);
+        angle = rotation.length();
+        rotation.normalize();
+        _formNodeParent->setRotation(rotation, angle);
+    }
 }
 
 void InputSample::render(float elapsedTime)
@@ -157,6 +214,8 @@ void InputSample::render(float elapsedTime)
     }
     if (hasAccelerometer() && !_keyboardState)
     {
+        _formNode->getForm()->draw();
+
         sprintf(buffer, "Pitch: %f   Roll: %f", pitch, roll);
         _font->measureText(buffer, _font->getSize(), &width, &height);
         _font->drawText(buffer, getWidth() - width, getHeight() - height, fontColor, _font->getSize());

+ 4 - 0
samples/browser/src/InputSample.h

@@ -65,6 +65,10 @@ private:
     Rectangle _crosshairSrcRect;
     Vector2 _crosshairLowerLimit;
     Vector2 _crosshairUpperLimit;
+    Scene* _scene;
+    Node* _formNode;
+    Node* _formNodeParent;
+    Vector3 _formNodeRestPosition;
 };
 
 #endif

+ 5 - 0
samples/browser/src/Sample.cpp

@@ -185,6 +185,11 @@ void Sample::getAccelerometerValues(float* pitch, float* roll)
     Game::getInstance()->getAccelerometerValues(pitch, roll);
 }
 
+void Sample::getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ)
+{
+    Game::getInstance()->getRawSensorValues(accelX, accelY, accelZ, gyroX, gyroY, gyroZ);
+}
+
 void Sample::schedule(long timeOffset, TimeListener* timeListener, void* cookie)
 {
     Game::getInstance()->schedule(timeOffset, timeListener, cookie);

+ 1 - 0
samples/browser/src/Sample.h

@@ -61,6 +61,7 @@ public:
     bool isMultiTouch() const;
     bool hasAccelerometer() const;
     void getAccelerometerValues(float* pitch, float* roll);
+    void getRawSensorValues(float* accelX, float* accelY, float* accelZ, float* gyroX, float* gyroY, float* gyroZ);
     void schedule(long timeOffset, TimeListener* timeListener, void* cookie = 0);
 	void enableScriptCamera(bool enable);
     void setScriptCameraSpeed(float normal, float fast);

+ 32 - 32
samples/character/android/build.xml

@@ -62,43 +62,43 @@
     <target name="-post-compile">
         <copy file="../game.png.config" tofile="assets/game.config"/>
         <copy file="../res/common/arial40.gpb" tofile="assets/res/common/arial40.gpb"/>
-        <copy file="../res/design/backboard.png" tofile="assets/res/design/backboard.png"/>
-        <copy file="../res/design/basketball.png" tofile="assets/res/design/basketball.png"/>
-        <copy file="../res/design/basketballnet.png" tofile="assets/res/design/basketballnet.png"/>
-        <copy file="../res/design/book.png" tofile="assets/res/design/book.png"/>
-        <copy file="../res/design/bookshelf.png" tofile="assets/res/design/bookshelf.png"/>
+        <copy file="../res/design/backboard.png" tofile="assets/res/png/backboard.png"/>
+        <copy file="../res/design/basketball.png" tofile="assets/res/png/basketball.png"/>
+        <copy file="../res/design/basketballnet.png" tofile="assets/res/png/basketballnet.png"/>
+        <copy file="../res/design/book.png" tofile="assets/res/png/book.png"/>
+        <copy file="../res/design/bookshelf.png" tofile="assets/res/png/bookshelf.png"/>
         <copy file="../res/common/boy.animation" tofile="assets/res/common/boy.animation"/>
-        <copy file="../res/design/character.png" tofile="assets/res/design/character.png"/>
-        <copy file="../res/design/decals.png" tofile="assets/res/design/decals.png"/>
-        <copy file="../res/design/door.png" tofile="assets/res/design/door.png"/>
-        <copy file="../res/design/doorframe.png" tofile="assets/res/design/doorframe.png"/>
-        <copy file="../res/design/easel.png" tofile="assets/res/design/easel.png"/>
-        <copy file="../res/design/floor.png" tofile="assets/res/design/floor.png"/>
-        <copy file="../res/design/floortiles.png" tofile="assets/res/design/floortiles.png"/>
-        <copy file="../res/design/gamepad.png" tofile="assets/res/design/gamepad.png"/>
-        <copy file="../res/design/playtable.png" tofile="assets/res/design/playtable.png"/>
+        <copy file="../res/design/character.png" tofile="assets/res/png/character.png"/>
+        <copy file="../res/design/decals.png" tofile="assets/res/png/decals.png"/>
+        <copy file="../res/design/door.png" tofile="assets/res/png/door.png"/>
+        <copy file="../res/design/doorframe.png" tofile="assets/res/png/doorframe.png"/>
+        <copy file="../res/design/easel.png" tofile="assets/res/png/easel.png"/>
+        <copy file="../res/design/floor.png" tofile="assets/res/png/floor.png"/>
+        <copy file="../res/design/floortiles.png" tofile="assets/res/png/floortiles.png"/>
+        <copy file="../res/design/gamepad.png" tofile="assets/res/png/gamepad.png"/>
+        <copy file="../res/design/playtable.png" tofile="assets/res/png/playtable.png"/>
         <copy file="../res/common/scene.gpb" tofile="assets/res/common/scene.gpb"/>
         <copy file="../res/common/scene.material" tofile="assets/res/common/scene.material"/>
         <copy file="../res/common/scene.physics" tofile="assets/res/common/scene.physics"/>
         <copy file="../res/common/scene.scene" tofile="assets/res/common/scene.scene"/>
-        <copy file="../res/design/shadow.png" tofile="assets/res/design/shadow.png"/>
-        <copy file="../res/design/storageorganizer.png" tofile="assets/res/design/storageorganizer.png"/>
-        <copy file="../res/design/tableleg1.png" tofile="assets/res/design/tableleg1.png"/>
-        <copy file="../res/design/tableleg2.png" tofile="assets/res/design/tableleg2.png"/>
-        <copy file="../res/design/tableleg3.png" tofile="assets/res/design/tableleg3.png"/>
-        <copy file="../res/design/tableleg4.png" tofile="assets/res/design/tableleg4.png"/>
-        <copy file="../res/design/tabletop.png" tofile="assets/res/design/tabletop.png"/>
-        <copy file="../res/design/tiles.png" tofile="assets/res/design/tiles.png"/>
-        <copy file="../res/design/tilesn.png" tofile="assets/res/design/tilesn.png"/>
-        <copy file="../res/design/toybox.png" tofile="assets/res/design/toybox.png"/>
-        <copy file="../res/design/walleast.png" tofile="assets/res/design/walleast.png"/>
-        <copy file="../res/design/wallnorth.png" tofile="assets/res/design/wallnorth.png"/>
-        <copy file="../res/design/walloverhang.png" tofile="assets/res/design/walloverhang.png"/>
-        <copy file="../res/design/wallsouth.png" tofile="assets/res/design/wallsouth.png"/>
-        <copy file="../res/design/wallwest.png" tofile="assets/res/design/wallwest.png"/>
-        <copy file="../res/design/windowledge.png" tofile="assets/res/design/windowledge.png"/>
-        <copy file="../res/design/wood.png" tofile="assets/res/design/wood.png"/>
-        <copy file="../res/design/woodn.png" tofile="assets/res/design/woodn.png"/>
+        <copy file="../res/design/shadow.png" tofile="assets/res/png/shadow.png"/>
+        <copy file="../res/design/storageorganizer.png" tofile="assets/res/png/storageorganizer.png"/>
+        <copy file="../res/design/tableleg1.png" tofile="assets/res/png/tableleg1.png"/>
+        <copy file="../res/design/tableleg2.png" tofile="assets/res/png/tableleg2.png"/>
+        <copy file="../res/design/tableleg3.png" tofile="assets/res/png/tableleg3.png"/>
+        <copy file="../res/design/tableleg4.png" tofile="assets/res/png/tableleg4.png"/>
+        <copy file="../res/design/tabletop.png" tofile="assets/res/png/tabletop.png"/>
+        <copy file="../res/design/tiles.png" tofile="assets/res/png/tiles.png"/>
+        <copy file="../res/design/tilesn.png" tofile="assets/res/png/tilesn.png"/>
+        <copy file="../res/design/toybox.png" tofile="assets/res/png/toybox.png"/>
+        <copy file="../res/design/walleast.png" tofile="assets/res/png/walleast.png"/>
+        <copy file="../res/design/wallnorth.png" tofile="assets/res/png/wallnorth.png"/>
+        <copy file="../res/design/walloverhang.png" tofile="assets/res/png/walloverhang.png"/>
+        <copy file="../res/design/wallsouth.png" tofile="assets/res/png/wallsouth.png"/>
+        <copy file="../res/design/wallwest.png" tofile="assets/res/png/wallwest.png"/>
+        <copy file="../res/design/windowledge.png" tofile="assets/res/png/windowledge.png"/>
+        <copy file="../res/design/wood.png" tofile="assets/res/png/wood.png"/>
+        <copy file="../res/design/woodn.png" tofile="assets/res/png/woodn.png"/>
         <copy todir="assets/res/common">
             <fileset dir="../res/common"/>
         </copy>