android native 使用opengl es畫點線面圖形(純c++)

一、首先需要對EGL進行初始化:

void Renderer::initEGL()
{
    const EGLint attribs[] =
    { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE };
    EGLint width, height, 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);

    //instance->surface = eglCreateWindowSurface(instance->display, instance->config[0], WindowTypes, NULL);
    surface = eglCreateWindowSurface(display, config, mWindow, NULL);
    EGLint attrs[] =
    { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    context = eglCreateContext(display, config, NULL, attrs);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
    {
        printf("------EGL-FALSE\n");
        return;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &width);
    eglQuerySurface(display, surface, EGL_HEIGHT, &height);

    mDisplay = display;
    mSurface = surface;
    mContext = context;
    mWidth = width;
    mHeight = height;
    printf("width:%d, height:%d\n", mWidth, mHeight);

}

EGL 是 OpenGL ES 和底層 Native 平臺視窗系統之間的接口,主要是爲了保證opengl es的平臺獨立性,EGL可以理解爲一塊一塊畫布,提供給

OpengGL ES來繪圖。

display用來獲取默認的顯示設備,可以理解爲顯示屏幕。surface可以理解爲使用native創建的java層中的surface。

比較重要的是:eglMakeCurrent(display, surface, surface, context),主要告訴設備在這個surface上面繪製圖像,經過測試,創建多個surface,

然後決定在哪個surface上面繪製圖像就由這個函數來決定。


二、模仿java層的glsurface進行初始化以及繪製:

void Renderer::nativeSurfaceCreated()
{
    printf("nativeSurfaceCreated\n");
    int program = 0;
    
    glClearColor(0.0f, 0.0f, 0.0f, 0.3f);
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);

    program = glutil->createProgram(vertexShaderCode, fragmentShaderCode);
    glUseProgram(program);
    aColorLocation = glGetAttribLocation(program, A_COLOR);
    aPositionLocation = glGetAttribLocation(program, A_POSITION);
    glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, tableVerticesWithTriangles);
    
    glEnableVertexAttribArray(aPositionLocation);
    glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, tableVerticesWithTriangles + POSITION_COMPONENT_COUNT);
    glEnableVertexAttribArray(aColorLocation);
}

glClearColor主要是把畫布初始化設置顏色,參數就是RGBA,範圍都是0.0-1.0,後面的glClear(GL_COLOR_BUFFER_BIT)纔是繪製的主要

函數;

createProgram是自己寫的作爲編譯連接glsl語言,主要就是運行在GPU上面的語言,主要的頂點以及顏色信息就是在這個裏面運算渲染;

aColorLocation就是獲取program中的句柄,使用glVertexAttribPointer對其進行賦值交給GPU去運算,告訴GPU渲染的顏色,COLOR_COMPONENET

是讀取顏色的長度,也就是在後面的數組中讀取顏色,STRIDE也是自己定義的每次讀取需要偏移的位數,最後一個參數是確定從哪裏開始讀取;

aPositionLocation是告訴GPU在哪些頂點去渲染;

glEnableVertexAttribArray就是使句柄生效。

void Renderer::nativeSurfaceChanged(EGLint width, EGLint height)
{
    glViewport(0, 0, width, height);
}
這個可以理解爲java層的Render中的SurfaceChanged;

void Renderer::nativeDraw()
{
    //printf("nativeDraw!!!\n");
    //glClearColor(0.3f, 0.0f, 0.0f, 0.3f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
    glDrawArrays(GL_LINES, 6, 2);
    glDrawArrays(GL_POINTS, 8, 2);
    glDrawArrays(GL_POINTS, 9, 1);
}
const GLfloat tableVerticesWithTriangles[] =
{
     0.0f,  0.0f, 1.0f, 1.0f, 1.0f,
    -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
     0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
     0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
    -0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
    -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,

    // Line 1
    -0.5f, 0.0f, 1.0f, 1.0f, 1.0f,
     0.5f, 0.0f, 0.0f, 0.0f, 0.0f,

    // Mallets
    0.0f, -0.25f, 1.0f, 0.0f, 0.0f,
    0.0f,  0.25f, 0.0f, 1.0f, 0.0f
};
這個就是具體繪製的函數,首先繪製兩個三角形,在本程序中就是繪製了一個長方形,從以上的數組中第0個開始的六個點確定了這兩個三角形

的位置信息,也就是(0.0f, 0.0f),( -0.5f,-0.5),(0.5, -0.5),(0.5, 0.5),(-0.5,0.5),(-0.5, -0.5),偏移量是由上面的surfaceCreate

中已經確定,每個點後面的三個值是RGB值,A默認爲1;

這個就是最終運行效果圖:

後面貼一下主要的代碼:

