浏览代码

Initial checkin for android platform support.

Ramprasad Madhavan 14 年之前
父节点
当前提交
0c66baf747

+ 14 - 0
gameplay-android/AndroidManifest.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.gameplay"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="15" />
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name" >
+    </application>
+
+</manifest>

+ 85 - 0
gameplay-android/build.xml

@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="gameplay-android" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
+            unless="sdk.dir"
+    />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+     in between standard targets -->
+<!--
+    <target name="-pre-build">
+    </target>
+    <target name="-pre-compile">
+    </target>
+
+    /* This is typically used for code obfuscation.
+       Compiled code location: ${out.classes.absolute.dir}
+       If this is not done in place, override ${out.dex.input.absolute.dir} */
+    <target name="-post-compile">
+    </target>
+-->
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

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

@@ -0,0 +1,25 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)/../../gameplay/src
+
+include $(CLEAR_VARS)
+LOCAL_MODULE    := libgameplay
+LOCAL_SRC_FILES := Animation.cpp DepthStencilTarget.cpp MeshBatch.cpp PhysicsRigidBody.cpp SceneLoader.cpp AnimationClip.cpp Effect.cpp MeshPart.cpp PhysicsSocketConstraint.cpp SpriteBatch.cpp AnimationController.cpp FileSystem.cpp MeshSkin.cpp PhysicsSpringConstraint.cpp Technique.cpp AnimationTarget.cpp Font.cpp Model.cpp Plane.cpp Texture.cpp AnimationValue.cpp FrameBuffer.cpp Node.cpp PlatformAndroid.cpp PlatformQNX.cpp AudioBuffer.cpp Frustum.cpp Package.cpp PlatformWin32.cpp Transform.cpp AudioController.cpp Game.cpp ParticleEmitter.cpp Properties.cpp Vector2.cpp AudioListener.cpp Image.cpp Pass.cpp Quaternion.cpp Vector3.cpp AudioSource.cpp Joint.cpp PhysicsConstraint.cpp Ray.cpp Vector4.cpp BoundingBox.cpp Light.cpp PhysicsController.cpp Rectangle.cpp VertexAttributeBinding.cpp BoundingSphere.cpp Material.cpp PhysicsFixedConstraint.cpp Ref.cpp VertexFormat.cpp Camera.cpp MaterialParameter.cpp PhysicsGenericConstraint.cpp RenderState.cpp Viewport.cpp Curve.cpp Matrix.cpp PhysicsHingeConstraint.cpp RenderTarget.cpp DebugNew.cpp Mesh.cpp PhysicsMotionState.cpp Scene.cpp gameplay-main-android.cpp
+LOCAL_CFLAGS := -D__ANDROID__ -I"../external-deps/bullet/include" -I"../external-deps/openal/include" -I"../external-deps/libpng/include" -I"../external-deps/oggvorbis/include"
+LOCAL_STATIC_LIBRARIES := android_native_app_glue
+
+include $(BUILD_STATIC_LIBRARY)
+
+$(call import-module,android/native_app_glue)

+ 2 - 0
gameplay-android/jni/Application.mk

@@ -0,0 +1,2 @@
+APP_STL     := stlport_static
+APP_MODULES := libgameplay

+ 10 - 0
gameplay-android/local.properties

@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=C:\\Android\\android-sdk

+ 40 - 0
gameplay-android/proguard.cfg

@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+   public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+  public static final android.os.Parcelable$Creator *;
+}

+ 11 - 0
gameplay-android/project.properties

@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-15

+ 373 - 0
gameplay/src/PlatformAndroid.cpp

