3dphotoshoot

annotate src/android/amain.c @ 25:ac80210d5fbe

preparing a pc version for easier development of non-android-specifics
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 18 Jun 2015 03:12:30 +0300
parents 2712c5da2e00
children
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@5 3 #include <assert.h>
nuclear@0 4 #include <EGL/egl.h>
nuclear@1 5 #include <jni.h>
nuclear@16 6 #include "amain.h"
nuclear@1 7 #include "native_glue.h"
nuclear@24 8 #include <android/sensor.h>
nuclear@24 9 #include "sensordef.h"
nuclear@0 10 #include "logger.h"
nuclear@0 11 #include "game.h"
nuclear@6 12 #include "camera.h"
nuclear@0 13 #include "timer.h"
nuclear@0 14
nuclear@24 15 #define EVID_SENS_ACCEL (LOOPER_ID_USER + 0)
nuclear@24 16 #define EVID_SENS_ROT (LOOPER_ID_USER + 1)
nuclear@0 17
nuclear@0 18 static void handle_command(struct android_app *app, int32_t cmd);
nuclear@0 19 static int handle_input(struct android_app *app, AInputEvent *ev);
nuclear@0 20 static int handle_touch_input(struct android_app *app, AInputEvent *ev);
nuclear@0 21 static int init_gl(void);
nuclear@0 22 static void destroy_gl(void);
nuclear@0 23
nuclear@0 24 static EGLDisplay dpy;
nuclear@0 25 static EGLSurface surf;
nuclear@0 26 static EGLContext ctx;
nuclear@0 27
nuclear@24 28 static int redisp_pending = 1; /* TODO stop busy-looping */
nuclear@24 29
nuclear@23 30 static int width, height;
nuclear@0 31 static int init_done;
nuclear@0 32
nuclear@1 33 static JavaVM *jvm;
nuclear@1 34 static JNIEnv *jni;
nuclear@1 35 static jclass activity_class;
nuclear@1 36
nuclear@24 37 static ASensorManager *sensorman;
nuclear@24 38 static ASensor const *sens_accel;
nuclear@24 39 static ASensor const *sens_rot;
nuclear@24 40 static ASensorEventQueue *sens_evq_accel;
nuclear@24 41 static ASensorEventQueue *sens_evq_rot;
nuclear@1 42
nuclear@0 43 void android_main(struct android_app *app_ptr)
nuclear@0 44 {
nuclear@0 45 app_dummy();
nuclear@0 46 app = app_ptr;
nuclear@0 47
nuclear@0 48 app->onAppCmd = handle_command;
nuclear@0 49 app->onInputEvent = handle_input;
nuclear@0 50
nuclear@0 51 start_logger();
nuclear@0 52
nuclear@1 53 jvm = app->activity->vm;
nuclear@1 54 if((*jvm)->AttachCurrentThread(jvm, &jni, 0) != 0) {
nuclear@1 55 fprintf(stderr, "failed to attach native thread to Java VM\n");
nuclear@1 56 exit(1);
nuclear@1 57 }
nuclear@2 58 activity_class = (*jni)->GetObjectClass(jni, app->activity->clazz);
nuclear@1 59
nuclear@24 60 {
nuclear@24 61 int i, num_sensors;
nuclear@24 62 ASensorList sensors;
nuclear@24 63
nuclear@24 64 sensorman = ASensorManager_getInstance();
nuclear@24 65 num_sensors = ASensorManager_getSensorList(sensorman, &sensors);
nuclear@24 66 printf("found %d sensors:\n", num_sensors);
nuclear@24 67
nuclear@24 68 for(i=0; i<num_sensors; i++) {
nuclear@24 69 ASensor const *sens = sensors[i];
nuclear@24 70 int type = ASensor_getType(sens);
nuclear@24 71 float res = ASensor_getResolution(sens);
nuclear@24 72 int mindel = ASensor_getMinDelay(sens);
nuclear@24 73
nuclear@24 74 printf(" %d) [%d:%s] %s - %s (res: %g, min-delay: %d)\n", i,
nuclear@24 75 type, sensor_typestr(type), ASensor_getName(sens),
nuclear@24 76 ASensor_getVendor(sens), res, mindel);
nuclear@24 77 }
nuclear@24 78
nuclear@24 79 // try to get a linear acceleration sensor
nuclear@24 80 printf("Requesting \"linear acceleration\" sensor ...\n");
nuclear@24 81 if(!(sens_accel = ASensorManager_getDefaultSensor(sensorman, SENSOR_TYPE_LINEAR_ACCELERATION))) {
nuclear@24 82 fprintf(stderr, "No linear acceleration sensor found, aborting!\n");
nuclear@24 83 return;
nuclear@24 84 }
nuclear@24 85
nuclear@24 86 // try to get a game rotation vector sensor
nuclear@24 87 printf("Requesting \"game rotation vector\" sensor ...\n");
nuclear@24 88 if(!(sens_rot = ASensorManager_getDefaultSensor(sensorman, SENSOR_TYPE_GAME_ROTATION_VECTOR))) {
nuclear@24 89 printf("Requesting \"rotation vector\" sensor ...\n");
nuclear@24 90 if(!(sens_rot = ASensorManager_getDefaultSensor(sensorman, SENSOR_TYPE_ROTATION_VECTOR))) {
nuclear@24 91 fprintf(stderr, "No rotation sensor found, aborting!\n");
nuclear@24 92 return;
nuclear@24 93 }
nuclear@24 94 }
nuclear@24 95
nuclear@24 96 if(!(sens_evq_accel = ASensorManager_createEventQueue(sensorman, app->looper,
nuclear@24 97 EVID_SENS_ACCEL, 0, 0))) {
nuclear@24 98 fprintf(stderr, "failed to create acceleration sensor event queue\n");
nuclear@24 99 return;
nuclear@24 100 }
nuclear@24 101
nuclear@24 102 if(!(sens_evq_rot = ASensorManager_createEventQueue(sensorman, app->looper,
nuclear@24 103 EVID_SENS_ROT, 0, 0))) {
nuclear@24 104 fprintf(stderr, "failed to create rotation sensor event queue\n");
nuclear@24 105 return;
nuclear@24 106 }
nuclear@24 107 }
nuclear@24 108
nuclear@24 109
nuclear@0 110 for(;;) {
nuclear@24 111 int num_events, evid;
nuclear@0 112 struct android_poll_source *pollsrc;
nuclear@24 113 ASensorEvent sens_ev;
nuclear@0 114
nuclear@24 115 while((evid = ALooper_pollAll(redisp_pending ? 0 : -1, 0, &num_events, (void**)&pollsrc)) >= 0) {
nuclear@24 116
nuclear@24 117 switch(evid) {
nuclear@24 118 case EVID_SENS_ACCEL:
nuclear@24 119 if(sens_accel) {
nuclear@25 120 static double prev_sec = -1.0;
nuclear@25 121 double sec, dt;
nuclear@25 122 double accel[3] = {0, 0, 0};
nuclear@25 123 static double velocity[3];
nuclear@25 124
nuclear@24 125 while(ASensorEventQueue_getEvents(sens_evq_accel, &sens_ev, 1) > 0) {
nuclear@25 126 accel[0] += sens_ev.acceleration.x;
nuclear@25 127 accel[1] += sens_ev.acceleration.y;
nuclear@25 128 accel[2] += sens_ev.acceleration.z;
nuclear@24 129 }
nuclear@24 130
nuclear@25 131 sec = get_time_sec();
nuclear@25 132 dt = prev_sec >= 0.0 ? sec - prev_sec : 0.0;
nuclear@25 133 prev_sec = sec;
nuclear@25 134
nuclear@25 135 velocity[0] += accel[0] * dt;
nuclear@25 136 velocity[1] += accel[1] * dt;
nuclear@25 137 velocity[2] += accel[2] * dt;
nuclear@25 138
nuclear@25 139 game_6dof_translation(velocity[0] * dt, velocity[1] * dt, velocity[2] * dt);
nuclear@24 140 }
nuclear@24 141 break;
nuclear@24 142
nuclear@24 143 case EVID_SENS_ROT:
nuclear@24 144 if(sens_rot) {
nuclear@24 145 float qrot[4];
nuclear@24 146 while(ASensorEventQueue_getEvents(sens_evq_rot, &sens_ev, 1) > 0) {
nuclear@24 147 int i;
nuclear@24 148 for(i=0; i<4; i++) {
nuclear@24 149 qrot[i] = sens_ev.data[i];
nuclear@24 150 }
nuclear@24 151 }
nuclear@24 152
nuclear@24 153 game_6dof_rotation(qrot[0], qrot[1], qrot[2], qrot[3]);
nuclear@24 154 }
nuclear@24 155 break;
nuclear@24 156
nuclear@24 157 default:
nuclear@24 158 if(pollsrc) {
nuclear@24 159 pollsrc->process(app, pollsrc);
nuclear@24 160 }
nuclear@0 161 }
nuclear@0 162 }
nuclear@0 163
nuclear@0 164 if(app->destroyRequested) {
nuclear@1 165 (*jvm)->DetachCurrentThread(jvm);
nuclear@0 166 return;
nuclear@0 167 }
nuclear@0 168
nuclear@24 169 if(init_done && redisp_pending) {
nuclear@0 170 game_display(get_time_msec());
nuclear@0 171 eglSwapBuffers(dpy, surf);
nuclear@0 172 }
nuclear@0 173 }
nuclear@0 174 }
nuclear@0 175
nuclear@0 176 void set_mouse_pos(int x, int y)
nuclear@0 177 {
nuclear@0 178 }
nuclear@0 179
nuclear@0 180 void set_mouse_cursor(int enable)
nuclear@0 181 {
nuclear@0 182 }
nuclear@0 183
nuclear@0 184 static void handle_command(struct android_app *app, int32_t cmd)
nuclear@0 185 {
nuclear@6 186 struct cam_android_platform_data cam_data;
nuclear@6 187
nuclear@0 188 switch(cmd) {
nuclear@0 189 case APP_CMD_SAVE_STATE:
nuclear@0 190 /* save the application state to be reloaded on restart if needed */
nuclear@0 191 break;
nuclear@0 192
nuclear@0 193 case APP_CMD_INIT_WINDOW:
nuclear@0 194 if(init_gl() == -1) {
nuclear@0 195 exit(1);
nuclear@0 196 }
nuclear@5 197
nuclear@6 198 cam_data.vm = jvm;
nuclear@6 199 cam_data.jni = jni;
nuclear@6 200 cam_data.activity_class = activity_class;
nuclear@6 201
nuclear@6 202 if(cam_init(&cam_data) == -1) {
nuclear@6 203 exit(1);
nuclear@6 204 }
nuclear@5 205
nuclear@0 206 /* initialize the application */
nuclear@0 207 if(game_init() == -1) {
nuclear@0 208 exit(1); /* initialization failed, quit */
nuclear@0 209 }
nuclear@0 210 init_done = 1;
nuclear@0 211 break;
nuclear@0 212
nuclear@0 213 case APP_CMD_TERM_WINDOW:
nuclear@0 214 /* cleanup */
nuclear@0 215 init_done = 0;
nuclear@0 216 game_shutdown();
nuclear@0 217 destroy_gl();
nuclear@0 218 break;
nuclear@0 219
nuclear@0 220 case APP_CMD_GAINED_FOCUS:
nuclear@0 221 /* app focused */
nuclear@24 222 printf("Command: APP_CMD_GAINED_FOCUS\n");
nuclear@24 223 if(sens_accel) {
nuclear@24 224 ASensorEventQueue_enableSensor(sens_evq_accel, sens_accel);
nuclear@24 225 ASensorEventQueue_setEventRate(sens_evq_accel, sens_accel, 1000000 / 60);
nuclear@24 226 }
nuclear@24 227 if(sens_rot) {
nuclear@24 228 ASensorEventQueue_enableSensor(sens_evq_rot, sens_rot);
nuclear@24 229 ASensorEventQueue_setEventRate(sens_evq_rot, sens_rot, 1000000 / 60);
nuclear@24 230 }
nuclear@8 231 //cam_start_video();
nuclear@0 232 break;
nuclear@0 233
nuclear@0 234 case APP_CMD_LOST_FOCUS:
nuclear@0 235 /* app lost focus */
nuclear@24 236 printf("Command: APP_CMD_LOST_FOCUS\n");
nuclear@24 237 if(sens_accel) {
nuclear@24 238 ASensorEventQueue_disableSensor(sens_evq_accel, sens_accel);
nuclear@24 239 }
nuclear@24 240 if(sens_rot) {
nuclear@24 241 ASensorEventQueue_disableSensor(sens_evq_rot, sens_rot);
nuclear@24 242 }
nuclear@8 243 //cam_stop_video();
nuclear@0 244 break;
nuclear@0 245
nuclear@0 246 case APP_CMD_WINDOW_RESIZED:
nuclear@0 247 case APP_CMD_CONFIG_CHANGED:
nuclear@0 248 {
nuclear@0 249 int nx = ANativeWindow_getWidth(app->window);
nuclear@0 250 int ny = ANativeWindow_getHeight(app->window);
nuclear@23 251 if(nx != width || ny != height) {
nuclear@0 252 game_reshape(nx, ny);
nuclear@23 253 width = nx;
nuclear@23 254 height = ny;
nuclear@0 255 }
nuclear@0 256 }
nuclear@0 257 break;
nuclear@0 258
nuclear@0 259 default:
nuclear@0 260 break;
nuclear@0 261 }
nuclear@0 262 }
nuclear@0 263
nuclear@0 264 static int handle_input(struct android_app *app, AInputEvent *ev)
nuclear@0 265 {
nuclear@0 266 int evtype = AInputEvent_getType(ev);
nuclear@0 267
nuclear@0 268 switch(evtype) {
nuclear@0 269 case AINPUT_EVENT_TYPE_MOTION:
nuclear@0 270 return handle_touch_input(app, ev);
nuclear@0 271
nuclear@0 272 default:
nuclear@0 273 break;
nuclear@0 274 }
nuclear@0 275 return 0;
nuclear@0 276 }
nuclear@0 277
nuclear@0 278 #define MAX_TOUCH_IDS 32
nuclear@0 279
nuclear@0 280 static int handle_touch_input(struct android_app *app, AInputEvent *ev)
nuclear@0 281 {
nuclear@0 282 int x, y, idx, touch_id;
nuclear@0 283 unsigned int action;
nuclear@0 284 static int prev_pos[MAX_TOUCH_IDS][2];
nuclear@0 285
nuclear@0 286 action = AMotionEvent_getAction(ev);
nuclear@0 287
nuclear@0 288 idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
nuclear@0 289 AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
nuclear@0 290 touch_id = AMotionEvent_getPointerId(ev, idx);
nuclear@0 291
nuclear@0 292 x = AMotionEvent_getX(ev, idx);
nuclear@0 293 y = AMotionEvent_getY(ev, idx);
nuclear@0 294
nuclear@0 295 switch(action & AMOTION_EVENT_ACTION_MASK) {
nuclear@0 296 case AMOTION_EVENT_ACTION_DOWN:
nuclear@0 297 case AMOTION_EVENT_ACTION_POINTER_DOWN:
nuclear@0 298 game_mouse_button(touch_id, 0, 1, x, y);
nuclear@0 299 if(touch_id < MAX_TOUCH_IDS) {
nuclear@0 300 prev_pos[touch_id][0] = x;
nuclear@0 301 prev_pos[touch_id][1] = y;
nuclear@0 302 }
nuclear@0 303 break;
nuclear@0 304
nuclear@0 305 case AMOTION_EVENT_ACTION_UP:
nuclear@0 306 case AMOTION_EVENT_ACTION_POINTER_UP:
nuclear@0 307 game_mouse_button(touch_id, 0, 0, x, y);
nuclear@0 308 if(touch_id < MAX_TOUCH_IDS) {
nuclear@0 309 prev_pos[touch_id][0] = x;
nuclear@0 310 prev_pos[touch_id][1] = y;
nuclear@0 311 }
nuclear@0 312 break;
nuclear@0 313
nuclear@0 314 case AMOTION_EVENT_ACTION_MOVE:
nuclear@0 315 {
nuclear@0 316 int i, pcount = AMotionEvent_getPointerCount(ev);
nuclear@0 317 for(i=0; i<pcount; i++) {
nuclear@0 318 int id = AMotionEvent_getPointerId(ev, i);
nuclear@0 319 if(id < MAX_TOUCH_IDS && x != prev_pos[id][0] && y != prev_pos[id][1]) {
nuclear@0 320 game_mouse_motion(id, x, y);
nuclear@0 321 prev_pos[id][0] = x;
nuclear@0 322 prev_pos[id][1] = y;
nuclear@0 323 }
nuclear@0 324 }
nuclear@0 325 }
nuclear@0 326 break;
nuclear@0 327
nuclear@0 328 default:
nuclear@0 329 break;
nuclear@0 330 }
nuclear@0 331
nuclear@0 332 return 1;
nuclear@0 333 }
nuclear@0 334
nuclear@0 335
nuclear@0 336 static int init_gl(void)
nuclear@0 337 {
nuclear@0 338 static const int eglattr[] = {
nuclear@0 339 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
nuclear@10 340 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
nuclear@0 341 EGL_RED_SIZE, 5,
nuclear@0 342 EGL_GREEN_SIZE, 5,
nuclear@0 343 EGL_BLUE_SIZE, 5,
nuclear@0 344 EGL_DEPTH_SIZE, 16,
nuclear@0 345 EGL_NONE
nuclear@0 346 };
nuclear@10 347 static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
nuclear@0 348
nuclear@0 349 EGLConfig eglcfg;
nuclear@0 350 int count, vis;
nuclear@0 351
nuclear@0 352 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
nuclear@0 353 if(!dpy || !eglInitialize(dpy, 0, 0)) {
nuclear@0 354 fprintf(stderr, "failed to initialize EGL\n");
nuclear@0 355 destroy_gl();
nuclear@0 356 return -1;
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 if(!eglChooseConfig(dpy, eglattr, &eglcfg, 1, &count)) {
nuclear@0 360 fprintf(stderr, "no matching EGL config found\n");
nuclear@0 361 destroy_gl();
nuclear@0 362 return -1;
nuclear@0 363 }
nuclear@0 364
nuclear@0 365 /* configure the native window visual according to the chosen EGL config */
nuclear@0 366 eglGetConfigAttrib(dpy, &eglcfg, EGL_NATIVE_VISUAL_ID, &vis);
nuclear@0 367 ANativeWindow_setBuffersGeometry(app->window, 0, 0, vis);
nuclear@0 368
nuclear@0 369 if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) {
nuclear@0 370 fprintf(stderr, "failed to create window\n");
nuclear@0 371 destroy_gl();
nuclear@0 372 return -1;
nuclear@0 373 }
nuclear@0 374
nuclear@0 375 if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) {
nuclear@0 376 fprintf(stderr, "failed to create OpenGL ES context\n");
nuclear@0 377 destroy_gl();
nuclear@0 378 return -1;
nuclear@0 379 }
nuclear@0 380 eglMakeCurrent(dpy, surf, surf, ctx);
nuclear@0 381
nuclear@23 382 eglQuerySurface(dpy, surf, EGL_WIDTH, &width);
nuclear@23 383 eglQuerySurface(dpy, surf, EGL_HEIGHT, &height);
nuclear@23 384 game_reshape(width, height);
nuclear@0 385
nuclear@0 386 return 0;
nuclear@0 387 }
nuclear@0 388
nuclear@0 389 static void destroy_gl(void)
nuclear@0 390 {
nuclear@0 391 if(!dpy) return;
nuclear@0 392
nuclear@0 393 eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
nuclear@0 394
nuclear@0 395 if(ctx) {
nuclear@0 396 eglDestroyContext(dpy, ctx);
nuclear@0 397 ctx = 0;
nuclear@0 398 }
nuclear@0 399 if(surf) {
nuclear@0 400 eglDestroySurface(dpy, surf);
nuclear@0 401 surf = 0;
nuclear@0 402 }
nuclear@0 403
nuclear@0 404 eglTerminate(dpy);
nuclear@0 405 dpy = 0;
nuclear@0 406 }