Home | History | Annotate | Download | only in jni
      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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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