|
|
@@ -13,38 +13,32 @@
|
|
|
#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;
|
|
|
-
|
|
|
+// Externally referenced global variables.
|
|
|
struct android_app* __state;
|
|
|
AAssetManager* __assetManager;
|
|
|
-std::string __assetsPath;
|
|
|
-bool __initialized = false;
|
|
|
-bool __destroyed = false;
|
|
|
|
|
|
+static bool __initialized;
|
|
|
+static bool __suspended;
|
|
|
static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
|
|
|
static EGLContext __eglContext = EGL_NO_CONTEXT;
|
|
|
static EGLSurface __eglSurface = EGL_NO_SURFACE;
|
|
|
static EGLConfig __eglConfig = 0;
|
|
|
-int __width;
|
|
|
-int __height;
|
|
|
-
|
|
|
-struct timespec __timespec;
|
|
|
+static int __width;
|
|
|
+static int __height;
|
|
|
+static struct timespec __timespec;
|
|
|
static long __timeStart;
|
|
|
static long __timeAbsolute;
|
|
|
static bool __vsync = WINDOW_VSYNC;
|
|
|
-
|
|
|
-ASensorManager* __sensorManager;
|
|
|
-ASensorEventQueue* __sensorEventQueue;
|
|
|
-ASensorEvent __sensorEvent;
|
|
|
-const ASensor* __accelerometerSensor;
|
|
|
-
|
|
|
-static int __orientationAngle = 90; // Landscape by default.
|
|
|
+static ASensorManager* __sensorManager;
|
|
|
+static ASensorEventQueue* __sensorEventQueue;
|
|
|
+static ASensorEvent __sensorEvent;
|
|
|
+static const ASensor* __accelerometerSensor;
|
|
|
+static int __orientationAngle = 90;
|
|
|
static bool __multiTouch = false;
|
|
|
static int __primaryTouchId = -1;
|
|
|
-bool __displayKeyboard = false;
|
|
|
+static bool __displayKeyboard = false;
|
|
|
|
|
|
+// OpenGL VAO functions.
|
|
|
static const char* __glExtensions;
|
|
|
PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
|
|
|
PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
|
|
|
@@ -54,7 +48,7 @@ PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
|
|
|
namespace gameplay
|
|
|
{
|
|
|
|
|
|
-long timespec2millis(struct timespec *a)
|
|
|
+static long timespec2millis(struct timespec *a)
|
|
|
{
|
|
|
return a->tv_sec*1000 + a->tv_nsec/1000000;
|
|
|
}
|
|
|
@@ -67,7 +61,7 @@ extern void printError(const char* format, ...)
|
|
|
va_end(argptr);
|
|
|
}
|
|
|
|
|
|
-EGLenum checkErrorEGL(const char* msg)
|
|
|
+static EGLenum checkErrorEGL(const char* msg)
|
|
|
{
|
|
|
static const char* errmsg[] =
|
|
|
{
|
|
|
@@ -93,7 +87,7 @@ EGLenum checkErrorEGL(const char* msg)
|
|
|
}
|
|
|
|
|
|
// Initialized EGL resources.
|
|
|
-bool initEGL()
|
|
|
+static bool initEGL()
|
|
|
{
|
|
|
// Hard-coded to 32-bit/OpenGL ES 2.0.
|
|
|
const EGLint eglConfigAttrs[] =
|
|
|
@@ -122,31 +116,34 @@ bool initEGL()
|
|
|
EGL_NONE
|
|
|
};
|
|
|
|
|
|
- // Get the EGL display and initialize.
|
|
|
- __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
|
- if (__eglDisplay == EGL_NO_DISPLAY)
|
|
|
+ if (__eglDisplay == EGL_NO_DISPLAY && __eglContext == EGL_NO_CONTEXT)
|
|
|
{
|
|
|
- checkErrorEGL("eglGetDisplay");
|
|
|
- goto error;
|
|
|
- }
|
|
|
+ // 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 (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;
|
|
|
- }
|
|
|
+ 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;
|
|
|
+ __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
|
|
|
@@ -191,12 +188,42 @@ bool initEGL()
|
|
|
return true;
|
|
|
|
|
|
error:
|
|
|
-
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+static void destroyEGLSurface()
|
|
|
+{
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void destroyEGLMain()
|
|
|
+{
|
|
|
+ destroyEGLSurface();
|
|
|
+
|
|
|
+ if (__eglContext != EGL_NO_CONTEXT)
|
|
|
+ {
|
|
|
+ eglDestroyContext(__eglDisplay, __eglContext);
|
|
|
+ __eglContext = EGL_NO_CONTEXT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (__eglDisplay != EGL_NO_DISPLAY)
|
|
|
+ {
|
|
|
+ eglTerminate(__eglDisplay);
|
|
|
+ __eglDisplay = EGL_NO_DISPLAY;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// Display the android virtual keyboard.
|
|
|
-void displayKeyboard(android_app* state, bool show)
|
|
|
+static void displayKeyboard(android_app* state, bool show)
|
|
|
{
|
|
|
// The following functions is supposed to show / hide functins from a native activity.. but currently do not work.
|
|
|
// ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
|
|
|
@@ -256,7 +283,7 @@ void displayKeyboard(android_app* state, bool show)
|
|
|
}
|
|
|
|
|
|
// Gets the Keyboard::Key enumeration constant that corresponds to the given Android key code.
|
|
|
-Keyboard::Key getKey(int keycode, int metastate)
|
|
|
+static Keyboard::Key getKey(int keycode, int metastate)
|
|
|
{
|
|
|
bool shiftOn = (metastate == AMETA_SHIFT_ON);
|
|
|
|
|
|
@@ -604,7 +631,7 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
|
|
|
}
|
|
|
|
|
|
// Process the next main command.
|
|
|
-static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
|
|
+static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
|
|
{
|
|
|
switch (cmd)
|
|
|
{
|
|
|
@@ -612,23 +639,47 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
|
|
// The window is being shown, get it ready.
|
|
|
if (app->window != NULL)
|
|
|
{
|
|
|
+ initEGL();
|
|
|
__initialized = true;
|
|
|
}
|
|
|
break;
|
|
|
case APP_CMD_TERM_WINDOW:
|
|
|
- {
|
|
|
- __destroyed = true;
|
|
|
- break;
|
|
|
- }
|
|
|
+ destroyEGLSurface();
|
|
|
+ __initialized = false;
|
|
|
+ break;
|
|
|
+ case APP_CMD_DESTROY:
|
|
|
+ Game::getInstance()->exit();
|
|
|
+ destroyEGLMain();
|
|
|
+ __initialized = false;
|
|
|
+ break;
|
|
|
case 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).
|
|
|
+ // We'd like to get 60 events per second (in microseconds).
|
|
|
ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
|
|
|
}
|
|
|
- Game::getInstance()->resume();
|
|
|
+
|
|
|
+ if (Game::getInstance()->getState() == Game::UNINITIALIZED)
|
|
|
+ {
|
|
|
+ Game::getInstance()->run(__width, __height);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Game::getInstance()->resume();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case APP_CMD_RESUME:
|
|
|
+ if (__initialized)
|
|
|
+ {
|
|
|
+ Game::getInstance()->resume();
|
|
|
+ }
|
|
|
+ __suspended = false;
|
|
|
+ break;
|
|
|
+ case APP_CMD_PAUSE:
|
|
|
+ Game::getInstance()->pause();
|
|
|
+ __suspended = true;
|
|
|
break;
|
|
|
case APP_CMD_LOST_FOCUS:
|
|
|
// When our app loses focus, we stop monitoring the accelerometer.
|
|
|
@@ -637,7 +688,6 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
|
|
{
|
|
|
ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
|
|
|
}
|
|
|
- Game::getInstance()->pause();
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -654,28 +704,6 @@ Platform::Platform(const Platform& copy)
|
|
|
|
|
|
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)
|
|
|
@@ -687,6 +715,9 @@ Platform* Platform::create(Game* game)
|
|
|
|
|
|
int Platform::enterMessagePump()
|
|
|
{
|
|
|
+ __initialized = false;
|
|
|
+ __suspended = false;
|
|
|
+
|
|
|
// Get the android application's activity.
|
|
|
ANativeActivity* activity = __state->activity;
|
|
|
JavaVM* jvm = __state->activity->vm;
|
|
|
@@ -702,12 +733,13 @@ int Platform::enterMessagePump()
|
|
|
const char* packageName;
|
|
|
jboolean isCopy;
|
|
|
packageName = env->GetStringUTFChars((jstring)result, &isCopy);
|
|
|
+ jvm->DetachCurrentThread();
|
|
|
|
|
|
// Set the default path to store the resources.
|
|
|
- __assetsPath = "/mnt/sdcard/android/data/";
|
|
|
- __assetsPath += packageName;
|
|
|
- __assetsPath += "/";
|
|
|
- FileSystem::setResourcePath(__assetsPath.c_str());
|
|
|
+ std::string assetsPath = "/mnt/sdcard/android/data/";
|
|
|
+ assetsPath += packageName;
|
|
|
+ assetsPath += "/";
|
|
|
+ FileSystem::setResourcePath(assetsPath.c_str());
|
|
|
|
|
|
// Get the asset manager to get the resources from the .apk file.
|
|
|
__assetManager = __state->activity->assetManager;
|
|
|
@@ -726,8 +758,6 @@ int Platform::enterMessagePump()
|
|
|
__timeStart = timespec2millis(&__timespec);
|
|
|
__timeAbsolute = 0L;
|
|
|
|
|
|
- bool initializeGame = true;
|
|
|
-
|
|
|
while (true)
|
|
|
{
|
|
|
// Read all pending events.
|
|
|
@@ -735,12 +765,10 @@ int Platform::enterMessagePump()
|
|
|
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)
|
|
|
+ while ((ident=ALooper_pollAll(!__suspended ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
|
|
|
{
|
|
|
// Process this event.
|
|
|
- if (source != NULL)
|
|
|
+ if (source != NULL)
|
|
|
source->process(__state, source);
|
|
|
|
|
|
// If a sensor has data, process it now.
|
|
|
@@ -748,20 +776,14 @@ int Platform::enterMessagePump()
|
|
|
ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
|
|
|
|
|
|
if (__state->destroyRequested != 0)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (__initialized && initializeGame)
|
|
|
- {
|
|
|
- gameplay::initEGL();
|
|
|
- WARN_VARG("Platform::enterMessagePump() - width: %d height: %d assetsPath: %s", __width, __height, __assetsPath.c_str());
|
|
|
- _game->run(__width, __height);
|
|
|
- initializeGame = false;
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Idle time (no events left to process) is spent rendering.
|
|
|
// We skip rendering when the app is paused.
|
|
|
- if (__initialized && _game->getState() != Game::PAUSED)
|
|
|
+ if (__initialized && !__suspended)
|
|
|
{
|
|
|
_game->frame();
|
|
|
|
|
|
@@ -781,23 +803,27 @@ int Platform::enterMessagePump()
|
|
|
int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
|
|
|
if (rc != EGL_TRUE)
|
|
|
{
|
|
|
- perror("eglSwapBuffers");
|
|
|
- _game->exit();
|
|
|
- break;
|
|
|
+ EGLint error = eglGetError();
|
|
|
+ if (error == EGL_BAD_NATIVE_WINDOW)
|
|
|
+ {
|
|
|
+ if (__state->window != NULL)
|
|
|
+ {
|
|
|
+ destroyEGLSurface();
|
|
|
+ initEGL();
|
|
|
+ }
|
|
|
+ __initialized = true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ perror("eglSwapBuffers");
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- // Check if we are exiting.
|
|
|
- if ((__state->destroyRequested != 0) || (__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED))
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
|
|
|
// Display the keyboard.
|
|
|
gameplay::displayKeyboard(__state, __displayKeyboard);
|
|
|
}
|
|
|
-
|
|
|
- jvm->DetachCurrentThread();
|
|
|
}
|
|
|
|
|
|
void Platform::signalShutdown()
|