1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 //BEGIN_INCLUDE(all)
19 #include <jni.h>
20 #include <errno.h>
21
22 #include <EGL/egl.h>
23 #include <GLES/gl.h>
24
25 #include <android/sensor.h>
26 #include <android/log.h>
27 #include <android_native_app_glue.h>
28
29 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
30 #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
31
32 /**
33 * Our saved state data.
34 */
35 struct saved_state {
36 float angle;
37 int32_t x;
38 int32_t y;
39 };
40
41 /**
42 * Shared state for our app.
43 */
44 struct engine {
45 struct android_app* app;
46
47 ASensorManager* sensorManager;
48 const ASensor* accelerometerSensor;
49 ASensorEventQueue* sensorEventQueue;
50
51 int animating;
52 EGLDisplay display;
53 EGLSurface surface;
54 EGLContext context;
55 int32_t width;
56 int32_t height;
57 struct saved_state state;
58 };
59
60 /**
61 * Initialize an EGL context for the current display.
62 */
engine_init_display(struct engine * engine)63 static int engine_init_display(struct engine* engine) {
64 // initialize OpenGL ES and EGL
65
66 /*
67 * Here specify the attributes of the desired configuration.
68 * Below, we select an EGLConfig with at least 8 bits per color
69 * component compatible with on-screen windows
70 */
71 const EGLint attribs[] = {
72 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
73 EGL_BLUE_SIZE, 8,
74 EGL_GREEN_SIZE, 8,
75 EGL_RED_SIZE, 8,
76 EGL_NONE
77 };
78 EGLint w, h, dummy, format;
79 EGLint numConfigs;
80 EGLConfig config;
81 EGLSurface surface;
82 EGLContext context;
83
84 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
85
86 eglInitialize(display, 0, 0);
87
88 /* Here, the application chooses the configuration it desires. In this
89 * sample, we have a very simplified selection process, where we pick
90 * the first EGLConfig that matches our criteria */
91 eglChooseConfig(display, attribs, &config, 1, &numConfigs);
92
93 /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
94 * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
95 * As soon as we picked a EGLConfig, we can safely reconfigure the
96 * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
97 eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
98
99 ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
100
101 surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
102 context = eglCreateContext(display, config, NULL, NULL);
103
104 if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
105 LOGW("Unable to eglMakeCurrent");
106 return -1;
107 }
108
109 eglQuerySurface(display, surface, EGL_WIDTH, &w);
110 eglQuerySurface(display, surface, EGL_HEIGHT, &h);
111
112 engine->display = display;
113 engine->context = context;
114 engine->surface = surface;
115 engine->width = w;
116 engine->height = h;
117 engine->state.angle = 0;
118
119 // Initialize GL state.
120 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
121 glEnable(GL_CULL_FACE);
122 glShadeModel(GL_SMOOTH);
123 glDisable(GL_DEPTH_TEST);
124
125 return 0;
126 }
127
128 /**
129 * Just the current frame in the display.
130 */
engine_draw_frame(struct engine * engine)131 static void engine_draw_frame(struct engine* engine) {
132 if (engine->display == NULL) {
133 // No display.
134 return;
135 }
136
137 // Just fill the screen with a color.
138 glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,
139 ((float)engine->state.y)/engine->height, 1);
140 glClear(GL_COLOR_BUFFER_BIT);
141
142 eglSwapBuffers(engine->display, engine->surface);
143 }
144
145 /**
146 * Tear down the EGL context currently associated with the display.
147 */
engine_term_display(struct engine * engine)148 static void engine_term_display(struct engine* engine) {
149 if (engine->display != EGL_NO_DISPLAY) {
150 eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
151 if (engine->context != EGL_NO_CONTEXT) {
152 eglDestroyContext(engine->display, engine->context);
153 }
154 if (engine->surface != EGL_NO_SURFACE) {
155 eglDestroySurface(engine->display, engine->surface);
156 }
157 eglTerminate(engine->display);
158 }
159 engine->animating = 0;
160 engine->display = EGL_NO_DISPLAY;
161 engine->context = EGL_NO_CONTEXT;
162 engine->surface = EGL_NO_SURFACE;
163 }
164
165 /**
166 * Process the next input event.
167 */
engine_handle_input(struct android_app * app,AInputEvent * event)168 static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
169 struct engine* engine = (struct engine*)app->userData;
170 if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
171 engine->animating = 1;
172 engine->state.x = AMotionEvent_getX(event, 0);
173 engine->state.y = AMotionEvent_getY(event, 0);
174 return 1;
175 }
176 return 0;
177 }
178
179 /**
180 * Process the next main command.
181 */
engine_handle_cmd(struct android_app * app,int32_t cmd)182 static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
183 struct engine* engine = (struct engine*)app->userData;
184 switch (cmd) {
185 case APP_CMD_SAVE_STATE:
186 // The system has asked us to save our current state. Do so.
187 engine->app->savedState = malloc(sizeof(struct saved_state));
188 *((struct saved_state*)engine->app->savedState) = engine->state;
189 engine->app->savedStateSize = sizeof(struct saved_state);
190 break;
191 case APP_CMD_INIT_WINDOW:
192 // The window is being shown, get it ready.
193 if (engine->app->window != NULL) {
194 engine_init_display(engine);
195 engine_draw_frame(engine);
196 }
197 break;
198 case APP_CMD_TERM_WINDOW:
199 // The window is being hidden or closed, clean it up.
200 engine_term_display(engine);
201 break;
202 case APP_CMD_GAINED_FOCUS:
203 // When our app gains focus, we start monitoring the accelerometer.
204 if (engine->accelerometerSensor != NULL) {
205 ASensorEventQueue_enableSensor(engine->sensorEventQueue,
206 engine->accelerometerSensor);
207 // We'd like to get 60 events per second (in us).
208 ASensorEventQueue_setEventRate(engine->sensorEventQueue,
209 engine->accelerometerSensor, (1000L/60)*1000);
210 }
211 break;
212 case APP_CMD_LOST_FOCUS:
213 // When our app loses focus, we stop monitoring the accelerometer.
214 // This is to avoid consuming battery while not being used.
215 if (engine->accelerometerSensor != NULL) {
216 ASensorEventQueue_disableSensor(engine->sensorEventQueue,
217 engine->accelerometerSensor);
218 }
219 // Also stop animating.
220 engine->animating = 0;
221 engine_draw_frame(engine);
222 break;
223 }
224 }
225
226 /**
227 * This is the main entry point of a native application that is using
228 * android_native_app_glue. It runs in its own thread, with its own
229 * event loop for receiving input events and doing other things.
230 */
android_main(struct android_app * state)231 void android_main(struct android_app* state) {
232 struct engine engine;
233
234 // Make sure glue isn't stripped.
235 app_dummy();
236
237 memset(&engine, 0, sizeof(engine));
238 state->userData = &engine;
239 state->onAppCmd = engine_handle_cmd;
240 state->onInputEvent = engine_handle_input;
241 engine.app = state;
242
243 // Prepare to monitor accelerometer
244 engine.sensorManager = ASensorManager_getInstance();
245 engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
246 ASENSOR_TYPE_ACCELEROMETER);
247 engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
248 state->looper, LOOPER_ID_USER, NULL, NULL);
249
250 if (state->savedState != NULL) {
251 // We are starting with a previous saved state; restore from it.
252 engine.state = *(struct saved_state*)state->savedState;
253 }
254
255 // loop waiting for stuff to do.
256
257 while (1) {
258 // Read all pending events.
259 int ident;
260 int events;
261 struct android_poll_source* source;
262
263 // If not animating, we will block forever waiting for events.
264 // If animating, we loop until all events are read, then continue
265 // to draw the next frame of animation.
266 while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
267 (void**)&source)) >= 0) {
268
269 // Process this event.
270 if (source != NULL) {
271 source->process(state, source);
272 }
273
274 // If a sensor has data, process it now.
275 if (ident == LOOPER_ID_USER) {
276 if (engine.accelerometerSensor != NULL) {
277 ASensorEvent event;
278 while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
279 &event, 1) > 0) {
280 LOGI("accelerometer: x=%f y=%f z=%f",
281 event.acceleration.x, event.acceleration.y,
282 event.acceleration.z);
283 }
284 }
285 }
286
287 // Check if we are exiting.
288 if (state->destroyRequested != 0) {
289 engine_term_display(&engine);
290 return;
291 }
292 }
293
294 if (engine.animating) {
295 // Done with events; draw next animation frame.
296 engine.state.angle += .01f;
297 if (engine.state.angle > 1) {
298 engine.state.angle = 0;
299 }
300
301 // Drawing is throttled to the screen update rate, so there
302 // is no need to do timing here.
303 engine_draw_frame(&engine);
304 }
305 }
306 }
307 //END_INCLUDE(all)
308