ホームに戻る
NDK 立体のアニメ
// 立体が回転します
#include <time.h>
#include <jni.h>
#include <errno.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <android_native_app_glue.h>
#define ONE_SECOND 1000000
struct engine{
struct android_app* app;
int32_t count; // アニメのカウント
int animating;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
int32_t width;
int32_t height;
};
// 三角形の座標
GLfloat quadBuf[] ={
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0
};
// 法線
GLfloat normBuf[] ={
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0
};
// 光源の設定
GLfloat lightAmb[] = {0.0, 0.0, 0.0, 1.0};
GLfloat lightPos[] = {0.0, 0.0, 0.0, 1.0};
GLfloat lightDif[] = {1.0, 1.0, 1.0, 1.0};
static int engine_init_display(struct engine* engine){
EGLint attribs[] = {
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
EGLint w, h, format;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
context = eglCreateContext(display, config, NULL, NULL);
if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE){
return -1;
}
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
engine->display = display;
engine->context = context;
engine->surface = surface;
engine->width = w;
engine->height = h;
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustumf(-1.33, 1.33, -1.0, 1.0, 1.0, 5.0);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmb);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDif);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
return 0;
}
static void engine_draw_frame(struct engine* engine){
if(engine->display == NULL){
return;
}
glClearColor(0.0, 0.0, 0.0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.0);
glRotatef((float)engine->count, 0.0, 1.0, 0.0);
glPushMatrix();
glTranslatef(0.0, 0.0, 1.0);
glVertexPointer(3, GL_FLOAT, 0, quadBuf);
glNormalPointer(GL_FLOAT, 0, normBuf);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
glPushMatrix();
glTranslatef(0.0, 0.0, -1.0);
glRotatef(180.0, 0.0, 1.0, 0.0);
glVertexPointer(3, GL_FLOAT, 0, quadBuf);
glNormalPointer(GL_FLOAT, 0, normBuf);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
glPushMatrix();
glTranslatef(1.0, 0.0, 0.0);
glRotatef(90.0, 0.0, 1.0, 0.0);
glVertexPointer(3, GL_FLOAT, 0, quadBuf);
glNormalPointer(GL_FLOAT, 0, normBuf);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
glPushMatrix();
glTranslatef(-1.0, 0.0, 0.0);
glRotatef(-90.0, 0.0, 1.0, 0.0);
glVertexPointer(3, GL_FLOAT, 0, quadBuf);
glNormalPointer(GL_FLOAT, 0, normBuf);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
eglSwapBuffers(engine->display, engine->surface);
}
static void 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 int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
struct engine* engine = (struct engine*)app->userData;
if(AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION){
if(engine->animating){
engine->animating= 0;
}
else{
engine->animating= 1;
}
return 1;
}
return 0;
}
// 入力以外のイベントに対する処理
static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
struct engine* engine = (struct engine*)app->userData;
switch(cmd){
case APP_CMD_INIT_WINDOW:
if(engine->app->window != NULL){
engine_init_display(engine);
engine_draw_frame(engine);
engine->animating = 1;
}
break;
case APP_CMD_TERM_WINDOW:
engine_term_display(engine);
break;
default:
break;
}
}
void android_main(struct android_app* state){
struct engine engine;
clock_t start, end;
app_dummy();
memset(&engine, 0, sizeof(engine));
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
engine.app = state;
start = clock();
while(1){
int ident;
int events;
struct android_poll_source* source;
while((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events, (void**)&source)) >= 0){
if(source != NULL){
source->process(state, source);
}
if(state->destroyRequested != 0){
engine_term_display(&engine);
return;
}
}
if(engine.animating){
end = clock();
if(end - start > (ONE_SECOND / 100)){
start = clock();
engine.count++;
engine_draw_frame(&engine);
}
}
}
}