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 }
|