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