Changeset 2579 for trunk/src/platform/android/androidapp.cpp
- Timestamp:
- Mar 11, 2013, 7:25:21 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/platform/android/androidapp.cpp
r2576 r2579 2 2 // Lol Engine 3 3 // 4 // Copyright: (c) 2010-201 1Sam Hocevar <sam@hocevar.net>4 // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> 5 5 // This program is free software; you can redistribute it and/or 6 6 // modify it under the terms of the Do What The Fuck You Want To … … 16 16 17 17 #include <jni.h> 18 #include <android/log.h> 18 19 #include <EGL/egl.h> 20 #include <GLES/gl.h> 21 22 extern "C" { 23 #include <android_native_app_glue.h> 24 #include <android_native_app_glue.c> 25 } 19 26 20 27 #include "core.h" 21 #include "loldebug.h"22 28 #include "androidapp.h" 23 29 24 30 using namespace lol; 31 32 namespace lol 33 { 34 JavaVM *g_vm; 35 jobject g_activity; 36 }; /* namespace lol */ 37 38 extern "C" jint 39 JNI_OnLoad(JavaVM* vm, void* reserved) 40 { 41 Log::Info("Java layer loading library, vm=0x%08lx", (long)(intptr_t)vm); 42 g_vm = vm; 43 return JNI_VERSION_1_4; 44 } 45 46 extern "C" void 47 Java_net_lolengine_LolActivity_nativeInit(JNIEnv* env, jobject thiz) 48 { 49 Log::Info("Java layer initialising activity 0x%08lx", (long)thiz); 50 env->NewGlobalRef(thiz); /* FIXME: never released! */ 51 g_activity = thiz; 52 } 25 53 26 54 /* One of these wrappers will be overridden by the user's version */ … … 29 57 void lol_android_main(int argc, char **argv, char **envp) __attribute__((weak)); 30 58 31 namespace lol 32 { 33 JavaVM *g_vm; 34 jobject g_activity; 35 Queue<int> g_main_queue; 36 Thread *g_main_thread; 37 float g_fps; 38 39 AndroidApp::AndroidApp(char const *title, ivec2 res, float fps) 40 : m_data(0) 41 { 42 g_fps = fps; 43 } 44 45 void AndroidApp::ShowPointer(bool show) 46 { 47 } 48 49 /* This is a fake Tick() method. We just wait until we're called and 50 * signal nativeInit() that all the user's initialisation code was 51 * called. Then we sit here forever, the Java layer is in charge of 52 * calling TickDraw(). */ 53 void AndroidApp::Tick() 54 { 55 static int init = 0; 56 if (!init) 57 { 58 init = 1; 59 g_main_queue.Push(1); 60 g_main_queue.Push(1); 61 } 62 63 /* Do nothing while the real render thread does the job. The 64 * real stuff happens in nativeRender() */ 65 Timer t; 66 t.Wait(0.5f); 67 } 68 69 void *AndroidApp::MainRun(void *data) 70 { 59 /** 60 * Our saved state data. 61 */ 62 struct SavedState 63 { 64 ivec2 position; 65 }; 66 67 /** 68 * Shared state for our app. 69 */ 70 class lol::AndroidAppData 71 { 72 public: 73 android_app* m_native_app; 74 75 EGLDisplay display; 76 EGLSurface surface; 77 EGLContext context; 78 79 SavedState m_state; 80 }; 81 82 /** 83 * Initialize an EGL context for the current display. 84 */ 85 static int engine_init_display(struct AndroidAppData* engine) 86 { 87 /* 88 * Here specify the attributes of the desired configuration. 89 * Below, we select an EGLConfig with at least 8 bits per color 90 * component compatible with on-screen windows 91 */ 92 const EGLint attribs[] = 93 { 94 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 95 EGL_BUFFER_SIZE, 16, 96 EGL_DEPTH_SIZE, 16, 97 EGL_RED_SIZE, 4, 98 EGL_GREEN_SIZE, 4, 99 EGL_BLUE_SIZE, 4, 100 EGL_ALPHA_SIZE, 4, 101 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 102 EGL_NONE 103 }; 104 EGLint w, h, dummy, format; 105 EGLint numConfigs; 106 EGLConfig config; 107 EGLSurface surface; 108 EGLContext context; 109 110 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 111 112 eglInitialize(display, 0, 0); 113 eglChooseConfig(display, attribs, &config, 1, &numConfigs); 114 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); 115 116 ANativeWindow_setBuffersGeometry(engine->m_native_app->window, 117 0, 0, format); 118 surface = eglCreateWindowSurface(display, config, 119 engine->m_native_app->window, nullptr); 120 121 EGLint ctxattr[] = 122 { 123 EGL_CONTEXT_CLIENT_VERSION, 2, 124 EGL_NONE 125 }; 126 context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxattr); 127 128 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) 129 { 130 Log::Error("unable to eglMakeCurrent"); 131 return -1; 132 } 133 134 eglQuerySurface(display, surface, EGL_WIDTH, &w); 135 eglQuerySurface(display, surface, EGL_HEIGHT, &h); 136 137 engine->display = display; 138 engine->context = context; 139 engine->surface = surface; 140 141 /* Launch our ticker */ 142 Log::Info("Java layer initialising renderer at %g fps", 60.0f); 143 Ticker::Setup(60.0f); 144 Video::Setup(ivec2(w, h)); 145 146 return 0; 147 } 148 149 static void engine_draw_frame(AndroidAppData* engine) 150 { 151 if (!engine->display) 152 return; 153 154 Ticker::TickDraw(); 155 156 eglSwapBuffers(engine->display, engine->surface); 157 } 158 159 /** 160 * Tear down the EGL context currently associated with the display. 161 */ 162 static void engine_term_display(AndroidAppData* engine) 163 { 164 if (engine->display != EGL_NO_DISPLAY) 165 { 166 eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 167 if (engine->context != EGL_NO_CONTEXT) 168 { 169 eglDestroyContext(engine->display, engine->context); 170 } 171 if (engine->surface != EGL_NO_SURFACE) 172 { 173 eglDestroySurface(engine->display, engine->surface); 174 } 175 eglTerminate(engine->display); 176 } 177 engine->display = EGL_NO_DISPLAY; 178 engine->context = EGL_NO_CONTEXT; 179 engine->surface = EGL_NO_SURFACE; 180 } 181 182 /** 183 * Process the next input event. 184 */ 185 static int32_t engine_handle_input(android_app* native_app, AInputEvent* event) 186 { 187 AndroidAppData* engine = (AndroidAppData*)native_app->userData; 188 switch (AInputEvent_getType(event)) 189 { 190 case AINPUT_EVENT_TYPE_MOTION: 191 Input::SetMousePos(ivec2(AMotionEvent_getX(event, 0), 192 AMotionEvent_getY(event, 0))); 193 switch (AKeyEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK) 194 { 195 case AMOTION_EVENT_ACTION_DOWN: 196 Input::SetMouseButton(0); 197 break; 198 case AMOTION_EVENT_ACTION_UP: 199 Input::UnsetMouseButton(0); 200 break; 201 } 202 return 1; 203 } 204 return 0; 205 } 206 207 /** 208 * Process the next main command. 209 */ 210 static void engine_handle_cmd(android_app* native_app, int32_t cmd) 211 { 212 AndroidAppData* engine = (AndroidAppData*)native_app->userData; 213 switch (cmd) 214 { 215 case APP_CMD_SAVE_STATE: 216 /* The system has asked us to save our current state. Do so. */ 217 engine->m_native_app->savedState = malloc(sizeof(SavedState)); 218 *((SavedState*)engine->m_native_app->savedState) = engine->m_state; 219 engine->m_native_app->savedStateSize = sizeof(SavedState); 220 break; 221 case APP_CMD_INIT_WINDOW: 222 /* The window is being shown, get it ready. */ 223 if (engine->m_native_app->window != nullptr) 224 { 225 engine_init_display(engine); 226 engine_draw_frame(engine); 227 } 228 break; 229 case APP_CMD_TERM_WINDOW: 230 /* The window is being hidden or closed, clean it up. */ 231 engine_term_display(engine); 232 break; 233 case APP_CMD_GAINED_FOCUS: 234 break; 235 case APP_CMD_LOST_FOCUS: 236 /* FIXME: stop animating */ 237 engine_draw_frame(engine); 238 break; 239 } 240 } 241 242 /* FIXME: find a better way to pass this to the AndroidApp ctor. */ 243 AndroidAppData *g_data; 244 245 void android_main(android_app* native_app) 246 { 247 g_data = new AndroidAppData(); 248 249 /* Make sure glue isn't stripped */ 250 app_dummy(); 251 252 native_app->userData = g_data; 253 native_app->onAppCmd = engine_handle_cmd; 254 native_app->onInputEvent = engine_handle_input; 255 g_data->m_native_app = native_app; 256 257 if (native_app->savedState != nullptr) 258 { 259 /* We are starting with a previous saved state; restore from it */ 260 g_data->m_state = *(SavedState*)native_app->savedState; 261 } 262 71 263 int argc = 1; 72 264 char *argv[] = { "", nullptr }; … … 77 269 lol_android_main(argc, argv); 78 270 lol_android_main(argc, argv, env); 79 80 return nullptr; 81 } 82 83 AndroidApp::~AndroidApp() 84 { 85 } 86 87 }; 88 89 extern "C" jint 90 JNI_OnLoad(JavaVM* vm, void* reserved) 91 { 92 Log::Info("Java layer loading library, vm=0x%08lx", (long)(intptr_t)vm); 93 g_vm = vm; 94 return JNI_VERSION_1_4; 95 } 96 97 extern "C" void 98 Java_net_lolengine_LolActivity_nativeInit(JNIEnv* env, jobject thiz) 99 { 100 Log::Info("Java layer initialising activity 0x%08lx", (long)thiz); 101 env->NewGlobalRef(thiz); /* FIXME: never released! */ 102 g_activity = thiz; 103 } 104 105 extern "C" void 106 Java_net_lolengine_LolRenderer_nativeInit(JNIEnv* env) 107 { 108 /* Initialise app thread and wait for it to be ready, ie. set 109 * the FPS value at least. */ 110 g_main_thread = new Thread(lol::AndroidApp::MainRun, nullptr); 111 g_main_queue.Pop(); 112 113 /* Launch our ticker */ 114 Log::Info("Java layer initialising renderer at %g fps", g_fps); 115 Ticker::Setup(g_fps); 116 Video::Setup(ivec2(320, 200)); 117 118 /* Wake up app thread */ 119 g_main_queue.Pop(); 120 } 121 122 extern "C" void 123 Java_net_lolengine_LolRenderer_nativeResize(JNIEnv* env, jobject thiz, 124 jint w, jint h) 125 { 126 Log::Info("Java layer resizing to %i x %i", w, h); 127 Video::Setup(ivec2(w, h)); 128 } 129 130 extern "C" void 131 Java_net_lolengine_LolRenderer_nativeDone(JNIEnv* env) 132 { 133 /* FIXME: clean up */ 134 delete g_main_thread; 135 } 136 137 extern "C" void 138 Java_net_lolengine_LolView_nativePause(JNIEnv* env) 139 { 140 /* TODO: unimplemented */ 141 } 142 143 extern "C" void 144 Java_net_lolengine_LolView_nativeDown(JNIEnv* env) 145 { 146 Input::SetMouseButton(0); 147 } 148 149 extern "C" void 150 Java_net_lolengine_LolView_nativeUp(JNIEnv* env) 151 { 152 Input::UnsetMouseButton(0); 153 } 154 155 extern "C" void 156 Java_net_lolengine_LolView_nativeMove(JNIEnv* env, jobject thiz, 157 jint x, jint y) 158 { 159 Input::SetMousePos(ivec2(x, y)); 160 } 161 162 /* Call to render the next GL frame */ 163 extern "C" void 164 Java_net_lolengine_LolRenderer_nativeRender(JNIEnv* env) 165 { 166 Ticker::TickDraw(); 271 } 272 273 lol::AndroidApp::AndroidApp(char const *title, ivec2 res, float fps) 274 : m_data(g_data) 275 { 276 ; 277 } 278 279 void lol::AndroidApp::ShowPointer(bool show) 280 { 281 } 282 283 lol::AndroidApp::~AndroidApp() 284 { 285 engine_term_display(m_data); 286 delete m_data; 287 } 288 289 void lol::AndroidApp::Tick() 290 { 291 /* Read all pending events. */ 292 int ident; 293 int events; 294 struct android_poll_source* source; 295 296 /* Loop until all events are read, then continue to draw the next 297 * frame of animation. */ 298 while ((ident = ALooper_pollAll(0, nullptr, &events, 299 (void**)&source)) >= 0) 300 { 301 /* Process this event */ 302 if (source) 303 source->process(m_data->m_native_app, source); 304 305 /* Check if we are exiting */ 306 if (m_data->m_native_app->destroyRequested != 0) 307 Ticker::Shutdown(); 308 } 309 310 engine_draw_frame(m_data); 167 311 } 168 312 … … 171 315 * a separate thread. 172 316 */ 173 void lol_android_main(void) {} 317 void lol_android_main(void) 318 { 319 } 320 174 321 void lol_android_main(int argc, char **argv) 175 322 { 176 323 UNUSED(argc, argv); 177 324 } 325 178 326 void lol_android_main(int argc, char **argv, char **envp) 179 327 {
Note: See TracChangeset
for help on using the changeset viewer.