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

Error handling improvements (6 of 7 - Game and Platform).
Fixes error/warning/assertion printing for Android.
Updated gameplay and sample04-particles Android source/resource files.
Fixes out-of-date asset problem on Android (where the files on the file system corresponding to an asset in the APK got out of sync).
Adds FileSystem::fileExists function.

Work on issue #330.

Chris Culy 13 лет назад
Родитель
Сommit
c28860fd66

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

@@ -16,7 +16,7 @@ LOCAL_PATH := $(call my-dir)/../../src
 
 include $(CLEAR_VARS)
 LOCAL_MODULE    := libgameplay
-LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Bundle.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp FlowLayout.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp Image.cpp Joint.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsMotionState.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
+LOCAL_SRC_FILES := AbsoluteLayout.cpp Animation.cpp AnimationClip.cpp AnimationController.cpp AnimationTarget.cpp AnimationValue.cpp AudioBuffer.cpp AudioController.cpp AudioListener.cpp AudioSource.cpp BoundingBox.cpp BoundingSphere.cpp Bundle.cpp Button.cpp Camera.cpp CheckBox.cpp Container.cpp Control.cpp Curve.cpp DebugNew.cpp DepthStencilTarget.cpp Effect.cpp FileSystem.cpp FlowLayout.cpp Font.cpp Form.cpp FrameBuffer.cpp Frustum.cpp Game.cpp gameplay-main-android.cpp Image.cpp Joint.cpp Label.cpp Layout.cpp Light.cpp Material.cpp MaterialParameter.cpp Matrix.cpp Mesh.cpp MeshBatch.cpp MeshPart.cpp MeshSkin.cpp Model.cpp Node.cpp ParticleEmitter.cpp Pass.cpp PhysicsCharacter.cpp PhysicsCollisionObject.cpp PhysicsCollisionShape.cpp PhysicsConstraint.cpp PhysicsController.cpp PhysicsFixedConstraint.cpp PhysicsGenericConstraint.cpp PhysicsGhostObject.cpp PhysicsHingeConstraint.cpp PhysicsMotionState.cpp PhysicsRigidBody.cpp PhysicsSocketConstraint.cpp PhysicsSpringConstraint.cpp Plane.cpp PlatformAndroid.cpp Properties.cpp Quaternion.cpp RadioButton.cpp Ray.cpp Rectangle.cpp Ref.cpp RenderState.cpp RenderTarget.cpp Scene.cpp SceneLoader.cpp ScrollLayout.cpp Slider.cpp SpriteBatch.cpp Technique.cpp TextBox.cpp Texture.cpp Theme.cpp ThemeStyle.cpp Transform.cpp Vector2.cpp Vector3.cpp Vector4.cpp VertexAttributeBinding.cpp VertexFormat.cpp VerticalLayout.cpp
 LOCAL_CFLAGS := -D__ANDROID__ -I"../../external-deps/bullet/include" -I"../../external-deps/libpng/include" -I"../../external-deps/oggvorbis/include" -I"../../external-deps/openal/include"
 LOCAL_STATIC_LIBRARIES := android_native_app_glue
 

+ 16 - 10
gameplay/src/Base.h

@@ -51,6 +51,13 @@ namespace gameplay
 extern void printError(const char* format, ...);
 }
 
+// Current function macro.
+#ifdef WIN32
+#define __current__func__ __FUNCTION__
+#else
+#define __current__func__ __func__
+#endif
+
 // Assert macros.
 #ifdef _DEBUG
 #ifdef WIN32
@@ -58,11 +65,10 @@ extern void printError(const char* format, ...);
 #else
 #define GP_FORCE_ASSERTION_FAILURE do { assert(0); } while (0)
 #endif
