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