This shows direct drawing to an ANativeWindow's bits. Update the NDK API, and fix a bug in the native-activity app where it would hang while exiting. Change-Id: I4fa98d083405eb0d1b22b10a73a2ef18d45fdb59
217 lines
6.2 KiB
C
217 lines
6.2 KiB
C
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <jni.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <android_glue/threaded_app.h>
|
|
|
|
#include "glutils.h"
|
|
|
|
struct engine {
|
|
struct android_app* app;
|
|
|
|
int animating;
|
|
EGLDisplay display;
|
|
EGLSurface surface;
|
|
EGLContext context;
|
|
int32_t width;
|
|
int32_t height;
|
|
float angle;
|
|
int32_t x;
|
|
int32_t y;
|
|
};
|
|
|
|
static int engine_init_display(struct engine* engine) {
|
|
// initialize opengl and egl
|
|
const EGLint attribs[] = {
|
|
EGL_DEPTH_SIZE, 16,
|
|
EGL_NONE
|
|
};
|
|
EGLint w, h, dummy;
|
|
EGLint numConfigs;
|
|
EGLConfig config;
|
|
EGLSurface surface;
|
|
EGLContext context;
|
|
|
|
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
|
|
eglInitialize(display, 0, 0);
|
|
selectConfigForNativeWindow(display, attribs, engine->app->window, &config);
|
|
surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
|
|
context = eglCreateContext(display, config, NULL, NULL);
|
|
eglQuerySurface(display, surface, EGL_WIDTH, &w);
|
|
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
|
|
|
|
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
|
|
LOGW("Unable to eglMakeCurrent");
|
|
return -1;
|
|
}
|
|
|
|
engine->display = display;
|
|
engine->context = context;
|
|
engine->surface = surface;
|
|
engine->width = w;
|
|
engine->height = h;
|
|
engine->angle = 0;
|
|
|
|
// Initialize GL state.
|
|
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
glEnable(GL_CULL_FACE);
|
|
glShadeModel(GL_SMOOTH);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void engine_draw_frame(struct engine* engine) {
|
|
if (engine->display == NULL) {
|
|
// No display.
|
|
return;
|
|
}
|
|
|
|
glClearColor(((float)engine->x)/engine->width, engine->angle,
|
|
((float)engine->y)/engine->height, 1);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
#if 0
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glTranslatef(0, 0, -3.0f);
|
|
glRotatef(engine->angle, 0, 1, 0);
|
|
glRotatef(engine->angle*0.25f, 1, 0, 0);
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
glEnableClientState(GL_COLOR_ARRAY);
|
|
|
|
//mCube.draw(gl);
|
|
|
|
glRotatef(engine->angle*2.0f, 0, 1, 1);
|
|
glTranslatef(0.5f, 0.5f, 0.5f);
|
|
|
|
//mCube.draw(gl);
|
|
#endif
|
|
|
|
eglSwapBuffers(engine->display, engine->surface);
|
|
|
|
//engine->angle += 1.2f;
|
|
}
|
|
|
|
static int engine_term_display(struct engine* engine) {
|
|
if (engine->display != EGL_NO_DISPLAY) {
|
|
eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
if (engine->context != EGL_NO_CONTEXT) {
|
|
eglDestroyContext(engine->display, engine->context);
|
|
}
|
|
if (engine->surface != EGL_NO_SURFACE) {
|
|
eglDestroySurface(engine->display, engine->surface);
|
|
}
|
|
eglTerminate(engine->display);
|
|
}
|
|
engine->animating = 0;
|
|
engine->display = EGL_NO_DISPLAY;
|
|
engine->context = EGL_NO_CONTEXT;
|
|
engine->surface = EGL_NO_SURFACE;
|
|
}
|
|
|
|
static int engine_do_ui_event(struct engine* engine) {
|
|
AInputEvent* event = NULL;
|
|
if (AInputQueue_getEvent(engine->app->inputQueue, &event) >= 0) {
|
|
LOGI("New input event: type=%d\n", AInputEvent_getType(event));
|
|
if (AInputEvent_getType(event) == INPUT_EVENT_TYPE_MOTION) {
|
|
engine->animating = 1;
|
|
engine->x = AMotionEvent_getX(event, 0);
|
|
engine->y = AMotionEvent_getY(event, 0);
|
|
AInputQueue_finishEvent(engine->app->inputQueue, event, 1);
|
|
} else {
|
|
AInputQueue_finishEvent(engine->app->inputQueue, event, 0);
|
|
}
|
|
} else {
|
|
LOGI("Failure reading next input event: %s\n", strerror(errno));
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int32_t engine_do_main_cmd(struct engine* engine) {
|
|
int32_t res;
|
|
int8_t cmd = android_app_read_cmd(engine->app);
|
|
switch (cmd) {
|
|
case APP_CMD_WINDOW_CHANGED:
|
|
engine_term_display(engine);
|
|
res = android_app_exec_cmd(engine->app, cmd);
|
|
if (engine->app->window != NULL) {
|
|
engine_init_display(engine);
|
|
engine_draw_frame(engine);
|
|
}
|
|
break;
|
|
case APP_CMD_LOST_FOCUS:
|
|
res = android_app_exec_cmd(engine->app, cmd);
|
|
engine->animating = 0;
|
|
engine_draw_frame(engine);
|
|
break;
|
|
default:
|
|
res = android_app_exec_cmd(engine->app, cmd);
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void android_main(struct android_app* state) {
|
|
struct engine engine;
|
|
|
|
memset(&engine, 0, sizeof(engine));
|
|
state->userData = &engine;
|
|
engine.app = state;
|
|
|
|
// loop waiting for stuff to do.
|
|
|
|
while (1) {
|
|
// Read all pending events.
|
|
int fd;
|
|
int events;
|
|
void* data;
|
|
while ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, &data)) >= 0) {
|
|
switch ((int)data) {
|
|
case LOOPER_ID_MAIN:
|
|
if (!engine_do_main_cmd(&engine)) {
|
|
LOGI("Engine thread destroy requested!");
|
|
engine_term_display(&engine);
|
|
android_app_destroy(state);
|
|
// Can't touch android_app object after this.
|
|
return;
|
|
}
|
|
break;
|
|
case LOOPER_ID_EVENT:
|
|
engine_do_ui_event(&engine);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (engine.animating) {
|
|
// Done with events; draw next animation frame.
|
|
engine.angle += .01f;
|
|
if (engine.angle > 1) {
|
|
engine.angle = 0;
|
|
}
|
|
engine_draw_frame(&engine);
|
|
}
|
|
}
|
|
}
|