demosys
[andemo] / src / android / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6 #include <EGL/egl.h>
7 #include <GLES2/gl2.h>
8 #include "demo.h"
9 #include "android_native_app_glue.h"
10 #include "logger.h"
11 #include "demosys.h"
12
13 static void handle_command(struct android_app *app, int32_t cmd);
14 static int handle_input(struct android_app *app, AInputEvent *ev);
15 static int handle_touch_input(struct android_app *app, AInputEvent *ev);
16 static int init_gl(void);
17 static void destroy_gl(void);
18 static unsigned long get_time_msec(void);
19
20 struct android_app *app;
21
22 static EGLDisplay dpy;
23 static EGLSurface surf;
24 static EGLContext ctx;
25 static int init_done, paused;
26
27 static int width, height;
28
29 static long start_time;
30
31
32 void android_main(struct android_app *app_ptr)
33 {
34         app = app_ptr;
35
36         app->onAppCmd = handle_command;
37         app->onInputEvent = handle_input;
38
39         start_logger();
40
41         for(;;) {
42                 int num_events;
43                 struct android_poll_source *pollsrc;
44
45                 while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) {
46                         if(pollsrc) {
47                                 pollsrc->process(app, pollsrc);
48                         }
49                 }
50
51                 if(app->destroyRequested) {
52                         return;
53                 }
54                 if(init_done && !paused) {
55                         time_msec = (long)get_time_msec() - start_time;
56                         demo_display();
57                         eglSwapBuffers(dpy, surf);
58                 }
59         }
60 }
61
62 void swap_buffers(void)
63 {
64         eglSwapBuffers(dpy, surf);
65 }
66
67 static void handle_command(struct android_app *app, int32_t cmd)
68 {
69         int xsz, ysz;
70
71         switch(cmd) {
72         case APP_CMD_PAUSE:
73                 paused = 1;     /* TODO: handle timers */
74                 dsys_stop();
75                 break;
76         case APP_CMD_RESUME:
77                 paused = 0;
78                 dsys_run();
79                 break;
80
81         case APP_CMD_INIT_WINDOW:
82                 if(init_gl() == -1) {
83                         exit(1);
84                 }
85                 if(demo_init() == -1) {
86                         exit(1);
87                 }
88                 demo_reshape(width, height);
89                 start_time = (long)get_time_msec();
90                 init_done = 1;
91                 dsys_run();
92                 break;
93
94         case APP_CMD_TERM_WINDOW:
95                 init_done = 0;
96                 demo_cleanup();
97                 destroy_gl();
98                 break;
99
100         case APP_CMD_WINDOW_RESIZED:
101         case APP_CMD_CONFIG_CHANGED:
102                 xsz = ANativeWindow_getWidth(app->window);
103                 ysz = ANativeWindow_getHeight(app->window);
104                 if(xsz != width || ysz != height) {
105                         printf("reshape(%d, %d)\n", xsz, ysz);
106                         demo_reshape(xsz, ysz);
107                         width = xsz;
108                         height = ysz;
109                 }
110                 break;
111
112         /*
113         case APP_CMD_SAVE_STATE:
114         case APP_CMD_GAINED_FOCUS:
115         case APP_CMD_LOST_FOCUS:
116         */
117         default:
118                 break;
119         }
120 }
121
122 static int handle_input(struct android_app *app, AInputEvent *ev)
123 {
124         int evtype = AInputEvent_getType(ev);
125
126         switch(evtype) {
127         case AINPUT_EVENT_TYPE_MOTION:
128                 return handle_touch_input(app, ev);
129
130         default:
131                 break;
132         }
133         return 0;
134 }
135
136 static int handle_touch_input(struct android_app *app, AInputEvent *ev)
137 {
138         int i, pcount, x, y, idx;
139         unsigned int action;
140         static int prev_pos[2];
141
142         action = AMotionEvent_getAction(ev);
143
144         idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
145                 AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
146
147         x = AMotionEvent_getX(ev, idx);
148         y = AMotionEvent_getY(ev, idx);
149
150         switch(action & AMOTION_EVENT_ACTION_MASK) {
151         case AMOTION_EVENT_ACTION_DOWN:
152         case AMOTION_EVENT_ACTION_POINTER_DOWN:
153                 demo_mouse(0, 1, x, y);
154
155                 prev_pos[0] = x;
156                 prev_pos[1] = y;
157                 break;
158
159         case AMOTION_EVENT_ACTION_UP:
160         case AMOTION_EVENT_ACTION_POINTER_UP:
161                 demo_mouse(0, 0, x, y);
162
163                 prev_pos[0] = x;
164                 prev_pos[1] = y;
165                 break;
166
167         case AMOTION_EVENT_ACTION_MOVE:
168                 pcount = AMotionEvent_getPointerCount(ev);
169                 for(i=0; i<pcount; i++) {
170                         int id = AMotionEvent_getPointerId(ev, i);
171                         if(id == 0) {
172                                 demo_motion(x, y);
173                                 prev_pos[0] = x;
174                                 prev_pos[1] = y;
175                                 break;
176                         }
177                 }
178                 break;
179
180         default:
181                 break;
182         }
183
184         return 1;
185 }
186
187 static int init_gl(void)
188 {
189         static const int eglattr[] = {
190                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
191                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
192                 EGL_RED_SIZE, 5,
193                 EGL_GREEN_SIZE, 5,
194                 EGL_BLUE_SIZE, 5,
195                 EGL_DEPTH_SIZE, 16,
196                 EGL_NONE
197         };
198         static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
199
200         EGLConfig eglcfg;
201         int count, vis;
202
203         dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
204         if(!dpy || !eglInitialize(dpy, 0, 0)) {
205                 fprintf(stderr, "failed to initialize EGL\n");
206                 destroy_gl();
207                 return -1;
208         }
209
210         if(!eglChooseConfig(dpy, eglattr, &eglcfg, 1, &count)) {
211                 fprintf(stderr, "no matching EGL config found\n");
212                 destroy_gl();
213                 return -1;
214         }
215
216         /* configure the native window visual according to the chosen EGL config */
217         eglGetConfigAttrib(dpy, &eglcfg, EGL_NATIVE_VISUAL_ID, &vis);
218         ANativeWindow_setBuffersGeometry(app->window, 0, 0, vis);
219
220         if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) {
221                 fprintf(stderr, "failed to create window\n");
222                 destroy_gl();
223                 return -1;
224         }
225
226         if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) {
227                 fprintf(stderr, "failed to create OpenGL ES context\n");
228                 destroy_gl();
229                 return -1;
230         }
231         eglMakeCurrent(dpy, surf, surf, ctx);
232
233         eglQuerySurface(dpy, surf, EGL_WIDTH, &width);
234         eglQuerySurface(dpy, surf, EGL_HEIGHT, &height);
235         return 0;
236 }
237
238 static void destroy_gl(void)
239 {
240         if(!dpy) return;
241
242         eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
243
244         if(ctx) {
245                 eglDestroyContext(dpy, ctx);
246                 ctx = 0;
247         }
248         if(surf) {
249                 eglDestroySurface(dpy, surf);
250                 surf = 0;
251         }
252
253         eglTerminate(dpy);
254         dpy = 0;
255 }
256
257 static unsigned long get_time_msec(void)
258 {
259         struct timespec ts;
260         static struct timespec ts0;
261
262         clock_gettime(CLOCK_MONOTONIC, &ts);
263         if(ts0.tv_sec == 0 && ts0.tv_nsec == 0) {
264                 ts0 = ts;
265                 return 0;
266         }
267         return (ts.tv_sec - ts0.tv_sec) * 1000 + (ts.tv_nsec - ts0.tv_nsec) / 1000000;
268 }