0xAA55 发表于 2014-8-18 18:43:28

【安卓】NDK+OpenGL的一个简单的例子

我讨厌Eclipse.各种麻烦,配置还需要下载各种包,各种不爽!
也许是我用不来,也许是我笨。总之在我的电脑上它从来没正常运行过。
好吧。那我就用c4droid进行开发。先在电脑上用Notepad++写代码,完了以后仍手机用c4droid变异。
首先我们需要一个Makefileall: ndkapp.so

ndkapp.so: napp.o
    $(CC) -o ndkapp.so napp.o -shared -lEGL -lGLESv1_CM -lm

clean:
    rm ndkapp.so napp.o我们是把napp.c这个源文件编译为napp.o,然后链接得到ndkapp.so这个可执行文件(安卓的可执行文件……?)
算了,不纠结这个。继续。
这个源码运行的效果就是屏幕上会显示一个正方形,然后你用手摸屏幕的时候正方形会跟着走。
我决定以后在安卓上开发程序都采取用OpenGL自己绘制界面的这种方式了。我更喜欢这种模式的编程。#include<jni.h>
#include<errno.h>
#include<math.h>

#include<sys/time.h>

#include<EGL/egl.h>
#include<GLES/gl.h>

#include<android/sensor.h>
#include<android/log.h>
#include<android_native_app_glue.h>

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"native-activity",__VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN,"native-activity",__VA_ARGS__))

//程序挂起恢复时存储的数据
typedef struct
{
    int32_t x;
    int32_t y;
   
    float   AccX,AccY,AccZ;
}SavedState,*SavedStateP;

//程序数据
typedef struct
{
    struct android_app      *pApp;

    //传感器
    ASensorManager          *pSensorManager;
    const ASensor         *pAccelerometerSensor;
    ASensorEventQueue       *pSensorEventQueue;
   
    //图形引擎
    EGLDisplay            Display;
    EGLSurface            Surface;
    EGLContext            Context;
    int32_t               Width;
    int32_t               Height;
   
    //存储的状态
    SavedState            State;
}AppData,*AppDataP;

//=============================================================================
//InitDisplay:
//初始化显示的部分,OpenGL ES
//-----------------------------------------------------------------------------
int InitDisplay(AppDataP pThis)
{
    const EGLint Attribs[]=
    {
      EGL_SURFACE_TYPE,EGL_WINDOW_BIT,
      EGL_BLUE_SIZE,8,
      EGL_GREEN_SIZE,8,
      EGL_RED_SIZE,8,
      EGL_DEPTH_SIZE,8,
      EGL_NONE
    };
    EGLint      W,H;
    EGLint      Dummy,Format;
    EGLint      NbConfigs;
    EGLConfig   Configs;
    EGLDisplayDisplay;
    EGLSurfaceSurface;
    EGLContextContext;
   
    Display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(Display,0,0);
    eglChooseConfig(Display,Attribs,&Configs,1,&NbConfigs);
    eglGetConfigAttrib(Display,Configs,EGL_NATIVE_VISUAL_ID,&Format);
    ANativeWindow_setBuffersGeometry(pThis->pApp->window,0,0,Format);
    Surface=eglCreateWindowSurface(Display,Configs,pThis->pApp->window,NULL);
    Context=eglCreateContext(Display,Configs,NULL,NULL);
    if(eglMakeCurrent(Display,Surface,Surface,Context)==EGL_FALSE)
    {
      LOGW("Unable to eglMakeCurrent");
      return 0;
    }
    eglQuerySurface(Display,Surface,EGL_WIDTH,&W);
    eglQuerySurface(Display,Surface,EGL_HEIGHT,&H);
   
    pThis->Display=Display;
    pThis->Context=Context;
    pThis->Surface=Surface;
    pThis->Width=W;
    pThis->Height=H;
   
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_FASTEST);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    glClearColor(0.0f,0.0f,0.0f,0.0f);
    glClearDepthf(1.0f);
    glShadeModel(GL_FLAT);
   
    glViewport(0,0,W,H);
   
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
   
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    return 1;
}

//=============================================================================
//CleanupDisplay:
//清理显示的部分,释放内存。和InitDisplay配套的
//-----------------------------------------------------------------------------
void CleanupDisplay(AppDataP pThis)
{
    if(pThis->Display!=EGL_NO_DISPLAY)
    {
      eglMakeCurrent(pThis->Display,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT);
      if(pThis->Context!=EGL_NO_CONTEXT)
            eglDestroyContext(pThis->Display,pThis->Context);
      if(pThis->Surface!=EGL_NO_SURFACE)
            eglDestroySurface(pThis->Display,pThis->Surface);
      eglTerminate(pThis->Display);
    }
    pThis->Display=EGL_NO_DISPLAY;
    pThis->Context=EGL_NO_CONTEXT;
    pThis->Surface=EGL_NO_SURFACE;
}

GLfloat Model=//模型
{
    -0.1,-0.1,0.5,//两个三角形组成一个四边形
   0.1,-0.1,0.5,
    -0.1, 0.1,0.5,
   0.1,-0.1,0.5,
   0.1, 0.1,0.5,
    -0.1, 0.1,0.5
};

//圆周率之类的东西
#define PI 3.141592653589793238462643

