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