@@ -0,0 +1,373 @@
+#ifdef __ANDROID__
+
+#include "Base.h"
+#include "Platform.h"
+#include "FileSystem.h"
+#include "Game.h"
+#include <unistd.h>
+
+#include <android/sensor.h>
+#include <android_native_app_glue.h>
+
+#include <android/log.h>
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
+
+#define TOUCH_COUNT_MAX     4
+
+using namespace std;
+
+struct timespec __timespec;
+static long __timeStart;
+static long __timeAbsolute;
+static bool __vsync = WINDOW_VSYNC;
+
+struct android_app* __state;
+extern std::string __assetsPath;
+int __width;
+int __height;
+static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
+static EGLContext __eglContext = EGL_NO_CONTEXT;
+static EGLSurface __eglSurface = EGL_NO_SURFACE;
+static EGLConfig __eglConfig = 0;
+ASensorManager* __sensorManager;
+const ASensor* __accelerometerSensor;
+ASensorEventQueue* __sensorEventQueue;
+ASensorEvent __sensorEvent;
+static int __orientationAngle;
+static bool __multiTouch = false;
+
+static const char* __glExtensions;
+PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
+PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
+PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL;
+PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
+
+
+
+//gameplay::Keyboard::Key getKey(int keycode, int metastate);
+
+namespace gameplay
+{
+
+// Gets the Keyboard::Key enumeration constant that corresponds to the given QNX key code.
+Keyboard::Key getKey(int keycode, int metastate)
+{
+    
+	// TODO.
+	
+	return Keyboard::KEY_NONE;
+}
+
+
+extern void printError(const char* format, ...)
+{
+    va_list argptr;
+    va_start(argptr, format);
+    LOGI(format, argptr);
+    va_end(argptr);
+}
+
+EGLenum checkErrorEGL(const char* msg)
+{
+    static const char* errmsg[] =
+    {
+        "EGL function succeeded",
+        "EGL is not initialized, or could not be initialized, for the specified display",
+        "EGL cannot access a requested resource",
+        "EGL failed to allocate resources for the requested operation",
+        "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
+        "EGLConfig argument does not name a valid EGLConfig",
+        "EGLContext argument does not name a valid EGLContext",
+        "EGL current surface of the calling thread is no longer valid",
+        "EGLDisplay argument does not name a valid EGLDisplay",
+        "EGL arguments are inconsistent",
+        "EGLNativePixmapType argument does not refer to a valid native pixmap",
+        "EGLNativeWindowType argument does not refer to a valid native window",
+        "EGL one or more argument values are invalid",
+        "EGLSurface argument does not name a valid surface configured for rendering",
+        "EGL power management event has occurred",
+    };
+    EGLenum error = eglGetError();
+    LOGI("%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
+    return error;
+}
+
+Platform::Platform(Game* game)
+    : _game(game)
+{
+}
+
+Platform::Platform(const Platform& copy)
+{
+    // hidden
+}
+
+Platform::~Platform()
+{
+    if (__eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglMakeCurrent(__eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    }
+
+    if (__eglSurface != EGL_NO_SURFACE)
+    {
+        eglDestroySurface(__eglDisplay, __eglSurface);
+        __eglSurface = EGL_NO_SURFACE;
+    }
+
+    if (__eglContext != EGL_NO_CONTEXT)
+    {
+        eglDestroyContext(__eglDisplay, __eglContext);
+        __eglContext = EGL_NO_CONTEXT;
+    }
+
+    if (__eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglTerminate(__eglDisplay);
+        __eglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+Platform* Platform::create(Game* game)
+{
+    FileSystem::setResourcePath(__assetsPath.c_str());
+   
+    Platform* platform = new Platform(game);
+
+    // Hard-coded to 32-bit/OpenGL ES 2.0.
+    const EGLint eglConfigAttrs[] =
+    {
+        EGL_RED_SIZE,           8,
+        EGL_GREEN_SIZE,         8,
+        EGL_BLUE_SIZE,          8,
+        EGL_ALPHA_SIZE,         8,
+        EGL_DEPTH_SIZE,         24,
+        EGL_STENCIL_SIZE,       8,
+        EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
+        EGL_RENDERABLE_TYPE,    EGL_OPENGL_ES2_BIT,
+        EGL_NONE
+    };
+    
+    EGLint eglConfigCount;
+    const EGLint eglContextAttrs[] =
+    {
+        EGL_CONTEXT_CLIENT_VERSION,    2,
+        EGL_NONE
+    };
+
+	const EGLint eglSurfaceAttrs[] =
+    {
+        EGL_RENDER_BUFFER,    EGL_BACK_BUFFER,
+        EGL_NONE
+    };
+
+    // Get the EGL display and initialize.
+    __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (__eglDisplay == EGL_NO_DISPLAY)
+    {
+        checkErrorEGL("eglGetDisplay");
+        goto error;
+    }
+    
+    if (eglInitialize(__eglDisplay, NULL, NULL) != EGL_TRUE)
+    {
+        checkErrorEGL("eglInitialize");
+        goto error;
+    }
+
+    if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
+    {
+        checkErrorEGL("eglChooseConfig");
+        goto error;
+    }
+    
+    __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
+    if (__eglContext == EGL_NO_CONTEXT)
+    {
+        checkErrorEGL("eglCreateContext");
+        goto error;
+    }
+    
+    // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
+    // guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
+    // As soon as we picked a EGLConfig, we can safely reconfigure the
+    // ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
+    EGLint format;
+    eglGetConfigAttrib(__eglDisplay, __eglConfig, EGL_NATIVE_VISUAL_ID, &format);
+    ANativeWindow_setBuffersGeometry(__state->window, 0, 0, format);
+
+    __eglSurface = eglCreateWindowSurface(__eglDisplay, __eglConfig, __state->window, eglSurfaceAttrs);
+    if (__eglSurface == EGL_NO_SURFACE)
+    {
+        checkErrorEGL("eglCreateWindowSurface");
+        goto error;
+    }
+
+    LOGI("Platform::create - 3");
+    
+    if (eglMakeCurrent(__eglDisplay, __eglSurface, __eglSurface, __eglContext) != EGL_TRUE)
+    {
+        checkErrorEGL("eglMakeCurrent");
+        goto error;
+    }
+
+    eglQuerySurface(__eglDisplay, __eglSurface, EGL_WIDTH, &__width);
+    eglQuerySurface(__eglDisplay, __eglSurface, EGL_HEIGHT, &__height);
+	
+    WARN_VARG("Platform::create - WIDTH: %d HEIGHT = %d" , __width, __height);
+    
+    // Set vsync.
+    eglSwapInterval(__eglDisplay, WINDOW_VSYNC ? 1 : 0);
+
+    // Initialize OpenGL ES extensions.
+    __glExtensions = (const char*)glGetString(GL_EXTENSIONS);
+
+    if (strstr(__glExtensions, "GL_OES_vertex_array_object") || strstr(__glExtensions, "GL_ARB_vertex_array_object"))
+    {
+        WARN("Platform::create - VAOs supported");
+		
+		// Disable VAO extension for now.
+        glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
+        glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArrays");
+        glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
+        glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES");
+    }
+
+    
+    // TODO: Determine initial orientation angle.
+    //orientation_direction_t direction;
+    //orientation_get(&direction, &__orientationAngle);
+
+    return platform;
+
+error:
+
+    // TODO: cleanup.
+
+    return NULL;
+}
+
+/**
+ * Convert the timespec into milliseconds.
+ */
+long timespec2millis(struct timespec *a)
+{
+    return a->tv_sec*1000 + a->tv_nsec/1000000;
+}
+
+int Platform::enterMessagePump()
+{
+    static int state = 0;
+	
+	switch (state)
+	{
+		case 0:
+			// Get the initial time.
+			clock_gettime(CLOCK_REALTIME, &__timespec);
+			__timeStart = timespec2millis(&__timespec);
+			__timeAbsolute = 0L;
+			WARN_VARG("Platform::enterMessagePump() - WIDTH: %d HEIGHT = %d" , __width, __height);
+			_game->run(__width, __height);
+			
+			state = 1;
+			break;
+		case 1:
+			// Idle time (no events left to process) is spent rendering.
+			// We skip rendering when the app is paused.
+			if (_game->getState() != Game::PAUSED)
+			{
+				_game->frame();
+
+				// Post the new frame to the display.
+				// Note that there are a couple cases where eglSwapBuffers could fail
+				// with an error code that requires a certain level of re-initialization:
+				//
+				// 1) EGL_BAD_NATIVE_WINDOW - Called when the surface we're currently using
+				//    is invalidated. This would require us to destroy our EGL surface,
+				//    close our OpenKODE window, and start again.
+				//
+				// 2) EGL_CONTEXT_LOST - Power management event that led to our EGL context
+				//    being lost. Requires us to re-create and re-initalize our EGL context
+				//    and all OpenGL ES state.
+				//
+				// For now, if we get these, we'll simply exit.
+				int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
+				if (rc != EGL_TRUE)
+				{
+					perror("eglSwapBuffers");
+					_game->exit();
+					break;
+				}
+			}
+			break;
+	}
+    
+    return 0;
+}
+
+long Platform::getAbsoluteTime()
+{
+    clock_gettime(CLOCK_REALTIME, &__timespec);
+    long now = timespec2millis(&__timespec);
+    __timeAbsolute = now - __timeStart;
+
+    return __timeAbsolute;
+}
+
+void Platform::setAbsoluteTime(long time)
+{
+    __timeAbsolute = time;
+}
+
+bool Platform::isVsync()
+{
+    return __vsync;
+}
+
+void Platform::setVsync(bool enable)
+{
+    eglSwapInterval(__eglDisplay, enable ? 1 : 0);
+    __vsync = enable;
+}
+
+int Platform::getOrientationAngle()
+{
+    return __orientationAngle;
+}
+
+void Platform::setMultiTouch(bool enabled)
+{
+    __multiTouch = enabled;
+}
+
+bool Platform::isMultiTouch()
+{
+    return __multiTouch;
+}
+
+void Platform::getAccelerometerValues(float* pitch, float* roll)
+{
+    double tx, ty, tz;
+	ASensorEvent event;
+	
+	// By default, android accelerometer values are oriented to the portrait mode.
+	// flipping the x and y to get the desired landscape mode values.
+	tx = -__sensorEvent.acceleration.y;
+	ty = __sensorEvent.acceleration.x;
+	tz = -__sensorEvent.acceleration.z;
+	
+	if (pitch != NULL)
+		*pitch = atan(ty / sqrt(tx * tx + tz * tz)) * 180.0f * M_1_PI;
+	if (roll != NULL)
+		*roll = atan(tx / sqrt(ty * ty + tz * tz)) * 180.0f * M_1_PI;
+}
+
+void Platform::swapBuffers()
+{
+    if (__eglDisplay && __eglSurface)
+        eglSwapBuffers(__eglDisplay, __eglSurface);
+}
+
+}
+
+#endif

+ 207 - 0
gameplay/src/gameplay-main-android.cpp

@@ -0,0 +1,207 @@
+#ifdef __ANDROID__
+
+#include "gameplay.h"
+#include <android/sensor.h>
+#include <android_native_app_glue.h>
+
+
+#include <android/log.h>
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
+
+using namespace gameplay;
+
+extern struct android_app* __state;
+AAssetManager* __assetManager;
+std::string __assetsPath;
+extern ASensorManager* __sensorManager;
+extern const ASensor* __accelerometerSensor;
+extern ASensorEventQueue* __sensorEventQueue;
+extern ASensorEvent __sensorEvent;
+
+//extern gameplay::Keyboard::Key getKey(int keycode, int metastate);
+bool __initialized;
+
+
+/**
+ * Process the next input event.
+ */
+static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) 
+{
+    Platform* platform = static_cast<Platform*>(app->userData);
+    
+    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
+    {
+        int32_t data = AMotionEvent_getAction(event);
+        int contactIndex = data >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+        Touch::TouchEvent touchEvent;
+        switch (data & AMOTION_EVENT_ACTION_MASK)
+        {
+            case AMOTION_EVENT_ACTION_DOWN:
+                touchEvent = Touch::TOUCH_PRESS;
+                break;
+            case AMOTION_EVENT_ACTION_UP:
+                touchEvent = Touch::TOUCH_RELEASE;
+                break;
+            case AMOTION_EVENT_ACTION_MOVE:
+                touchEvent = Touch::TOUCH_MOVE;
+                break;
+        }
+    
+        Game::getInstance()->touchEvent(touchEvent, AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0), contactIndex);
+        return 1;
+    } 
+    else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
+    {
+        int32_t action = AKeyEvent_getAction(event);
+		int32_t keycode = AKeyEvent_getKeyCode(event);
+		int32_t metastate = AKeyEvent_getMetaState(event); 
+		
+		WARN_VARG("Key event: action=%d keyCode=%d metaState=0x%x", action, keycode, metastate);
+        
+		switch(action)
+		{
+			case AKEY_EVENT_ACTION_DOWN:
+				//Game::getInstance()->keyEvent(Keyboard::KEY_PRESS, getKey(keycode, metastate));
+				break;
+					
+			case AKEY_EVENT_ACTION_UP:
+				//Game::getInstance()->keyEvent(Keyboard::KEY_RELEASE, getKey(keycode, metastate));
+				break;
+			
+		
+		}
+    }
+    return 0;
+}
+
+/**
+ * Process the next main command.
+ */
+static void engine_handle_cmd(struct android_app* app, int32_t cmd) 
+{
+    switch (cmd) 
+    {
+        case APP_CMD_SAVE_STATE:
+            WARN("engine_handle_cmd - APP_CMD_SAVE_STATE");
+            // TODO
+            break;
+        case APP_CMD_INIT_WINDOW:
+            WARN("engine_handle_cmd - APP_CMD_INIT_WINDOW");
+			// The window is being shown, get it ready.
+            if (app->window != NULL)
+            {
+                Game* game = Game::getInstance();
+                assert(game != NULL);
+                Platform* platform = Platform::create(game);
+                app->userData = platform;
+				__initialized = true;
+            }
+            break;
+        case APP_CMD_TERM_WINDOW:
+		{
+			WARN("engine_handle_cmd - APP_CMD_TERM_WINDOW");
+            Game::getInstance()->exit();
+			Platform* platform = static_cast<Platform*>(app->userData);
+			if (!platform)
+			{
+				return;
+			}
+			delete platform;
+			app->userData = NULL;
+			break;
+		}
+        case APP_CMD_GAINED_FOCUS:
+            WARN("engine_handle_cmd - APP_CMD_GAINED_FOCUS");
+			// When our app gains focus, we start monitoring the accelerometer.
+            if (__accelerometerSensor != NULL) {
+                ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
+                // We'd like to get 60 events per second (in us).
+                ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
+            }
+            Game::getInstance()->resume();
+            break;
+        case APP_CMD_LOST_FOCUS:
+            WARN("engine_handle_cmd - APP_CMD_LOST_FOCUS");
+			// When our app loses focus, we stop monitoring the accelerometer.
+            // This is to avoid consuming battery while not being used.
+            if (__accelerometerSensor != NULL) {
+                ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
+            }
+            Game::getInstance()->pause();
+            ((Platform*)static_cast<Platform*>(app->userData))->swapBuffers();
+            break;
+    }
+}
+
+/**
+ * Main entry point.
+ */
+void amain(struct android_app* state)
+{
+	ANativeActivity* activity = state->activity;
+	JNIEnv* env = activity->env;
+
+    jclass clazz = env->GetObjectClass(activity->clazz);
+    jmethodID methodID = env->GetMethodID(clazz, "getPackageName", "()Ljava/lang/String;");
+    jobject result = env->CallObjectMethod(activity->clazz, methodID);
+	
+	const char* packageName;
+    jboolean isCopy;
+    packageName = env->GetStringUTFChars((jstring)result, &isCopy);
+    
+    __assetsPath = "/mnt/sdcard/android/data/";
+    __assetsPath += packageName;
+    __assetsPath += "/";
+    
+    __assetManager = state->activity->assetManager; 
+    
+    state->onAppCmd = engine_handle_cmd;
+    state->onInputEvent = engine_handle_input;
+    __state = state;
+    
+	// Prepare to monitor accelerometer.
+    __sensorManager = ASensorManager_getInstance();
+    __accelerometerSensor = ASensorManager_getDefaultSensor(__sensorManager, ASENSOR_TYPE_ACCELEROMETER);
+    __sensorEventQueue = ASensorManager_createEventQueue(__sensorManager, __state->looper, LOOPER_ID_USER, NULL, NULL);
+	
+	ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
+	
+	
+	__initialized = false;
+	while (true) 
+    {
+		// Read all pending events.
+        int ident;
+        int events;
+        struct android_poll_source* source;
+        
+		bool _shouldPoll = !(__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED) && (Game::getInstance()->getState() != Game::PAUSED); 
+		
+		while ((ident=ALooper_pollAll( _shouldPoll ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
+        {
+			// Process this event.
+            if (source != NULL) 
+                source->process(__state, source);
+            
+            // If a sensor has data, process it now.
+            if (ident == LOOPER_ID_USER && __accelerometerSensor != NULL)
+                ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
+			
+			if (__state->destroyRequested != 0)
+				break;
+        }
+		
+		Platform* platform = static_cast<Platform*>(state->userData);
+		if (platform)
+			platform->enterMessagePump();
+		
+		// Check if we are exiting.
+        if ((__state->destroyRequested != 0) || (__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED))
+            break;        
+    }
+	
+	// We need to exit the process to cleanup global resources.
+	exit(0);
+}
+
+#endif