nuclear@0: #include nuclear@0: #include nuclear@5: #include nuclear@0: #include nuclear@1: #include nuclear@1: #include "native_glue.h" nuclear@0: #include "logger.h" nuclear@0: #include "game.h" nuclear@6: #include "camera.h" nuclear@0: #include "timer.h" nuclear@0: nuclear@0: nuclear@0: static void handle_command(struct android_app *app, int32_t cmd); nuclear@0: static int handle_input(struct android_app *app, AInputEvent *ev); nuclear@0: static int handle_touch_input(struct android_app *app, AInputEvent *ev); nuclear@0: static int init_gl(void); nuclear@0: static void destroy_gl(void); nuclear@0: nuclear@0: static EGLDisplay dpy; nuclear@0: static EGLSurface surf; nuclear@0: static EGLContext ctx; nuclear@0: nuclear@0: static struct android_app *app; nuclear@0: static int win_width, win_height; nuclear@0: static int init_done; nuclear@0: nuclear@1: static JavaVM *jvm; nuclear@1: static JNIEnv *jni; nuclear@1: static jclass activity_class; nuclear@1: nuclear@1: nuclear@1: nuclear@0: void android_main(struct android_app *app_ptr) nuclear@0: { nuclear@0: app_dummy(); nuclear@0: app = app_ptr; nuclear@0: nuclear@0: app->onAppCmd = handle_command; nuclear@0: app->onInputEvent = handle_input; nuclear@0: nuclear@0: start_logger(); nuclear@0: nuclear@1: jvm = app->activity->vm; nuclear@1: if((*jvm)->AttachCurrentThread(jvm, &jni, 0) != 0) { nuclear@1: fprintf(stderr, "failed to attach native thread to Java VM\n"); nuclear@1: exit(1); nuclear@1: } nuclear@2: activity_class = (*jni)->GetObjectClass(jni, app->activity->clazz); nuclear@1: nuclear@0: for(;;) { nuclear@0: int num_events; nuclear@0: struct android_poll_source *pollsrc; nuclear@0: nuclear@0: while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) { nuclear@0: if(pollsrc) { nuclear@0: pollsrc->process(app, pollsrc); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(app->destroyRequested) { nuclear@1: (*jvm)->DetachCurrentThread(jvm); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: if(init_done) { nuclear@0: game_display(get_time_msec()); nuclear@0: eglSwapBuffers(dpy, surf); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void set_mouse_pos(int x, int y) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: void set_mouse_cursor(int enable) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: static void handle_command(struct android_app *app, int32_t cmd) nuclear@0: { nuclear@6: struct cam_android_platform_data cam_data; nuclear@6: nuclear@0: switch(cmd) { nuclear@0: case APP_CMD_SAVE_STATE: nuclear@0: /* save the application state to be reloaded on restart if needed */ nuclear@0: break; nuclear@0: nuclear@0: case APP_CMD_INIT_WINDOW: nuclear@0: if(init_gl() == -1) { nuclear@0: exit(1); nuclear@0: } nuclear@5: nuclear@6: cam_data.vm = jvm; nuclear@6: cam_data.jni = jni; nuclear@6: cam_data.activity_class = activity_class; nuclear@6: nuclear@6: if(cam_init(&cam_data) == -1) { nuclear@6: exit(1); nuclear@6: } nuclear@5: nuclear@0: /* initialize the application */ nuclear@0: if(game_init() == -1) { nuclear@0: exit(1); /* initialization failed, quit */ nuclear@0: } nuclear@0: init_done = 1; nuclear@0: break; nuclear@0: nuclear@0: case APP_CMD_TERM_WINDOW: nuclear@0: /* cleanup */ nuclear@0: init_done = 0; nuclear@0: game_shutdown(); nuclear@0: destroy_gl(); nuclear@0: break; nuclear@0: nuclear@0: case APP_CMD_GAINED_FOCUS: nuclear@0: /* app focused */ nuclear@8: //cam_start_video(); nuclear@0: break; nuclear@0: nuclear@0: case APP_CMD_LOST_FOCUS: nuclear@0: /* app lost focus */ nuclear@8: //cam_stop_video(); nuclear@0: break; nuclear@0: nuclear@0: case APP_CMD_WINDOW_RESIZED: nuclear@0: case APP_CMD_CONFIG_CHANGED: nuclear@0: { nuclear@0: int nx = ANativeWindow_getWidth(app->window); nuclear@0: int ny = ANativeWindow_getHeight(app->window); nuclear@0: if(nx != win_width || ny != win_height) { nuclear@0: game_reshape(nx, ny); nuclear@0: win_width = nx; nuclear@0: win_height = ny; nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static int handle_input(struct android_app *app, AInputEvent *ev) nuclear@0: { nuclear@0: int evtype = AInputEvent_getType(ev); nuclear@0: nuclear@0: switch(evtype) { nuclear@0: case AINPUT_EVENT_TYPE_MOTION: nuclear@0: return handle_touch_input(app, ev); nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: #define MAX_TOUCH_IDS 32 nuclear@0: nuclear@0: static int handle_touch_input(struct android_app *app, AInputEvent *ev) nuclear@0: { nuclear@0: int x, y, idx, touch_id; nuclear@0: unsigned int action; nuclear@0: static int prev_pos[MAX_TOUCH_IDS][2]; nuclear@0: nuclear@0: action = AMotionEvent_getAction(ev); nuclear@0: nuclear@0: idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> nuclear@0: AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; nuclear@0: touch_id = AMotionEvent_getPointerId(ev, idx); nuclear@0: nuclear@0: x = AMotionEvent_getX(ev, idx); nuclear@0: y = AMotionEvent_getY(ev, idx); nuclear@0: nuclear@0: switch(action & AMOTION_EVENT_ACTION_MASK) { nuclear@0: case AMOTION_EVENT_ACTION_DOWN: nuclear@0: case AMOTION_EVENT_ACTION_POINTER_DOWN: nuclear@0: game_mouse_button(touch_id, 0, 1, x, y); nuclear@0: if(touch_id < MAX_TOUCH_IDS) { nuclear@0: prev_pos[touch_id][0] = x; nuclear@0: prev_pos[touch_id][1] = y; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case AMOTION_EVENT_ACTION_UP: nuclear@0: case AMOTION_EVENT_ACTION_POINTER_UP: nuclear@0: game_mouse_button(touch_id, 0, 0, x, y); nuclear@0: if(touch_id < MAX_TOUCH_IDS) { nuclear@0: prev_pos[touch_id][0] = x; nuclear@0: prev_pos[touch_id][1] = y; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case AMOTION_EVENT_ACTION_MOVE: nuclear@0: { nuclear@0: int i, pcount = AMotionEvent_getPointerCount(ev); nuclear@0: for(i=0; iwindow, 0, 0, vis); nuclear@0: nuclear@0: if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) { nuclear@0: fprintf(stderr, "failed to create window\n"); nuclear@0: destroy_gl(); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) { nuclear@0: fprintf(stderr, "failed to create OpenGL ES context\n"); nuclear@0: destroy_gl(); nuclear@0: return -1; nuclear@0: } nuclear@0: eglMakeCurrent(dpy, surf, surf, ctx); nuclear@0: nuclear@0: eglQuerySurface(dpy, surf, EGL_WIDTH, &win_width); nuclear@0: eglQuerySurface(dpy, surf, EGL_HEIGHT, &win_height); nuclear@0: game_reshape(win_width, win_height); nuclear@0: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static void destroy_gl(void) nuclear@0: { nuclear@0: if(!dpy) return; nuclear@0: nuclear@0: eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); nuclear@0: nuclear@0: if(ctx) { nuclear@0: eglDestroyContext(dpy, ctx); nuclear@0: ctx = 0; nuclear@0: } nuclear@0: if(surf) { nuclear@0: eglDestroySurface(dpy, surf); nuclear@0: surf = 0; nuclear@0: } nuclear@0: nuclear@0: eglTerminate(dpy); nuclear@0: dpy = 0; nuclear@0: }