//=============================================================================
//DrawFrame:
//在屏幕上画一帧图像
//-----------------------------------------------------------------------------
void DrawFrame(AppDataP pThis)
{
    GLfloat Aspect;
    doubleCurTime;
    structtimeval tv;
    GLfloat Matrix;

    if(!pThis->Display)
      return;
      
    gettimeofday(&tv,NULL);//取得时间
    CurTime=tv.tv_sec+tv.tv_usec*0.000001;//以秒为单位的时间

    Aspect=(GLfloat)(pThis->Height)/(GLfloat)(pThis->Width);//宽高比
      
    //清空图形缓冲区
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
   
    //加载模型
    glVertexPointer(3,GL_FLOAT,0,Model);
    glEnableClientState(GL_VERTEX_ARRAY);
   
    //设置矩阵
    glLoadIdentity();//载入单位矩阵
   
    memset(&Matrix,0,sizeof(Matrix));
    Matrix=Matrix=1;
   
    //绕Z轴旋转
    Matrix=(GLfloat)sin(CurTime);
    Matrix=(GLfloat)cos(CurTime);
    Matrix=-Matrix;
    Matrix=Matrix;
   
    //宽高比缩放
    Matrix*=Aspect;
    Matrix*=Aspect;
   
    //位移
    Matrix=((GLfloat)(pThis->State.x)/(GLfloat)(pThis->Width))*2-1;
    Matrix=1-((GLfloat)(pThis->State.y)/(GLfloat)(pThis->Height))*2;
    glMultMatrixf(Matrix);
   
    glColor4f(0,1,0,1);//绿色
    glDrawArrays(GL_TRIANGLES,0,6);//画模型
   
    glFlush();
    eglSwapBuffers(pThis->Display,pThis->Surface);//把缓冲区的图像刷到屏幕上
}

//=============================================================================
//CmdProc:
//处理窗口消息
//-----------------------------------------------------------------------------
static void CmdProc(struct android_app*pApp,int32_t cmd)
{
#   definepThis   ((AppDataP)pApp->userData)

    switch(cmd)
    {
    case APP_CMD_SAVE_STATE://保存状态
      pThis->pApp->savedState=malloc(sizeof(SavedState));
      if(pThis->pApp->savedState)
      {
            memcpy(pThis->pApp->savedState,&(pThis->State),sizeof(SavedState));
            pThis->pApp->savedStateSize=sizeof(SavedState);
      }
      break;
    case APP_CMD_INIT_WINDOW://初始化窗口
      if(pThis->pApp->window)
      {
            InitDisplay(pThis);
            DrawFrame(pThis);
      }
      break;
    case APP_CMD_TERM_WINDOW://结束窗口
      CleanupDisplay(pThis);
      break;
    case APP_CMD_GAINED_FOCUS://取得焦点
      if(pThis->pAccelerometerSensor)
      {
            ASensorEventQueue_enableSensor(pThis->pSensorEventQueue,pThis->pAccelerometerSensor);
            ASensorEventQueue_setEventRate(pThis->pSensorEventQueue,pThis->pAccelerometerSensor,50000);
      }
      break;
    case APP_CMD_LOST_FOCUS://失去焦点
      if (pThis->pAccelerometerSensor)
            ASensorEventQueue_disableSensor(pThis->pSensorEventQueue,pThis->pAccelerometerSensor);
      break;
    }

#   undef   pThis
}

//=============================================================================
//InputProc:
//处理触摸操作
//-----------------------------------------------------------------------------
static int32_t InputProc(struct android_app*pApp,AInputEvent*pEvent)
{
#   definepThis   ((AppDataP)pApp->userData)
    if(AInputEvent_getType(pEvent)==AINPUT_EVENT_TYPE_MOTION)
    {
      pThis->State.x=AMotionEvent_getX(pEvent,0);
      pThis->State.y=AMotionEvent_getY(pEvent,0);
      return 1;
    }
    return 0;
#   undef   pThis
}

//=============================================================================
//android_main:
//程序入口点
//-----------------------------------------------------------------------------
void android_main(struct android_app*pApp)
{
    AppData This;

    // Make sure glue isn't stripped.
    app_dummy();

    memset(&This,0,sizeof(This));
    pApp->userData=&This;
    pApp->onAppCmd=CmdProc;
    pApp->onInputEvent=InputProc;
    This.pApp=pApp;

    //初始化传感器
    This.pSensorManager=ASensorManager_getInstance();
    This.pAccelerometerSensor=ASensorManager_getDefaultSensor(This.pSensorManager,ASENSOR_TYPE_ACCELEROMETER);
    This.pSensorEventQueue=ASensorManager_createEventQueue(This.pSensorManager,pApp->looper,LOOPER_ID_USER,NULL,NULL);

    if(pApp->savedState)//从已有的状态恢复回来
      memcpy(&(This.State),pApp->savedState,sizeof(SavedState));

    for(;;)
    {
      int iIdent;
      int iEvents;
      struct android_poll_source*pSource;
      
      //从传感器读取事件
      while((iIdent=ALooper_pollAll(0,NULL,&iEvents,(void**)&pSource))>=0)
      {
            //处理事件
            if(pSource)
                pSource->process(pApp,pSource);

            //如果传感器有数据,处理它
            if(iIdent==LOOPER_ID_USER)
            {
                if(This.pAccelerometerSensor)
                {
                  ASensorEvent sEvent;
                  while(ASensorEventQueue_getEvents(This.pSensorEventQueue,&sEvent,1)>0)//取得加速度传感器的采样
                  {
                        This.State.AccX=sEvent.acceleration.x;
                        This.State.AccY=sEvent.acceleration.y;
                        This.State.AccZ=sEvent.acceleration.z;
                  }
                }
            }
            if(pApp->destroyRequested)//退出消息
            {
                CleanupDisplay(&This);
                return;
            }
      }
      DrawFrame(&This);//更新显示
    }
}
页: [1]
查看完整版本: 【安卓】NDK+OpenGL的一个简单的例子