-
 #define GP_ASSERT(expression) do { \
     if (!(expression)) \
     { \
-        printError("%s -- Assertion '" #expression "' failed.\n", __FUNCTION__); \
+        printError("%s -- Assertion '" #expression "' failed.\n", __current__func__); \
         GP_FORCE_ASSERTION_FAILURE; \
     } } while (0)
 #else
@@ -73,7 +79,7 @@ extern void printError(const char* format, ...);
 // Error macro.
 #define GP_ERROR(...) do \
     { \
-        printError("%s -- ", __FUNCTION__); \
+        printError("%s -- ", __current__func__); \
         printError(__VA_ARGS__); \
         printError("\n"); \
         GP_FORCE_ASSERTION_FAILURE; \
@@ -83,7 +89,7 @@ extern void printError(const char* format, ...);
 // Warning macro.
 #define GP_WARN(...) do \
     { \
-        printError("%s -- ", __FUNCTION__); \
+        printError("%s -- ", __current__func__); \
         printError(__VA_ARGS__); \
         printError("\n"); \
     } while (0)
@@ -241,12 +247,12 @@ typedef GLuint RenderBufferHandle;
 #ifdef NDEBUG
 #define GL_ASSERT( gl_code ) gl_code
 #else
-#define GL_ASSERT( gl_code ) \
+#define GL_ASSERT( gl_code ) do \
     { \
         gl_code; \
         __gl_error_code = glGetError(); \
         GP_ASSERT(__gl_error_code == GL_NO_ERROR); \
-    }
+    } while(0)
 #endif
 
 /**
@@ -258,7 +264,7 @@ typedef GLuint RenderBufferHandle;
  * macro can be used afterwards to check whether a GL error was
  * encountered executing the specified code.
  */
-#define GL_CHECK( gl_code ) \
+#define GL_CHECK( gl_code ) do \
     { \
         while (glGetError() != GL_NO_ERROR) ; \
         gl_code; \
@@ -267,7 +273,7 @@ typedef GLuint RenderBufferHandle;
         { \
             GP_ERROR(#gl_code ": %d", (int)__gl_error_code); \
         } \
-    }
+    } while(0)
 
 // Global variable to hold GL errors
 extern GLenum __gl_error_code;
@@ -284,7 +290,7 @@ extern GLenum __gl_error_code;
  * The AL_LAST_ERROR macro can be used afterwards to check whether a AL error was
  * encountered executing the specified code.
  */
-#define AL_CHECK( al_code ) \
+#define AL_CHECK( al_code ) do \
     { \
         while (alGetError() != AL_NO_ERROR) ; \
         al_code; \
@@ -293,7 +299,7 @@ extern GLenum __gl_error_code;
         { \
             GP_ERROR(#al_code ": %d", (int)__al_error_code); \
         } \
-    }
+    } while(0)
 
 // Global variable to hold AL errors
 extern ALenum __al_error_code;

+ 86 - 35
gameplay/src/FileSystem.cpp

@@ -2,13 +2,19 @@
 #include "FileSystem.h"
 #include "Properties.h"
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #ifdef WIN32
     #include <windows.h>
     #include <tchar.h>
     #include <stdio.h>
+    #define gp_stat _stat
+    #define gp_stat_struct struct stat
 #else
     #include <dirent.h>
-    #include <sys/stat.h>
+    #define gp_stat stat
+    #define gp_stat_struct struct stat
 #endif
 
 #ifdef __ANDROID__
@@ -19,9 +25,10 @@ extern AAssetManager* __assetManager;
 namespace gameplay
 {
 
+// Creates a file on the file system from the specified asset (Android-specific).
+static void createFileFromAsset(const char* path);
+
 #ifdef __ANDROID__
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
 
 void makepath(std::string path, int mode)
@@ -109,6 +116,8 @@ void FileSystem::loadResourceAliases(Properties* properties)
 
 const char* FileSystem::resolvePath(const char* path)
 {
+    GP_ASSERT(path);
+
     size_t len = strlen(path);
     if (len > 1 && path[0] == '@')
     {
@@ -191,49 +200,40 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
 #endif
 }
 
-FILE* FileSystem::openFile(const char* path, const char* mode)
+bool FileSystem::fileExists(const char* path)
 {
     GP_ASSERT(path);
 
     std::string fullPath(__resourcePath);
     fullPath += resolvePath(path);
 
-#ifdef __ANDROID__
-    std::string directoryPath = fullPath.substr(0, fullPath.rfind('/'));
-    struct stat s;
-    if (stat(directoryPath.c_str(), &s) != 0)
-        makepath(directoryPath.c_str(), 0777);
+    createFileFromAsset(path);
 
+    gp_stat_struct s;
+// Win32 doesn't support an asset or bundle definitions.
+#ifdef WIN32
     if (stat(fullPath.c_str(), &s) != 0)
     {
-        AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
-        if (asset)
-        {
-            const void* data = AAsset_getBuffer(asset);
-            int length = AAsset_getLength(asset);
-            FILE* file = fopen(fullPath.c_str(), "wb");
-            if (file != NULL)
-            {
-                int ret = fwrite(data, sizeof(unsigned char), length, file);
-                if (fclose(file) != 0)
-                {
-                    GP_ERROR("Failed to close file on file system created from APK asset.");
-                    return NULL;
-                }
-                if (ret != length)
-                {
-                    GP_ERROR("Failed to write all data from APK asset to file on file system.");
-                    return NULL;
-                }
-            }
-            else
-            {
-                GP_ERROR("Failed to create file on file system from APK asset.");
-                return NULL;
-            }
-        }
+        fullPath = __resourcePath;
+        fullPath += "../../gameplay/";
+        fullPath += path;
+        
+        return stat(fullPath.c_str(), &s) == 0;
     }
+    return true;
+#else
+    return stat(fullPath.c_str(), &s) == 0;
 #endif
+}
+
+FILE* FileSystem::openFile(const char* path, const char* mode)
+{
+    GP_ASSERT(path);
+
+    std::string fullPath(__resourcePath);
+    fullPath += resolvePath(path);
+
+    createFileFromAsset(path);
     
     FILE* fp = fopen(fullPath.c_str(), mode);
     
@@ -301,4 +301,55 @@ char* FileSystem::readAll(const char* filePath, int* fileSize)
     return buffer;
 }
 
+void createFileFromAsset(const char* path)
+{
+#ifdef __ANDROID__
+    static std::set<std::string> upToDateAssets;
+
+    GP_ASSERT(path);
+    std::string fullPath(__resourcePath);
+    fullPath += FileSystem::resolvePath(path);
+
+    std::string directoryPath = fullPath.substr(0, fullPath.rfind('/'));
+    struct stat s;
+    if (stat(directoryPath.c_str(), &s) != 0)
+        makepath(directoryPath.c_str(), 0777);
+
+    // To ensure that the files on the file system corresponding to the assets in the APK bundle
+    // are always up to date (and in sync), we copy them from the APK to the file system once
+    // for each time the process (game) runs.
+    if (upToDateAssets.find(fullPath) == upToDateAssets.end())
+    {
+        AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
+        if (asset)
+        {
+            const void* data = AAsset_getBuffer(asset);
+            int length = AAsset_getLength(asset);
+            FILE* file = fopen(fullPath.c_str(), "wb");
+            if (file != NULL)
+            {
+                int ret = fwrite(data, sizeof(unsigned char), length, file);
+                if (fclose(file) != 0)
+                {
+                    GP_ERROR("Failed to close file on file system created from APK asset '%s'.", path);
+                    return;
+                }
+                if (ret != length)
+                {
+                    GP_ERROR("Failed to write all data from APK asset '%s' to file on file system.", path);
+                    return;
+                }
+            }
+            else
+            {
+                GP_ERROR("Failed to create file on file system from APK asset '%s'.", path);
+                return;
+            }
+
+            upToDateAssets.insert(fullPath);
+        }
+    }
+#endif
+}
+
 }

+ 8 - 0
gameplay/src/FileSystem.h

@@ -92,6 +92,14 @@ public:
      */
     static bool listFiles(const char* dirPath, std::vector<std::string>& files);
 
+    /**
+     * Checks if the file at the given path exists.
+     * 
+     * @param path The path to the file.
+     * @return <code>true</code> if the file exists; <code>false</code> otherwise.
+     */
+    static bool fileExists(const char* path);
+
     /**
      * Opens the specified file.
      *

+ 30 - 16
gameplay/src/Game.cpp

@@ -34,7 +34,7 @@ Game::~Game()
 {
     // Do not call any virtual functions from the destructor.
     // Finalization is done from outside this class.
-    delete _timeEvents;
+    SAFE_DELETE(_timeEvents);
 #ifdef GAMEPLAY_MEM_LEAK_DETECTION
     Ref::printLeaks();
     printMemoryLeaks();
@@ -114,6 +114,10 @@ void Game::shutdown()
     // Call user finalization.
     if (_state != UNINITIALIZED)
     {
+        GP_ASSERT(_animationController);
+        GP_ASSERT(_audioController);
+        GP_ASSERT(_physicsController);
+
         Platform::signalShutdown();
         finalize();
 
@@ -140,6 +144,10 @@ void Game::pause()
 {
     if (_state == RUNNING)
     {
+        GP_ASSERT(_animationController);
+        GP_ASSERT(_audioController);
+        GP_ASSERT(_physicsController);
+
         _state = PAUSED;
         _pausedTimeLast = Platform::getAbsoluteTime();
         _animationController->pause();
@@ -152,6 +160,10 @@ void Game::resume()
 {
     if (_state == PAUSED)
     {
+        GP_ASSERT(_animationController);
+        GP_ASSERT(_audioController);
+        GP_ASSERT(_physicsController);
+
         _state = RUNNING;
         _pausedTimeTotal += Platform::getAbsoluteTime() - _pausedTimeLast;
         _animationController->resume();
@@ -175,6 +187,10 @@ void Game::frame()
 
     if (_state == Game::RUNNING)
     {
+        GP_ASSERT(_animationController);
+        GP_ASSERT(_audioController);
+        GP_ASSERT(_physicsController);
+
         // Update Time.
         static long lastFrameTime = Game::getGameTime();
         long frameTime = Game::getGameTime();
@@ -288,7 +304,7 @@ void Game::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactI
 
 void Game::schedule(long timeOffset, TimeListener* timeListener, void* cookie)
 {
-    GP_ASSERT(timeListener);
+    GP_ASSERT(_timeEvents);
     TimeEvent timeEvent(getGameTime() + timeOffset, timeListener, cookie);
     _timeEvents->push(timeEvent);
 }
@@ -300,6 +316,10 @@ bool Game::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
 
 void Game::updateOnce()
 {
+    GP_ASSERT(_animationController);
+    GP_ASSERT(_audioController);
+    GP_ASSERT(_physicsController);
+
     // Update Time.
     static long lastFrameTime = Game::getGameTime();
     long frameTime = Game::getGameTime();
@@ -325,22 +345,15 @@ void Game::loadConfig()
     if (_properties == NULL)
     {
         // Try to load custom config from file.
-        // Check if file exists.
-        FILE* file = FileSystem::openFile("game.config", "rb");
-        if (file)
+        if (FileSystem::fileExists("game.config"))
         {
-            fclose(file);
             _properties = Properties::create("game.config");
+            
+            // Load filesystem aliases.
+            Properties* aliases = _properties->getNamespace("aliases", true);
+            if (aliases)
+                FileSystem::loadResourceAliases(aliases);
         }
-        else
-        {
-            _properties = new Properties();
-        }
-
-        // Load filesystem aliases
-        Properties* aliases = _properties->getNamespace("aliases", true);
-        if (aliases)
-            FileSystem::loadResourceAliases(aliases);
     }
 }
 
@@ -353,7 +366,8 @@ void Game::fireTimeEvents(long frameTime)
         {
             break;
         }
-        timeEvent->listener->timeEvent(frameTime - timeEvent->time, timeEvent->cookie);
+        if (timeEvent->listener)
+            timeEvent->listener->timeEvent(frameTime - timeEvent->time, timeEvent->cookie);
         _timeEvents->pop();
     }
 }

+ 1 - 0
gameplay/src/Game.inl

@@ -47,6 +47,7 @@ inline PhysicsController* Game::getPhysicsController() const
 template <class T>
 void Game::renderOnce(T* instance, void (T::*method)(void*), void* cookie)
 {
+    GP_ASSERT(instance);
     (instance->*method)(cookie);
     Platform::swapBuffers();
 }

+ 1 - 1
gameplay/src/Matrix.cpp

@@ -116,7 +116,7 @@ void Matrix::createPerspective(float fieldOfView, float aspectRatio,
 
     float f_n = 1.0f / (zFarPlane - zNearPlane);
     float theta = MATH_DEG_TO_RAD(fieldOfView) * 0.5f;
-    if (abs(fmod(theta, MATH_PIOVER2)) < MATH_EPSILON)
+    if (fabs(fmod(theta, MATH_PIOVER2)) < MATH_EPSILON)
     {
         GP_ERROR("Invalid field of view value (%d) causes attempted calculation tan(%d), which is undefined.", fieldOfView, theta);
         return;

+ 33 - 14
gameplay/src/PlatformAndroid.cpp

@@ -11,7 +11,6 @@
 #include <android_native_app_glue.h>
 
 #include <android/log.h>
-#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
 
 // Externally referenced global variables.
 struct android_app* __state;
@@ -50,19 +49,22 @@ namespace gameplay
 
 static long timespec2millis(struct timespec *a)
 {
+    GP_ASSERT(a);
     return a->tv_sec*1000 + a->tv_nsec/1000000;
 }
 
 extern void printError(const char* format, ...)
 {
+    GP_ASSERT(format);
     va_list argptr;
     va_start(argptr, format);
-    LOGI(format, argptr);
+    __android_log_vprint(ANDROID_LOG_INFO, "gameplay-native-activity", format, argptr);
     va_end(argptr);
 }
 
 static EGLenum checkErrorEGL(const char* msg)
 {
+    GP_ASSERT(msg);
     static const char* errmsg[] =
     {
         "EGL function succeeded",
@@ -82,7 +84,7 @@ static EGLenum checkErrorEGL(const char* msg)
         "EGL power management event has occurred",
     };
     EGLenum error = eglGetError();
-    LOGI("%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
+    printError("%s: %s.", msg, errmsg[error - EGL_SUCCESS]);
     return error;
 }
 
@@ -232,17 +234,21 @@ static void displayKeyboard(android_app* state, bool show)
     // ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
     // ANativeActivity_hideSoftInput(state->activity, ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY);
     
+    GP_ASSERT(state && state->activity && state->activity->vm);
+
     // Show or hide the keyboard by calling the appropriate Java method through JNI instead.
-    jint result;
     jint flags = 0;
     JavaVM* jvm = state->activity->vm;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
-    jvm->AttachCurrentThread(&env, NULL);
+    jint result = jvm->AttachCurrentThread(&env, NULL);
     if (result == JNI_ERR)
-    { 
+    {
+        GP_ERROR("Failed to retrieve JVM environment to display keyboard.");
         return; 
-    } 
+    }
+    GP_ASSERT(env);
+
     // Retrieves NativeActivity. 
     jobject lNativeActivity = state->activity->clazz;
     jclass ClassNativeActivity = env->GetObjectClass(lNativeActivity);
@@ -564,7 +570,7 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
         switch (action & AMOTION_EVENT_ACTION_MASK)
         {
             case AMOTION_EVENT_ACTION_DOWN:
-                // Primary pointer down
+                // Primary pointer down.
                 pointerId = AMotionEvent_getPointerId(event, 0);
                 gameplay::Platform::touchEventInternal(Touch::TOUCH_PRESS, AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0), pointerId);
                 __primaryTouchId = pointerId;
@@ -578,7 +584,7 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
                 __primaryTouchId = -1;
                 break;
             case AMOTION_EVENT_ACTION_POINTER_DOWN:
-                // Non-primary pointer down
+                // Non-primary pointer down.
                 if (__multiTouch)
                 {
                     pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
@@ -718,15 +724,23 @@ Platform* Platform::create(Game* game)
 
 int Platform::enterMessagePump()
 {
+    GP_ASSERT(__state && __state->activity && __state->activity->vm);
+
     __initialized = false;
     __suspended = false;
 
     // Get the android application's activity.
     ANativeActivity* activity = __state->activity;
     JavaVM* jvm = __state->activity->vm;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jvm->GetEnv((void **)&env, JNI_VERSION_1_6);
-    jvm->AttachCurrentThread(&env, NULL);
+    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);
 
     // Get the package name for this app from Java.
     jclass clazz = env->GetObjectClass(activity->clazz);
@@ -745,7 +759,7 @@ int Platform::enterMessagePump()
     FileSystem::setResourcePath(assetsPath.c_str());    
         
     // Get the asset manager to get the resources from the .apk file.
-    __assetManager = __state->activity->assetManager; 
+    __assetManager = activity->assetManager; 
     
     // Set the event call back functions.
     __state->onAppCmd = engine_handle_cmd;
@@ -893,16 +907,21 @@ void Platform::getAccelerometerValues(float* pitch, float* roll)
     }
     else
     {
-        // 0
         tx = __sensorEvent.acceleration.x;
         ty = __sensorEvent.acceleration.y;
     }
     tz = __sensorEvent.acceleration.z;
 
     if (pitch != NULL)
+    {
+        GP_ASSERT(tx * tx + tz * tz);
         *pitch = -atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
+    }
     if (roll != NULL)
+    {
+        GP_ASSERT(ty * ty + tz * tz);
         *roll = -atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
+    }
 }
 
 void Platform::swapBuffers()

+ 110 - 33
gameplay/src/PlatformMacOSX.mm

@@ -15,11 +15,11 @@ using namespace std;
 using namespace gameplay;
 
 // Default to 720p
-#define WINDOW_WIDTH    1280
-#define WINDOW_HEIGHT   720
+static int __width = 1280;
+static int __height = 720;
 
-static const float ACCELEROMETER_FACTOR_X = 90.0f / WINDOW_WIDTH;
-static const float ACCELEROMETER_FACTOR_Y = 90.0f / WINDOW_HEIGHT;
+static float ACCELEROMETER_FACTOR_X = 90.0f / __width;
+static float ACCELEROMETER_FACTOR_Y = 90.0f / __height;
 
 static long __timeStart;
 static long __timeAbsolute;
@@ -33,6 +33,8 @@ static bool __leftMouseDown = false;
 static bool __rightMouseDown = false;
 static bool __otherMouseDown = false;
 static bool __shiftDown = false;
+static char* __title = NULL;
+static bool __fullscreen = false;
 
 
 long getMachTimeInMilliseconds()
@@ -44,6 +46,7 @@ long getMachTimeInMilliseconds()
         (void) mach_timebase_info(&s_timebase_info);
     
     // mach_absolute_time() returns billionth of seconds, so divide by one million to get milliseconds
+    GP_ASSERT(kOneMillion * s_timebase_info.denom);
     return (long)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
 }
 
@@ -107,7 +110,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 - (id) initWithFrame: (NSRect) frame
 {    
-    NSOpenGLPixelFormatAttribute attrs[] = 
+    NSOpenGLPixelFormatAttribute windowedAttrs[] = 
     {
         NSOpenGLPFAAccelerated,
         NSOpenGLPFADoubleBuffer,
@@ -117,6 +120,18 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
         NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
         0
     };
+    NSOpenGLPixelFormatAttribute fullscreenAttrs[] = 
+    {
+        NSOpenGLPFADoubleBuffer,
+        NSOpenGLPFAScreenMask, (NSOpenGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID()),
+        NSOpenGLPFAFullScreen,
+        NSOpenGLPFAColorSize, 32,
+        NSOpenGLPFADepthSize, 24,
+        NSOpenGLPFAAlphaSize, 8,
+        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
+        0
+    };
+    NSOpenGLPixelFormatAttribute* attrs = __fullscreen ? fullscreenAttrs : windowedAttrs;
     
     NSOpenGLPixelFormat* pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
     if (!pf)
@@ -135,14 +150,14 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 {
     [super prepareOpenGL];
     
-    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
-    NSString* path = [bundlePath stringByAppendingString:@"/Contents/Resources/"];
-    FileSystem::setResourcePath([path cStringUsingEncoding:NSASCIIStringEncoding]);
     _game->run();
     
-    [[self window] setLevel: NSFloatingWindowLevel];
+    if (__fullscreen)
+        [[self window] setLevel: NSMainMenuWindowLevel+1];
+    else
+        [[self window] setLevel: NSFloatingWindowLevel];
     [[self window] makeKeyAndOrderFront: self];
-    [[self window] setTitle: [NSString stringWithUTF8String: ""]];
+    [[self window] setTitle: [NSString stringWithUTF8String: __title ? __title : ""]];
     
     // Make all the OpenGL calls to setup rendering and build the necessary rendering objects
     [[self openGLContext] makeCurrentContext];
@@ -160,6 +175,10 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     CGLPixelFormatObj cglPixelFormat = (CGLPixelFormatObj)[[self pixelFormat] CGLPixelFormatObj];
     CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
     
+    GLint dim[2] = {__width, __height};
+    CGLSetParameter(cglContext, kCGLCPSurfaceBackingSize, dim);
+    CGLEnable(cglContext, kCGLCESurfaceBackingSize);
+    
     // Activate the display link
     CVDisplayLinkStart(displayLink);
 }
@@ -204,20 +223,20 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     __leftMouseDown = true;
-    [self mouse: Mouse::MOUSE_PRESS_LEFT_BUTTON orTouchEvent: Touch::TOUCH_PRESS x: point.x y: WINDOW_HEIGHT - point.y s: 0];
+    [self mouse: Mouse::MOUSE_PRESS_LEFT_BUTTON orTouchEvent: Touch::TOUCH_PRESS x: point.x y: __height - point.y s: 0];
 }
 
 - (void) mouseUp: (NSEvent*) event
 {
      NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     __leftMouseDown = false;
-    [self mouse: Mouse::MOUSE_RELEASE_LEFT_BUTTON orTouchEvent: Touch::TOUCH_RELEASE x: point.x y: WINDOW_HEIGHT - point.y s: 0];
+    [self mouse: Mouse::MOUSE_RELEASE_LEFT_BUTTON orTouchEvent: Touch::TOUCH_RELEASE x: point.x y: __height - point.y s: 0];
 }
 
 - (void)mouseMoved:(NSEvent *) event 
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, __height - point.y, 0);
 }
 
 - (void) mouseDragged: (NSEvent*) event
@@ -225,7 +244,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
      NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     if (__leftMouseDown)
     {
-        [self mouse: Mouse::MOUSE_MOVE orTouchEvent: Touch::TOUCH_MOVE x: point.x y: WINDOW_HEIGHT - point.y s: 0];
+        [self mouse: Mouse::MOUSE_MOVE orTouchEvent: Touch::TOUCH_MOVE x: point.x y: __height - point.y s: 0];
     }
 }
 
@@ -234,15 +253,15 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __rightMouseDown = true;
      NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
     __lx = point.x;
-    __ly = WINDOW_HEIGHT - point.y;    
-    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    __ly = __height - point.y;    
+    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, __height - point.y, 0);
 }
 
 - (void) rightMouseUp: (NSEvent*) event
 {
    __rightMouseDown = false;
     NSPoint point = [event locationInWindow];
-    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, __height - point.y, 0);
 }
 
 - (void) rightMouseDragged: (NSEvent*) event
@@ -252,7 +271,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     {
         // Update the pitch and roll by adding the scaled deltas.
         __roll += (float)(point.x - __lx) * ACCELEROMETER_FACTOR_X;
-        __pitch -= -(float)(point.y - (WINDOW_HEIGHT - __ly)) * ACCELEROMETER_FACTOR_Y;
+        __pitch -= -(float)(point.y - (__height - __ly)) * ACCELEROMETER_FACTOR_Y;
     
         // Clamp the values to the valid range.
         __roll = max(min(__roll, 90.0f), -90.0f);
@@ -260,32 +279,32 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     
         // Update the last X/Y values.
         __lx = point.x;
-        __ly = (WINDOW_HEIGHT - point.y);
+        __ly = (__height - point.y);
     }
     
     // In right-mouse case, whether __rightMouseDown is true or false
     // this should not matter, mouse move is still occuring
-    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, __height - point.y, 0);
 }
 
 - (void)otherMouseDown: (NSEvent *) event 
 {
     __otherMouseDown = true;
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    _game->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    _game->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, point.x, __height - point.y, 0);
 }
 
 - (void)otherMouseUp: (NSEvent *) event 
 {
     __otherMouseDown = false;
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    _game->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, point.x, __height - point.y, 0);
 }
 
 - (void)otherMouseDragged: (NSEvent *) event 
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, __height - point.y, 0);
 }
 
 - (void) mouseEntered: (NSEvent*)event
@@ -296,7 +315,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 - (void)scrollWheel: (NSEvent *) event 
 {
     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
-    Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, point.x, WINDOW_HEIGHT - point.y, (int)([event deltaY] * 10.0f));
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, point.x, __height - point.y, (int)([event deltaY] * 10.0f));
 }
 
 - (void) mouseExited: (NSEvent*)event
@@ -557,12 +576,25 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
 
 @end
 
+@interface FullscreenWindow : NSWindow
+{ 
+}
+@end
+
+@implementation FullscreenWindow
+- (BOOL)canBecomeKeyWindow
+{
+    return YES;
+}
+@end
+
 
 namespace gameplay
 {
 
 extern void printError(const char* format, ...)
 {
+    GP_ASSERT(format);
     va_list argptr;
     va_start(argptr, format);
     vfprintf(stderr, format, argptr);
@@ -591,10 +623,40 @@ Platform* Platform::create(Game* game)
 
 int Platform::enterMessagePump()
 {
+    NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
+    NSString* path = [bundlePath stringByAppendingString:@"/Contents/Resources/"];
+    FileSystem::setResourcePath([path cStringUsingEncoding:NSASCIIStringEncoding]);
+    
+    // Read window settings from config.
+    if (_game->getConfig())
+    {
+        Properties* config = _game->getConfig()->getNamespace("window", true);
+        if (config)
+        {
+            // Read window title.
+            __title = const_cast<char *>(config->getString("title"));
+
+            // Read window size.
+            int width = config->getInt("width");
+            if (width != 0)
+                __width = width;
+            int height = config->getInt("height");
+            if (height != 0)
+                __height = height;
+
+            // Read fullscreen state.
+            __fullscreen = config->getBool("fullscreen");
+        }
+    }
+
+    // Set the scale factors for the mouse movement used to simulate the accelerometer.
+    ACCELEROMETER_FACTOR_X = 90.0f / __width;
+    ACCELEROMETER_FACTOR_Y = 90.0f / __height;
+
     NSAutoreleasePool* pool = [NSAutoreleasePool new];
     NSApplication* app = [NSApplication sharedApplication];
     NSRect screenBounds = [[NSScreen mainScreen] frame];
-    NSRect viewBounds = NSMakeRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    NSRect viewBounds = NSMakeRect(0, 0, __width, __height);
     
     __view = [[View alloc] initWithFrame:viewBounds];
     
@@ -603,11 +665,23 @@ int Platform::enterMessagePump()
                                  viewBounds.size.width, 
                                  viewBounds.size.height);
     
-    NSWindow* window = [[NSWindow alloc]
-                        initWithContentRect:centered
-                        styleMask:NSTitledWindowMask | NSClosableWindowMask
-                        backing:NSBackingStoreBuffered
-                        defer:NO];
+    NSWindow* window = NULL;
+    if (__fullscreen)
+    {
+        window = [[FullscreenWindow alloc]
+                   initWithContentRect:screenBounds
+                   styleMask:NSBorderlessWindowMask
+                   backing:NSBackingStoreBuffered
+                   defer:NO];
+    }
+    else
+    {
+        window = [[NSWindow alloc]
+                   initWithContentRect:centered
+                   styleMask:NSTitledWindowMask | NSClosableWindowMask
+                   backing:NSBackingStoreBuffered
+                   defer:NO];
+    }
     
     [window setAcceptsMouseMovedEvents:YES];
     [window setContentView:__view];
@@ -632,12 +706,12 @@ void Platform::signalShutdown()
     
 unsigned int Platform::getDisplayWidth()
 {
-    return WINDOW_WIDTH;
+    return __width;
 }
 
 unsigned int Platform::getDisplayHeight()
 {
-    return WINDOW_HEIGHT;
+    return __height;
 }
 
 long Platform::getAbsoluteTime()
@@ -672,6 +746,9 @@ bool Platform::isMultiTouch()
     
 void Platform::getAccelerometerValues(float* pitch, float* roll)
 {
+    GP_ASSERT(pitch);
+    GP_ASSERT(roll);
+
     *pitch = __pitch;
     *roll = __roll;
 }
@@ -697,7 +774,7 @@ void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned
     
 void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
-    gameplay::Game::getInstance()->keyEvent(evt, key);
+    Game::getInstance()->keyEvent(evt, key);
     Form::keyEventInternal(evt, key);
 }
     

+ 14 - 6
gameplay/src/PlatformQNX.cpp

@@ -401,6 +401,7 @@ static int getUnicode(int qnxKeyCode)
 
 extern void printError(const char* format, ...)
 {
+    GP_ASSERT(format);
     va_list argptr;
     va_start(argptr, format);
     vfprintf(stderr, format, argptr);
@@ -409,6 +410,7 @@ extern void printError(const char* format, ...)
 
 EGLenum checkErrorEGL(const char* msg)
 {
+    GP_ASSERT(msg);
     static const char* errmsg[] =
     {
         "EGL function succeeded",
@@ -751,6 +753,7 @@ error:
  */
 long timespec2millis(struct timespec *a)
 {
+    GP_ASSERT(a);
     return a->tv_sec*1000 + a->tv_nsec/1000000;
 }
 
@@ -773,6 +776,8 @@ void mouseOrTouchEvent(Mouse::MouseEvent mouseEvent, Touch::TouchEvent touchEven
 
 int Platform::enterMessagePump()
 {
+    GP_ASSERT(_game);
+
     int rc;
     int eventType;
     int flags;
@@ -849,7 +854,7 @@ int Platform::enterMessagePump()
                         // A move event will be fired unless a button state changed.
                         bool move = true;
                         bool left_move = false;
-                        //This is a mouse move event, it is applicable to a device with a usb mouse or simulator
+                        // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
                         screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
                         screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
                         screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
@@ -875,7 +880,7 @@ int Platform::enterMessagePump()
                             mouseOrTouchEvent(Mouse::MOUSE_RELEASE_LEFT_BUTTON, Touch::TOUCH_RELEASE, position[0], position[1]);
                         }
 
-                        // Handle right mouse
+                        // Handle right mouse.
                         if (buttons & SCREEN_RIGHT_MOUSE_BUTTON)
                         {
                             if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0)
@@ -892,7 +897,7 @@ int Platform::enterMessagePump()
                             Game::getInstance()->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, position[0], position[1], 0);
                         }
 
-                        // Handle middle mouse
+                        // Handle middle mouse.
                         if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON)
                         {
                             if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0)
