在上一篇文章中,简单介绍了openGL ES版的helloworld程序,给出了最简单的使用步骤。在接下来的openGLES系列文章中,主要想通过一些demo由浅入深地记录对openGL ES的学习和总结。而这些系列demo会基于一个基本框架基础来开发,因此本文主要是想先介绍这个基本框架。
openGLES的开发可以完全在java层完成,调用其相关的一些接口和类。当然也可以在native层通过c++实现,更贴近openGLES本身。其实这两种都可以,基本没有性能上的优劣,相差不大。但是为了以后在openGLES的处理基础上,再加入其他音视频相关操作,所以本博主考虑在c++层去实现。因此框架的搭建会涉及到natvie层。
一、基本框架流程图
二、大致流程简介
1、MyGLSurfaceView
简单自定义GLSurfaceView,继承GLSurfaceView。
并在里面调用GLSurfaceView的setRenderer方法。绑定渲染实现。
2、MyGLRender
简单自定义一个 Render,实现GLSurfaceView.Renderer接口。
跟之前的文章不同的是,由于我们要在c++层去做opengles相关操作,所以这里的绘制等回调接口都不直接做事情,而是调用到c++层那边的一些接口。
public class MyGLRender implements GLSurfaceView.Renderer {
private static final String TAG = "MyGLRender";
private MyNativeRender mNativeRender;
private int mSampleType;
MyGLRender() {
mNativeRender = new MyNativeRender();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mNativeRender.native_OnSurfaceCreated();
Log.e(TAG, "onSurfaceCreated() called with: GL_VERSION = [" + gl.glGetString(GL10.GL_VERSION) + "]");
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
mNativeRender.native_OnSurfaceChanged(width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
mNativeRender.native_OnDrawFrame();
}
public void init() {
mNativeRender.native_Init();
}
public void unInit() {
mNativeRender.native_UnInit();
}
}
3、MyNativeRender
MyNativeRender只是一个java层到c++层的桥梁,用于2中去调用,如下:
public class MyNativeRender {
public static final int SAMPLE_TYPE = 200;
public static final int SAMPLE_TYPE_TRIANGLE = SAMPLE_TYPE;
static {
System.loadLibrary("native-lib");
}
public native void native_Init();
public native void native_UnInit();
public native void native_SetImageData(int format, int width, int height, byte[] bytes);
public native void native_OnSurfaceCreated();
public native void native_OnSurfaceChanged(int width, int height);
public native void native_OnDrawFrame();
}
4、MyGLRenderContext
到这一步,进入了c++层jni,在jni中,实现相关接口,和绘制。并调用具体的绘制内容的类,去进行渲染和绘制。
MyGLRenderContext* MyGLRenderContext::m_pContext = nullptr;
MyGLRenderContext::MyGLRenderContext()
{
}
MyGLRenderContext::~MyGLRenderContext()
{
}
void MyGLRenderContext::OnSurfaceCreated()
{
LOGCATE("MyGLRenderContext::OnSurfaceCreated");
void MyGLRenderContext::OnSurfaceChanged(int width, int height)
{
LOGCATE("MyGLRenderContext::OnSurfaceChanged [w, h] = [%d, %d]", width, height);
}
void MyGLRenderContext::OnDrawFrame()
{
LOGCATE("MyGLRenderContext::OnDrawFrame");
}
MyGLRenderContext *MyGLRenderContext::GetInstance()
{
LOGCATE("MyGLRenderContext::GetInstance");
}
void MyGLRenderContext::DestroyInstance()
{
LOGCATE("MyGLRenderContext::DestroyInstance");
}
5、xxxSample
在4中,会去调用真正的进行绘制渲染内容的类xxxSample进行渲染等,而一般xxxSample类中实现具体的绘制内容,比如顶点着色器,片元着色器等的编写,绑定等。
这个我们在后面的系列demo中更展开阐述。一般会提供Init、Draw等接口
6、GLUtils
在绘制类中,需要调用编译和绘制着色器相关的东西,将这一块单独提出一个工具类,实现编译和链接着色器程序等。
这个工具类,基本所有系列demo可以共用,是个通用的工具类。
#include "GLUtils.h"
#include "LogUtil.h"
#include <stdlib.h>
#include <cstring>
#include <GLES2/gl2ext.h>
GLuint GLUtils::LoadShader(GLenum shaderType, const char *pSource)
{
GLuint shader = 0;
FUN_BEGIN_TIME("GLUtils::LoadShader")
shader = glCreateShader(shaderType);
if (shader)
{
glShaderSource(shader, 1, &pSource, NULL);
glCompileShader(shader);
GLint compiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled)
{
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen)
{
char* buf = (char*) malloc((size_t)infoLen);
if (buf)
{
glGetShaderInfoLog(shader, infoLen, NULL, buf);
LOGCATE("GLUtils::LoadShader Could not compile shader %d:\n%s\n", shaderType, buf);
free(buf);
}
glDeleteShader(shader);
shader = 0;
}
}
}
FUN_END_TIME("GLUtils::LoadShader")
return shader;
}
GLuint GLUtils::CreateProgram(const char *pVertexShaderSource, const char *pFragShaderSource, GLuint &vertexShaderHandle, GLuint &fragShaderHandle)
{
GLuint program = 0;
FUN_BEGIN_TIME("GLUtils::CreateProgram")
vertexShaderHandle = LoadShader(GL_VERTEX_SHADER, pVertexShaderSource);
if (!vertexShaderHandle) return program;
fragShaderHandle = LoadShader(GL_FRAGMENT_SHADER, pFragShaderSource);
if (!fragShaderHandle) return program;
program = glCreateProgram();
if (program)
{
glAttachShader(program, vertexShaderHandle);
CheckGLError("glAttachShader");
glAttachShader(program, fragShaderHandle);
CheckGLError("glAttachShader");
glLinkProgram(program);
GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
glDetachShader(program, vertexShaderHandle);
glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
glDetachShader(program, fragShaderHandle);
glDeleteShader(fragShaderHandle);
fragShaderHandle = 0;
if (linkStatus != GL_TRUE)
{
GLint bufLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength)
{
char* buf = (char*) malloc((size_t)bufLength);
if (buf)
{
glGetProgramInfoLog(program, bufLength, NULL, buf);
LOGCATE("GLUtils::CreateProgram Could not link program:\n%s\n", buf);
free(buf);
}
}
glDeleteProgram(program);
program = 0;
}
}
FUN_END_TIME("GLUtils::CreateProgram")
LOGCATE("GLUtils::CreateProgram program = %d", program);
return program;
}
GLuint GLUtils::CreateProgramWithFeedback(const char *pVertexShaderSource, const char *pFragShaderSource, GLuint &vertexShaderHandle, GLuint &fragShaderHandle, GLchar const **varying, int varyingCount)
{
GLuint program = 0;
FUN_BEGIN_TIME("GLUtils::CreateProgramWithFeedback")
vertexShaderHandle = LoadShader(GL_VERTEX_SHADER, pVertexShaderSource);
if (!vertexShaderHandle) return program;
fragShaderHandle = LoadShader(GL_FRAGMENT_SHADER, pFragShaderSource);
if (!fragShaderHandle) return program;
program = glCreateProgram();
if (program)
{
glAttachShader(program, vertexShaderHandle);
CheckGLError("glAttachShader");
glAttachShader(program, fragShaderHandle);
CheckGLError("glAttachShader");
//transform feedback
glTransformFeedbackVaryings(program, varyingCount, varying, GL_INTERLEAVED_ATTRIBS);
GO_CHECK_GL_ERROR();
glLinkProgram(program);
GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
glDetachShader(program, vertexShaderHandle);
glDeleteShader(vertexShaderHandle);
vertexShaderHandle = 0;
glDetachShader(program, fragShaderHandle);
glDeleteShader(fragShaderHandle);
fragShaderHandle = 0;
if (linkStatus != GL_TRUE)
{
GLint bufLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
if (bufLength)
{
char* buf = (char*) malloc((size_t)bufLength);
if (buf)
{
glGetProgramInfoLog(program, bufLength, NULL, buf);
LOGCATE("GLUtils::CreateProgramWithFeedback Could not link program:\n%s\n", buf);
free(buf);
}
}
glDeleteProgram(program);
program = 0;
}
}
FUN_END_TIME("GLUtils::CreateProgramWithFeedback")
LOGCATE("GLUtils::CreateProgramWithFeedback program = %d", program);
return program;
}
void GLUtils::DeleteProgram(GLuint &program)
{
LOGCATE("GLUtils::DeleteProgram");
if (program)
{
glUseProgram(0);
glDeleteProgram(program);
program = 0;
}
}
void GLUtils::CheckGLError(const char *pGLOperation)
{
for (GLint error = glGetError(); error; error = glGetError())
{
LOGCATE("GLUtils::CheckGLError GL Operation %s() glError (0x%x)\n", pGLOperation, error);
}
}
GLuint GLUtils::CreateProgram(const char *pVertexShaderSource, const char *pFragShaderSource) {
GLuint vertexShaderHandle, fragShaderHandle;
return CreateProgram(pVertexShaderSource, pFragShaderSource, vertexShaderHandle, fragShaderHandle);
}
框架就大概介绍到这里,在接下来的opengles系列demo中,我会在这个框架的基础上,进行一些demo的阐述和介绍。