mirror of https://github.com/buggins/dlangui.git
android support refactoring #119
This commit is contained in:
parent
2325d3e4df
commit
e633218cb5
|
@ -99,7 +99,7 @@ class AndroidPlatform : Platform {
|
||||||
this(android_app* state) {
|
this(android_app* state) {
|
||||||
_appstate = state;
|
_appstate = state;
|
||||||
memset(&_engine, 0, engine.sizeof);
|
memset(&_engine, 0, engine.sizeof);
|
||||||
state.userData = &_engine;
|
state.userData = cast(void*)this;
|
||||||
state.onAppCmd = &engine_handle_cmd;
|
state.onAppCmd = &engine_handle_cmd;
|
||||||
state.onInputEvent = &engine_handle_input;
|
state.onInputEvent = &engine_handle_input;
|
||||||
_engine.app = state;
|
_engine.app = state;
|
||||||
|
@ -119,7 +119,174 @@ class AndroidPlatform : Platform {
|
||||||
}
|
}
|
||||||
|
|
||||||
~this() {
|
~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
|
// Drawing is throttled to the screen update rate, so there
|
||||||
// is no need to do timing here.
|
// is no need to do timing here.
|
||||||
engine_draw_frame(&_engine);
|
engine_draw_frame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,172 +431,20 @@ struct engine {
|
||||||
saved_state state;
|
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.
|
* Process the next input event.
|
||||||
*/
|
*/
|
||||||
extern(C) int engine_handle_input(android_app* app, AInputEvent* event) {
|
extern(C) int engine_handle_input(android_app* app, AInputEvent* event) {
|
||||||
engine* engine = cast(engine*)app.userData;
|
AndroidPlatform p = cast(AndroidPlatform)app.userData;
|
||||||
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
|
return p.handle_input(event);
|
||||||
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.
|
* Process the next main command.
|
||||||
*/
|
*/
|
||||||
extern(C) void engine_handle_cmd(android_app* app, int cmd) {
|
extern(C) void engine_handle_cmd(android_app* app, int cmd) {
|
||||||
engine* engine = cast(engine*)app.userData;
|
AndroidPlatform p = cast(AndroidPlatform)app.userData;
|
||||||
switch (cmd) {
|
p.handle_cmd(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(){}
|
void main(){}
|
||||||
|
|
Loading…
Reference in New Issue