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