在上一篇文章中,简单介绍了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#include #include 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%sn", 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%sn", 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%sn", 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的阐述和介绍。



