nuclear@0: #include nuclear@0: #include nuclear@5: #include nuclear@0: #include nuclear@1: #include nuclear@16: #include "amain.h" nuclear@1: #include "native_glue.h" nuclear@24: #include nuclear@24: #include "sensordef.h" nuclear@0: #include "logger.h" nuclear@0: #include "game.h" nuclear@6: #include "camera.h" nuclear@0: #include "timer.h" nuclear@0: nuclear@24: #define EVID_SENS_ACCEL (LOOPER_ID_USER + 0) nuclear@24: #define EVID_SENS_ROT (LOOPER_ID_USER + 1) 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@24: static int redisp_pending = 1; /* TODO stop busy-looping */ nuclear@24: nuclear@23: static int width, 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@24: static ASensorManager *sensorman; nuclear@24: static ASensor const *sens_accel; nuclear@24: static ASensor const *sens_rot; nuclear@24: static ASensorEventQueue *sens_evq_accel; nuclear@24: static ASensorEventQueue *sens_evq_rot; 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@24: { nuclear@24: int i, num_sensors; nuclear@24: ASensorList sensors; nuclear@24: nuclear@24: sensorman = ASensorManager_getInstance(); nuclear@24: num_sensors = ASensorManager_getSensorList(sensorman, &sensors); nuclear@24: printf("found %d sensors:\n", num_sensors); nuclear@24: nuclear@24: for(i=0; ilooper, nuclear@24: EVID_SENS_ACCEL, 0, 0))) { nuclear@24: fprintf(stderr, "failed to create acceleration sensor event queue\n"); nuclear@24: return; nuclear@24: } nuclear@24: nuclear@24: if(!(sens_evq_rot = ASensorManager_createEventQueue(sensorman, app->looper, nuclear@24: EVID_SENS_ROT, 0, 0))) { nuclear@24: fprintf(stderr, "failed to create rotation sensor event queue\n"); nuclear@24: return; nuclear@24: } nuclear@24: } nuclear@24: nuclear@24: nuclear@0: for(;;) { nuclear@24: int num_events, evid; nuclear@0: struct android_poll_source *pollsrc; nuclear@24: ASensorEvent sens_ev; nuclear@0: nuclear@24: while((evid = ALooper_pollAll(redisp_pending ? 0 : -1, 0, &num_events, (void**)&pollsrc)) >= 0) { nuclear@24: nuclear@24: switch(evid) { nuclear@24: case EVID_SENS_ACCEL: nuclear@24: if(sens_accel) { nuclear@24: float accel[3]; nuclear@24: while(ASensorEventQueue_getEvents(sens_evq_accel, &sens_ev, 1) > 0) { nuclear@24: accel[0] = sens_ev.acceleration.x; nuclear@24: accel[1] = sens_ev.acceleration.y; nuclear@24: accel[2] = sens_ev.acceleration.z; nuclear@24: } nuclear@24: nuclear@24: // TODO: integrate over time nuclear@24: game_6dof_translation(accel[0], accel[1], accel[2]); nuclear@24: } nuclear@24: break; nuclear@24: nuclear@24: case EVID_SENS_ROT: nuclear@24: if(sens_rot) { nuclear@24: float qrot[4]; nuclear@24: while(ASensorEventQueue_getEvents(sens_evq_rot, &sens_ev, 1) > 0) { nuclear@24: int i; nuclear@24: for(i=0; i<4; i++) { nuclear@24: qrot[i] = sens_ev.data[i]; nuclear@24: } nuclear@24: } nuclear@24: nuclear@24: game_6dof_rotation(qrot[0], qrot[1], qrot[2], qrot[3]); nuclear@24: } nuclear@24: break; nuclear@24: nuclear@24: default: nuclear@24: if(pollsrc) { nuclear@24: pollsrc->process(app, pollsrc); nuclear@24: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(app->destroyRequested) { nuclear@1: (*jvm)->DetachCurrentThread(jvm); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@24: if(init_done && redisp_pending) { 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@24: printf("Command: APP_CMD_GAINED_FOCUS\n"); nuclear@24: if(sens_accel) { nuclear@24: ASensorEventQueue_enableSensor(sens_evq_accel, sens_accel); nuclear@24: ASensorEventQueue_setEventRate(sens_evq_accel, sens_accel, 1000000 / 60); nuclear@24: } nuclear@24: if(sens_rot) { nuclear@24: ASensorEventQueue_enableSensor(sens_evq_rot, sens_rot); nuclear@24: ASensorEventQueue_setEventRate(sens_evq_rot, sens_rot, 1000000 / 60); nuclear@24: } nuclear@8: //cam_start_video(); nuclear@0: break; nuclear@0: nuclear@0: case APP_CMD_LOST_FOCUS: nuclear@0: /* app lost focus */ nuclear@24: printf("Command: APP_CMD_LOST_FOCUS\n"); nuclear@24: if(sens_accel) { nuclear@24: ASensorEventQueue_disableSensor(sens_evq_accel, sens_accel); nuclear@24: } nuclear@24: if(sens_rot) { nuclear@24: ASensorEventQueue_disableSensor(sens_evq_rot, sens_rot); nuclear@24: } 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@23: if(nx != width || ny != height) { nuclear@0: game_reshape(nx, ny); nuclear@23: width = nx; nuclear@23: 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@23: eglQuerySurface(dpy, surf, EGL_WIDTH, &width); nuclear@23: eglQuerySurface(dpy, surf, EGL_HEIGHT, &height); nuclear@23: game_reshape(width, 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: }