/*main.cpp*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/prctl.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

#include "GLUtil.h"
#include "Renderer.h"

using namespace android;

int main(int argc, char ** argv)
{
    Renderer * mRenderer = NULL;
    
    mRenderer = new Renderer();

    //mRenderer->start();
    EGLNativeWindowType WindowTypes = (EGLNativeWindowType) mRenderer->glutil->getNativeWindow(800, 600, 100, 100, 0);
    mRenderer->requestInitEGL(WindowTypes);

    while(1)
        mRenderer->requestRenderFrame();
    
    mRenderer->requestDestroy();
    ANativeWindow_release(WindowTypes);
    delete mRenderer;
    return 0;
}
Render.cpp:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/prctl.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

#include "GLUtil.h"
#include "Renderer.h"

const char * vertexShaderCode = 
    "attribute vec4 a_Position;"
    "attribute vec4 a_Color;"
    "varying vec4 v_Color;"
    "void main(){"
        "v_Color = a_Color;"
        "gl_Position = a_Position;"
        "gl_PointSize = 10.0;}";

const char * fragmentShaderCode =         
        "precision mediump float;"
        "varying vec4 v_Color;"
        "void main(){"
            "gl_FragColor = v_Color;}";

#define COLOR_COMPONENT_COUNT 3
#define POSITION_COMPONENT_COUNT 2
#define STRIDE ((COLOR_COMPONENT_COUNT + POSITION_COMPONENT_COUNT) * 4)
#define A_COLOR "a_Color"
#define A_POSITION "a_Position"

const GLfloat tableVerticesWithTriangles[] =
{
     0.0f,  0.0f, 1.0f, 1.0f, 1.0f,
    -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
     0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
     0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
    -0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
    -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,

    // Line 1
    -0.5f, 0.0f, 1.0f, 1.0f, 1.0f,
     0.5f, 0.0f, 0.0f, 0.0f, 0.0f,

    // Mallets
    0.0f, -0.25f, 1.0f, 0.0f, 0.0f,
    0.0f,  0.25f, 0.0f, 1.0f, 0.0f
};

Renderer::Renderer()
{
    //pthread_mutex_init(&mMutex, NULL);
    //pthread_cond_init(&mCondVar, NULL);
    mDisplay = EGL_NO_DISPLAY;
    mSurface = EGL_NO_SURFACE;
    mContext = EGL_NO_CONTEXT;
    glutil = new GLUtil();
}

Renderer::~Renderer()
{
    //pthread_mutex_destroy(&mMutex);
    //pthread_cond_destroy(&mCondVar);
}

void Renderer::start()
{
    pthread_create(&mThread, NULL, startRenderThread, this);
}

void Renderer::requestInitEGL(EGLNativeWindowType pWindow)
{
    //pthread_mutex_lock(&mMutex);
    mWindow = pWindow;
    //mEnumRenderEvent = RE_SURFACE_CHANGED;
    initEGL();
    nativeSurfaceCreated();
    nativeSurfaceChanged(mWidth, mHeight);

    //pthread_mutex_unlock(&mMutex);
    //pthread_cond_signal(&mCondVar);
}
void Renderer::requestRenderFrame()
{
    //pthread_mutex_lock(&mMutex);
    mEnumRenderEvent = RE_DRAW_FRAME;
    nativeDraw();
    eglSwapBuffers(mDisplay, mSurface);
    //pthread_mutex_unlock(&mMutex);
    //pthread_cond_signal(&mCondVar);
}

void Renderer::requestDestroy()
{
    //pthread_mutex_lock(&mMutex);
    //mEnumRenderEvent = RE_EXIT;
    terminateDisplay();
    mISRenderering = false;
    //pthread_mutex_unlock(&mMutex);
    //pthread_cond_signal(&mCondVar);
}

void Renderer::onRenderThreadRun()
{
    mISRenderering = true;
    while (mISRenderering)
    {
        //pthread_mutex_lock(&mMutex);
        // 姣忓畬鎴愪竴涓簨浠跺氨wait鍦ㄨ繖閲岀洿鍒版湁鍏朵粬浜嬩歡鍞ら啋
        //pthread_cond_wait(&mCondVar, &mMutex);

        printf("-------this mEnumRenderEvent is %d\n", mEnumRenderEvent);
        switch (mEnumRenderEvent)
        {
            case RE_SURFACE_CHANGED:
                printf("-------case RE_SURFACE_CHANGED\n");
                //mEnumRenderEvent = RE_NONE;
                //pthread_mutex_unlock(&mMutex);
                initEGL();
                nativeSurfaceCreated();
                nativeSurfaceChanged(mWidth, mHeight);
                break;
            case RE_DRAW_FRAME:
                //mEnumRenderEvent = RE_NONE;
                //pthread_mutex_unlock(&mMutex);
                // draw
                nativeDraw();
                eglSwapBuffers(mDisplay, mSurface);
                break;
            case RE_EXIT:
                //mEnumRenderEvent = RE_NONE;
                //pthread_mutex_unlock(&mMutex);
                terminateDisplay();
                mISRenderering = false;
                break;
            //default:
                //mEnumRenderEvent = RE_NONE;
                //pthread_mutex_unlock(&mMutex);
        }
    }
}
void *Renderer::startRenderThread(void * pVoid)
{
    Renderer * render = (Renderer*) pVoid;
    render->onRenderThreadRun();

    return NULL;
}

void Renderer::initEGL()
{
    const EGLint attribs[] =
    { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8,
            EGL_RED_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE };
    EGLint width, height, 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);

    //instance->surface = eglCreateWindowSurface(instance->display, instance->config[0], WindowTypes, NULL);
    surface = eglCreateWindowSurface(display, config, mWindow, NULL);
    EGLint attrs[] =
    { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    context = eglCreateContext(display, config, NULL, attrs);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
    {
        printf("------EGL-FALSE\n");
        return;
    }

    eglQuerySurface(display, surface, EGL_WIDTH, &width);
    eglQuerySurface(display, surface, EGL_HEIGHT, &height);

    mDisplay = display;
    mSurface = surface;
    mContext = context;
    mWidth = width;
    mHeight = height;
    printf("width:%d, height:%d\n", mWidth, mHeight);

}

void Renderer::terminateDisplay()
{
    if (mDisplay != EGL_NO_DISPLAY)
    {
        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
                EGL_NO_CONTEXT);
        if (mContext != EGL_NO_CONTEXT)
        {
            eglDestroyContext(mDisplay, mContext);
        }
        if (mSurface != EGL_NO_SURFACE)
        {
            eglDestroySurface(mDisplay, mSurface);
        }
        eglTerminate(mDisplay);
    }

    mDisplay = EGL_NO_DISPLAY;
    mSurface = EGL_NO_SURFACE;
    mContext = EGL_NO_CONTEXT;
}
int program = 0;
int angle = 0;
void Renderer::nativeSurfaceCreated()
{
#if 1
    printf("nativeSurfaceCreated\n");
    int program = 0;
    
    glClearColor(0.0f, 0.0f, 0.0f, 0.3f);
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);

    program = glutil->createProgram(vertexShaderCode, fragmentShaderCode);
    glUseProgram(program);
    aColorLocation = glGetAttribLocation(program, A_COLOR);
    aPositionLocation = glGetAttribLocation(program, A_POSITION);
    glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, tableVerticesWithTriangles);
    
    glEnableVertexAttribArray(aPositionLocation);
    glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, tableVerticesWithTriangles + POSITION_COMPONENT_COUNT);
    glEnableVertexAttribArray(aColorLocation);
#else
    //int program = 0;
    glClearColor(0.0f, 0.0f, 0.0f, 0.3f);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    program = glutil->createProgram(vertexShaderCode, fragmentShaderCode);
    //glViewport(0, 0, width, height);

    glUseProgram(program);
#endif
}

void Renderer::nativeSurfaceChanged(EGLint width, EGLint height)
{
    glViewport(0, 0, width, height);
}

void Renderer::nativeDraw()
{
    //printf("nativeDraw!!!\n");
    //glClearColor(0.3f, 0.0f, 0.0f, 0.3f);
    glClear(GL_COLOR_BUFFER_BIT);
    
    glDrawArrays(GL_TRIANGLE_FAN, 0, 6);
    glDrawArrays(GL_LINES, 6, 2);
    glDrawArrays(GL_POINTS, 8, 2);
    glDrawArrays(GL_POINTS, 9, 1);
}
EGLNativeWindowType GLUtil::getNativeWindow(int width, int hight, int position_x, int position_y, int type)
{
    DisplayInfo dinfo;
    
    mComposerClient = new SurfaceComposerClient();
    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
                        ISurfaceComposer::eDisplayIdMain));

    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    printf("w=%d,h=%d,xdpi=%f,ydpi=%f,fps=%f,ds=%f\n", 
                dinfo.w, dinfo.h, dinfo.xdpi, dinfo.ydpi, dinfo.fps, dinfo.density);

    mSurfaceControl = mComposerClient->createSurface(
        String8("Test Surface"),
        dinfo.w, dinfo.h,
        PIXEL_FORMAT_RGBA_8888, 0);

    SurfaceComposerClient::openGlobalTransaction();
    mSurfaceControl->setLayer(100000);//設定Z座標
    mSurfaceControl->setPosition(position_x, position_y);
    mSurfaceControl->setSize(width, hight);

    SurfaceComposerClient::closeGlobalTransaction();

    sp<ANativeWindow> window = mSurfaceControl->getSurface();

    return window.get();
}


void GLUtil::disposeNativeWindow(void)
{
    if (mComposerClient != NULL) 
    {
        mComposerClient->dispose();
        mComposerClient = NULL;
        mSurfaceControl = NULL;
    }
}

以上代碼爲部分代碼,程序的編譯需要在android源碼編譯環境中編譯,這個會比較麻煩,我提供一個編譯好的可以試着在android中運行一下,

看看效果:opengl_test

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章