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

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