From e633218cb51d4ef694ebf38eb714b430eef427e6 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Wed, 20 Apr 2016 15:47:30 +0300 Subject: [PATCH] android support refactoring #119 --- examples/android/jni/main.d | 333 +++++++++++++++++++----------------- 1 file changed, 174 insertions(+), 159 deletions(-) diff --git a/examples/android/jni/main.d b/examples/android/jni/main.d index 8ddf710a..5b5f8c46 100644 --- a/examples/android/jni/main.d +++ b/examples/android/jni/main.d @@ -99,7 +99,7 @@ class AndroidPlatform : Platform { this(android_app* state) { _appstate = state; memset(&_engine, 0, engine.sizeof); - state.userData = &_engine; + state.userData = cast(void*)this; state.onAppCmd = &engine_handle_cmd; state.onInputEvent = &engine_handle_input; _engine.app = state; @@ -119,7 +119,174 @@ class AndroidPlatform : Platform { } ~this() { - engine_term_display(&_engine); + engine_term_display(); + } + + + /** + * Initialize an EGL context for the current display. + */ + int engine_init_display() { + // initialize OpenGL ES and EGL + + /* + * Here specify the attributes of the desired configuration. + * Below, we select an EGLConfig with at least 8 bits per color + * component compatible with on-screen windows + */ + const(EGLint)[9] attribs = [ + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_NONE + ]; + EGLint w, h, dummy, format; + EGLint numConfigs; + EGLConfig config; + EGLSurface surface; + EGLContext context; + + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + eglInitialize(display, null, null); + + /* Here, the application chooses the configuration it desires. In this + * sample, we have a very simplified selection process, where we pick + * the first EGLConfig that matches our criteria */ + eglChooseConfig(display, attribs.ptr, &config, 1, &numConfigs); + + /* 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. */ + eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); + + ANativeWindow_setBuffersGeometry(_engine.app.window, 0, 0, format); + + surface = eglCreateWindowSurface(display, config, _engine.app.window, null); + context = eglCreateContext(display, config, null, null); + + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { + LOGW("Unable to eglMakeCurrent"); + return -1; + } + + eglQuerySurface(display, surface, EGL_WIDTH, &w); + eglQuerySurface(display, surface, EGL_HEIGHT, &h); + + _engine.display = display; + _engine.context = context; + _engine.surface = surface; + _engine.width = w; + _engine.height = h; + _engine.state.angle = 0; + + // Initialize GL state. + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glEnable(GL_CULL_FACE); + //glShadeModel(GL_SMOOTH); + glDisable(GL_DEPTH_TEST); + + return 0; + } + + /** + * Just the current frame in the display. + */ + void engine_draw_frame() { + if (_engine.display == null) { + // No display. + return; + } + + // Just fill the screen with a color. + glClearColor(_engine.state.x/_engine.width, _engine.state.angle, + _engine.state.y/_engine.height, 1); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(_engine.display, _engine.surface); + } + + /** + * Tear down the EGL context currently associated with the display. + */ + void engine_term_display() { + if (_engine.display != EGL_NO_DISPLAY) { + eglMakeCurrent(_engine.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (_engine.context != EGL_NO_CONTEXT) { + eglDestroyContext(_engine.display, _engine.context); + } + if (_engine.surface != EGL_NO_SURFACE) { + eglDestroySurface(_engine.display, _engine.surface); + } + eglTerminate(_engine.display); + } + _engine.animating = 0; + _engine.display = EGL_NO_DISPLAY; + _engine.context = EGL_NO_CONTEXT; + _engine.surface = EGL_NO_SURFACE; + } + + /** + * Process the next input event. + */ + int handle_input(AInputEvent* event) { + if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { + _engine.animating = 1; + _engine.state.x = AMotionEvent_getX(event, 0); + _engine.state.y = AMotionEvent_getY(event, 0); + return 1; + } + return 0; + } + + /** + * Process the next main command. + */ + void handle_cmd(int cmd) { + switch (cmd) { + case APP_CMD_SAVE_STATE: + // The system has asked us to save our current state. Do so. + _engine.app.savedState = malloc(saved_state.sizeof); + *(cast(saved_state*)_engine.app.savedState) = _engine.state; + _engine.app.savedStateSize = saved_state.sizeof; + break; + case APP_CMD_INIT_WINDOW: + // The window is being shown, get it ready. + if (_engine.app.window != null) { + engine_init_display(); + engine_draw_frame(); + } + break; + case APP_CMD_TERM_WINDOW: + // The window is being hidden or closed, clean it up. + engine_term_display(); + break; + case APP_CMD_GAINED_FOCUS: + // When our app gains focus, we start monitoring the accelerometer. + if (_engine.accelerometerSensor != null) { + ASensorEventQueue_enableSensor(_engine.sensorEventQueue, + _engine.accelerometerSensor); + // We'd like to get 60 events per second (in us). + ASensorEventQueue_setEventRate(_engine.sensorEventQueue, + _engine.accelerometerSensor, (1000L/60)*1000); + } + break; + case 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 (_engine.accelerometerSensor != null) { + ASensorEventQueue_disableSensor(_engine.sensorEventQueue, + _engine.accelerometerSensor); + } + // Also stop animating. + _engine.animating = 0; + engine_draw_frame(); + break; + default: + break; + } } /** @@ -207,7 +374,7 @@ class AndroidPlatform : Platform { // Drawing is throttled to the screen update rate, so there // is no need to do timing here. - engine_draw_frame(&_engine); + engine_draw_frame(); } } } @@ -264,172 +431,20 @@ struct engine { saved_state state; } -/** - * Initialize an EGL context for the current display. - */ -int engine_init_display(engine* engine) { - // initialize OpenGL ES and EGL - - /* - * Here specify the attributes of the desired configuration. - * Below, we select an EGLConfig with at least 8 bits per color - * component compatible with on-screen windows - */ - const(EGLint)[9] attribs = [ - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_BLUE_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_RED_SIZE, 8, - EGL_NONE - ]; - EGLint w, h, dummy, format; - EGLint numConfigs; - EGLConfig config; - EGLSurface surface; - EGLContext context; - - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - - eglInitialize(display, null, null); - - /* Here, the application chooses the configuration it desires. In this - * sample, we have a very simplified selection process, where we pick - * the first EGLConfig that matches our criteria */ - eglChooseConfig(display, attribs.ptr, &config, 1, &numConfigs); - - /* 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. */ - eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format); - - ANativeWindow_setBuffersGeometry(engine.app.window, 0, 0, format); - - surface = eglCreateWindowSurface(display, config, engine.app.window, null); - context = eglCreateContext(display, config, null, null); - - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { - LOGW("Unable to eglMakeCurrent"); - return -1; - } - - eglQuerySurface(display, surface, EGL_WIDTH, &w); - eglQuerySurface(display, surface, EGL_HEIGHT, &h); - - engine.display = display; - engine.context = context; - engine.surface = surface; - engine.width = w; - engine.height = h; - engine.state.angle = 0; - - // Initialize GL state. - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); - glEnable(GL_CULL_FACE); - //glShadeModel(GL_SMOOTH); - glDisable(GL_DEPTH_TEST); - - return 0; -} - -/** - * Just the current frame in the display. - */ -void engine_draw_frame(engine* engine) { - if (engine.display == null) { - // No display. - return; - } - - // Just fill the screen with a color. - glClearColor(engine.state.x/engine.width, engine.state.angle, - engine.state.y/engine.height, 1); - glClear(GL_COLOR_BUFFER_BIT); - - eglSwapBuffers(engine.display, engine.surface); -} - -/** - * Tear down the EGL context currently associated with the display. - */ -void engine_term_display(engine* engine) { - if (engine.display != EGL_NO_DISPLAY) { - eglMakeCurrent(engine.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (engine.context != EGL_NO_CONTEXT) { - eglDestroyContext(engine.display, engine.context); - } - if (engine.surface != EGL_NO_SURFACE) { - eglDestroySurface(engine.display, engine.surface); - } - eglTerminate(engine.display); - } - engine.animating = 0; - engine.display = EGL_NO_DISPLAY; - engine.context = EGL_NO_CONTEXT; - engine.surface = EGL_NO_SURFACE; -} - /** * Process the next input event. */ extern(C) int engine_handle_input(android_app* app, AInputEvent* event) { - engine* engine = cast(engine*)app.userData; - if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) { - engine.animating = 1; - engine.state.x = AMotionEvent_getX(event, 0); - engine.state.y = AMotionEvent_getY(event, 0); - return 1; - } - return 0; + AndroidPlatform p = cast(AndroidPlatform)app.userData; + return p.handle_input(event); } /** * Process the next main command. */ extern(C) void engine_handle_cmd(android_app* app, int cmd) { - engine* engine = cast(engine*)app.userData; - switch (cmd) { - case APP_CMD_SAVE_STATE: - // The system has asked us to save our current state. Do so. - engine.app.savedState = malloc(saved_state.sizeof); - *(cast(saved_state*)engine.app.savedState) = engine.state; - engine.app.savedStateSize = saved_state.sizeof; - break; - case APP_CMD_INIT_WINDOW: - // The window is being shown, get it ready. - if (engine.app.window != null) { - engine_init_display(engine); - engine_draw_frame(engine); - } - break; - case APP_CMD_TERM_WINDOW: - // The window is being hidden or closed, clean it up. - engine_term_display(engine); - break; - case APP_CMD_GAINED_FOCUS: - // When our app gains focus, we start monitoring the accelerometer. - if (engine.accelerometerSensor != null) { - ASensorEventQueue_enableSensor(engine.sensorEventQueue, - engine.accelerometerSensor); - // We'd like to get 60 events per second (in us). - ASensorEventQueue_setEventRate(engine.sensorEventQueue, - engine.accelerometerSensor, (1000L/60)*1000); - } - break; - case 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 (engine.accelerometerSensor != null) { - ASensorEventQueue_disableSensor(engine.sensorEventQueue, - engine.accelerometerSensor); - } - // Also stop animating. - engine.animating = 0; - engine_draw_frame(engine); - break; - default: - break; - } + AndroidPlatform p = cast(AndroidPlatform)app.userData; + p.handle_cmd(cmd); } void main(){}