@@ -919,7 +924,7 @@ int Platform::enterMessagePump()
                             Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, position[0], position[1], 0);
                         }
 
-                        // Handle mouse wheel events
+                        // Handle mouse wheel events.
                         if (wheel)
                         {
                             Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, position[0], position[1], -wheel);
@@ -932,7 +937,7 @@ int Platform::enterMessagePump()
                         screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
                         screen_get_event_property_iv(__screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
                         gameplay::Keyboard::KeyEvent evt = (flags & KEY_DOWN) ? gameplay::Keyboard::KEY_PRESS :  gameplay::Keyboard::KEY_RELEASE;
-                        // Suppress key repeats
+                        // Suppress key repeats.
                         if ((flags & KEY_REPEAT) == 0)
                         {
                             keyEventInternal(evt, getKey(value));
@@ -1076,6 +1081,9 @@ bool Platform::isMultiTouch()
 
 void Platform::getAccelerometerValues(float* pitch, float* roll)
 {
+    GP_ASSERT(pitch);
+    GP_ASSERT(roll);
+
     switch(__orientationAngle)
     {
     // Landscape based device adjusting for landscape game mode
@@ -1136,7 +1144,7 @@ void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned
 
 void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
-    gameplay::Game::getInstance()->keyEvent(evt, key);
+    Game::getInstance()->keyEvent(evt, key);
     Form::keyEventInternal(evt, key);
 }
 

+ 67 - 33
gameplay/src/PlatformWin32.cpp

@@ -8,6 +8,8 @@
 #include <GL/wglew.h>
 #include <windowsx.h>
 
+using gameplay::printError;
+
 // Default to 720p
 static int __width = 1280;
 static int __height = 720;
@@ -257,11 +259,13 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     if (hwnd != __hwnd)
     {
-        // Ignore messages that are not for our game window
-        return DefWindowProc(hwnd, msg, wParam, lParam); 
+        // Ignore messages that are not for our game window.
+        return DefWindowProc(hwnd, msg, wParam, lParam);
     }
 
     // Scale factors for the mouse movement used to simulate the accelerometer.
+    GP_ASSERT(__width);
+    GP_ASSERT(__height);
     static const float ACCELEROMETER_X_FACTOR = 90.0f / __width;
     static const float ACCELEROMETER_Y_FACTOR = 90.0f / __height;
 
@@ -374,7 +378,7 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         if (wParam == VK_CAPITAL)
             capsOn = !capsOn;
 
-        // Suppress key repeats
+        // Suppress key repeats.
         if ((lParam & 0x40000000) == 0)
             gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, getKey(wParam, shiftDown ^ capsOn));
         break;
@@ -387,13 +391,13 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
         break;
 
     case WM_CHAR:
-        // Suppress key repeats
+        // Suppress key repeats.
         if ((lParam & 0x40000000) == 0)
             gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
         break;
 
     case WM_UNICHAR:
-        // Suppress key repeats
+        // Suppress key repeats.
         if ((lParam & 0x40000000) == 0)
             gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
         break;
@@ -449,6 +453,8 @@ Platform::~Platform()
 
 Platform* Platform::create(Game* game)
 {
+    GP_ASSERT(game);
+
     FileSystem::setResourcePath("./");
 
     Platform* platform = new Platform(game);
@@ -460,31 +466,34 @@ Platform* Platform::create(Game* game)
     std::wstring windowName;
     bool fullscreen = false;
     
-    // Read window settings from config
-    Properties* config = game->getConfig()->getNamespace("window", true);
-    if (config)
+    // Read window settings from config.
+    if (game->getConfig())
     {
-        // Read window title
-        const char* title = config->getString("title");
-        if (title)
+        Properties* config = game->getConfig()->getNamespace("window", true);
+        if (config)
         {
-            int len = MultiByteToWideChar(CP_ACP, 0, title, -1, NULL, 0);
-            wchar_t* wtitle = new wchar_t[len];
-            MultiByteToWideChar(CP_ACP, 0, title, -1, wtitle, len);
-            windowName = wtitle;
-            SAFE_DELETE_ARRAY(wtitle);
-        }
+            // Read window title.
+            const char* title = config->getString("title");
+            if (title)
+            {
+                int len = MultiByteToWideChar(CP_ACP, 0, title, -1, NULL, 0);
+                wchar_t* wtitle = new wchar_t[len];
+                MultiByteToWideChar(CP_ACP, 0, title, -1, wtitle, len);
+                windowName = wtitle;
+                SAFE_DELETE_ARRAY(wtitle);
+            }
 
-        // Read window size
-        int width = config->getInt("width");
-        if (width != 0)
-            __width = width;
-        int height = config->getInt("height");
-        if (height != 0)
-            __height = height;
+            // Read window size.
+            int width = config->getInt("width");
+            if (width != 0)
+                __width = width;
+            int height = config->getInt("height");
+            if (height != 0)
+                __height = height;
 
-        // Read fullscreen state
-        fullscreen = config->getBool("fullscreen");
+            // Read fullscreen state.
+            fullscreen = config->getBool("fullscreen");
+        }
     }
 
     RECT rect = { 0, 0, __width, __height };
@@ -505,7 +514,10 @@ Platform* Platform::create(Game* game)
     wc.lpszClassName  = windowClass;
 
     if (!::RegisterClassEx(&wc))
+    {
+        GP_ERROR("Failed to register window class.");
         goto error;
+    }
 
     if (fullscreen)
     {
@@ -517,11 +529,12 @@ Platform* Platform::create(Game* game)
         dm.dmBitsPerPel	= 32;
         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.
         if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
         {
             fullscreen = false;
-            GP_ERROR("Failed to start fullscreen with resolution %dx%d.", __width, __height);
+            GP_ERROR("Failed to start game in full-screen mode with resolution %dx%d.", __width, __height);
+            goto error;
         }
     }
 
@@ -557,14 +570,25 @@ Platform* Platform::create(Game* game)
 
     int pixelFormat = ChoosePixelFormat(__hdc, &pfd);
 
-    if (pixelFormat == 0 || !SetPixelFormat (__hdc, pixelFormat, &pfd))
+    if (pixelFormat == 0)
+    {
+        GP_ERROR("Failed to choose a pixel format.");
+        goto error;
+    }
+    if (!SetPixelFormat (__hdc, pixelFormat, &pfd))
+    {
+        GP_ERROR("Failed to set the pixel format.");
         goto error;
+    }
 
     HGLRC tempContext = wglCreateContext(__hdc);
     wglMakeCurrent(__hdc, tempContext);
 
     if (GLEW_OK != glewInit())
+    {
+        GP_ERROR("Failed to initialize GLEW.");
         goto error;
+    }
 
     int attribs[] =
     {
@@ -576,17 +600,21 @@ Platform* Platform::create(Game* game)
     if (!(__hrc = wglCreateContextAttribsARB(__hdc, 0, attribs) ) )
     {
         wglDeleteContext(tempContext);
+        GP_ERROR("Failed to create OpenGL context.");
         goto error;
     }
     wglDeleteContext(tempContext);
 
     if (!wglMakeCurrent(__hdc, __hrc) || !__hrc)
+    {
+        GP_ERROR("Failed to make the window current.");
         goto error;
+    }
 
     // Vertical sync.
     wglSwapIntervalEXT(__vsync ? 1 : 0);
 
-    // Show the window
+    // Show the window.
     ShowWindow(__hwnd, SW_SHOW);
 
     return platform;
@@ -598,7 +626,8 @@ error:
 }
 
 int Platform::enterMessagePump()
-{  
+{
+    GP_ASSERT(_game);
     int rc = 0;
 
     // Get the initial time.
@@ -607,6 +636,7 @@ int Platform::enterMessagePump()
     __timeTicksPerMillis = (long)(tps.QuadPart / 1000L);
     LARGE_INTEGER queryTime;
     QueryPerformanceCounter(&queryTime);
+    GP_ASSERT(__timeTicksPerMillis);
     __timeStart = queryTime.QuadPart / __timeTicksPerMillis;
 
     // Set the initial pitch and roll values.
@@ -659,8 +689,9 @@ unsigned int Platform::getDisplayHeight()
     
 long Platform::getAbsoluteTime()
 {
-       LARGE_INTEGER queryTime;
+    LARGE_INTEGER queryTime;
     QueryPerformanceCounter(&queryTime);
+    GP_ASSERT(__timeTicksPerMillis);
     __timeAbsolute = queryTime.QuadPart / __timeTicksPerMillis;
 
     return __timeAbsolute;
@@ -693,6 +724,9 @@ bool Platform::isMultiTouch()
 
 void Platform::getAccelerometerValues(float* pitch, float* roll)
 {
+    GP_ASSERT(pitch);
+    GP_ASSERT(roll);
+
     *pitch = __pitch;
     *roll = __roll;
 }
@@ -718,7 +752,7 @@ void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned
 
 void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
-    gameplay::Game::getInstance()->keyEvent(evt, key);
+    Game::getInstance()->keyEvent(evt, key);
     Form::keyEventInternal(evt, key);
 }
 

+ 3 - 1
gameplay/src/PlatformiOS.mm

@@ -549,6 +549,7 @@ long getMachTimeInMilliseconds()
         (void) mach_timebase_info(&s_timebase_info);
     
     // mach_absolute_time() returns billionth of seconds, so divide by one million to get milliseconds
+    GP_ASSERT(kOneMillion * s_timebase_info.denom);
     return (long)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
 }
 
@@ -773,6 +774,7 @@ namespace gameplay
     
 extern void printError(const char* format, ...)
 {
+    GP_ASSERT(format);
     va_list argptr;
     va_start(argptr, format);
     vfprintf(stderr, format, argptr);
@@ -891,7 +893,7 @@ void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned
 
 void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
 {
-    gameplay::Game::getInstance()->keyEvent(evt, key);
+    Game::getInstance()->keyEvent(evt, key);
     Form::keyEventInternal(evt, key);
 }
     

+ 11 - 2
gameplay/src/Ref.cpp

@@ -76,6 +76,7 @@ void Ref::printLeaks()
         for (RefAllocationRecord* rec = __refAllocations; rec != NULL; rec = rec->next)
         {
             Ref* ref = rec->ref;
+            GP_ASSERT(ref);
             const char* type = typeid(*ref).name();
             printError("[memory] LEAK: Ref object '%s' still active with reference count %d.\n", (type ? type : ""), ref->getRefCount());
         }
@@ -84,7 +85,9 @@ void Ref::printLeaks()
 
 void* trackRef(Ref* ref)
 {
-    // Create memory allocation record
+    GP_ASSERT(ref);
+
+    // Create memory allocation record.
     RefAllocationRecord* rec = (RefAllocationRecord*)malloc(sizeof(RefAllocationRecord));
     rec->ref = ref;
     rec->next = __refAllocations;
@@ -100,6 +103,12 @@ void* trackRef(Ref* ref)
 
 void untrackRef(Ref* ref, void* record)
 {
+    if (!record)
+    {
+        printError("[memory] ERROR: Attempting to free null ref tracking record.\n");
+        return;
+    }
+
     RefAllocationRecord* rec = (RefAllocationRecord*)record;
     if (rec->ref != ref)
     {
@@ -107,7 +116,7 @@ void untrackRef(Ref* ref, void* record)
         return;
     }
 
-    // Link this item out
+    // Link this item out.
     if (__refAllocations == rec)
         __refAllocations = rec->next;
     if (rec->prev)

+ 3 - 3
gameplay/src/RenderState.cpp

@@ -399,7 +399,7 @@ void RenderState::StateBlock::bindNoRestore()
     if ((_bits & RS_BLEND) && (_blendEnabled != _defaultState->_blendEnabled))
     {
         if (_blendEnabled)
-            GL_ASSERT( glEnable(GL_BLEND) )
+            GL_ASSERT( glEnable(GL_BLEND) );
         else
             GL_ASSERT( glDisable(GL_BLEND) );
         _defaultState->_blendEnabled = _blendEnabled;
@@ -413,7 +413,7 @@ void RenderState::StateBlock::bindNoRestore()
     if ((_bits & RS_CULL_FACE) && (_cullFaceEnabled != _defaultState->_cullFaceEnabled))
     {
         if (_cullFaceEnabled)
-            GL_ASSERT( glEnable(GL_CULL_FACE) ) 
+            GL_ASSERT( glEnable(GL_CULL_FACE) );
         else
             GL_ASSERT( glDisable(GL_CULL_FACE) );
         _defaultState->_cullFaceEnabled = _cullFaceEnabled;
@@ -421,7 +421,7 @@ void RenderState::StateBlock::bindNoRestore()
     if ((_bits & RS_DEPTH_TEST) && (_depthTestEnabled != _defaultState->_depthTestEnabled))
     {
         if (_depthTestEnabled) 
-            GL_ASSERT( glEnable(GL_DEPTH_TEST) ) 
+            GL_ASSERT( glEnable(GL_DEPTH_TEST) );
         else 
             GL_ASSERT( glDisable(GL_DEPTH_TEST) );
         _defaultState->_depthTestEnabled = _depthTestEnabled;

+ 1 - 1
gameplay/src/gameplay-main-android.cpp

@@ -18,8 +18,8 @@ void android_main(struct android_app* state)
     
     __state = state;
     Game* game = Game::getInstance();
-    GP_ASSERT(game != NULL);
     Platform* platform = Platform::create(game);
+    GP_ASSERT(platform);
     platform->enterMessagePump();
     delete platform;
     

+ 1 - 1
gameplay/src/gameplay-main-ios.mm

@@ -10,8 +10,8 @@ using namespace gameplay;
 int main(int argc, char** argv)
 {    
     Game* game = Game::getInstance();
-    GP_ASSERT(game != NULL);
     Platform* platform = Platform::create(game);
+    GP_ASSERT(platform);
     int result = platform->enterMessagePump();
 	delete platform;
     return result;

+ 1 - 1
gameplay/src/gameplay-main-macosx.mm

@@ -10,8 +10,8 @@ using namespace gameplay;
 int main(int argc, char** argv)
 {
     Game* game = Game::getInstance();
-    GP_ASSERT(game != NULL);
     Platform* platform = Platform::create(game);
+    GP_ASSERT(platform);
     int result = platform->enterMessagePump();
 	delete platform;
     return result;

+ 1 - 1
gameplay/src/gameplay-main-qnx.cpp

@@ -10,8 +10,8 @@ using namespace gameplay;
 int main(int argc, char** argv)
 {
     Game* game = Game::getInstance();
-    GP_ASSERT(game != NULL);
     Platform* platform = Platform::create(game);
+    GP_ASSERT(platform);
     int result = platform->enterMessagePump();
     delete platform;
     return result;

+ 1 - 1
gameplay/src/gameplay-main-win32.cpp

@@ -15,8 +15,8 @@ using namespace gameplay;
 extern "C" int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
 {
     Game* game = Game::getInstance();
-    GP_ASSERT(game != NULL);
     Platform* platform = Platform::create(game);
+    GP_ASSERT(platform);
     int result = platform->enterMessagePump();
     delete platform;
     return result;