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