不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!
【OpenGL ES】构建可移植、易扩展的代码书写结构
package com.example.openglndk;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.setEGLContextClientVersion(3);
GLSurfaceView.Renderer renderer = new MyRenderer(this);
mGLSurfaceView.setRenderer(renderer);
}
}
JAVA语言
分离GLSL语言
-
创建assets 文件夹 -
在assets 文件夹中创建glsl 文件
创建工具类
-
工具类中有三个方法。
public static String readFileFromAssets(Context context, String fileName) {
InputStream inputStream = null;
Reader reader = null;
BufferedReader bufferedReader = null;
StringBuilder shaderCode = new StringBuilder();
try {
inputStream = context.getResources().getAssets().open(fileName);
reader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(reader);
String temp;
while ((temp = bufferedReader.readLine()) != null) {
shaderCode.append(temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return shaderCode.toString();
}
public static int LoadShader(int type, String shaderCode) {
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
GLES30.glShaderSource(shaderId, shaderCode);
GLES30.glCompileShader(shaderId);
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
return 0;
}
}
public static int linkProgram(int vertexShader, int fragmentShader) {
final int program = GLES30.glCreateProgram();
if (program != 0) {
GLES30.glAttachShader(program, vertexShader);
GLES30.glAttachShader(program, fragmentShader);
GLES30.glLinkProgram(program);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(program);
System.err.println(logInfo);
GLES30.glDeleteProgram(program);
return 0;
}
return program;
} else {
return 0;
}
}
传入环境
C++语言
分离GLSL语言
和JAVA版本的一样。
创建工具类
在工具类中需加入下列头文件。
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <malloc.h>
#include <iostream>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
-
工具类中还是三个方法。
/**
* 读取文件
* @param env jni环境
* @param assetManager 资源
* @param fileName 文件名
* @return 数据字符串
*/
char *readFileFromAssets(JNIEnv *env, jobject assetManager, char *fileName) {
//创建资源
AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
if (mgr == NULL) {
return nullptr;
}
//根据文件名打开资源文件
AAsset *asset = AAssetManager_open(mgr, fileName, AASSET_MODE_UNKNOWN);
if (NULL == asset) {
return nullptr;
}
//获取文件长度
long size = AAsset_getLength(asset);
//获取内存,存储数据
char *shaderCode = (char *) malloc(sizeof(char) * size + 1);
//结尾符号
shaderCode[size] = '\0';
//读取资源文件到buffer缓冲区中
AAsset_read(asset, shaderCode, size);
//不可释放内存,释放了数据就没了
// free(shaderCode);
//释放资源
AAsset_close(asset);
//返回数据
return shaderCode;
}
/**创建和编译着色器
*
*/
GLuint LoadShader(int type, char *shaderCode) {
//创建一个着色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加载到着色器
glShaderSource(shader, 1, &shaderCode, NULL);
//编译着色器
glCompileShader(shader);
//检测状态
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//声明log长度变量
GLint infoLen = 0;
//获取长度并赋值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//创建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
cout << "SHADER ERROR!" << endl;
free(infoLog);
}
//创建失败
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//创建失败
return 0;
}
}
/**链接统一管理程序
*
*/
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//将顶点着色器加入到程序
glAttachShader(program, vertexShader);
//将片元着色器加入到程序中
glAttachShader(program, fragmentShader);
//链接着色器程序
glLinkProgram(program);
//检测状态
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
cout << "PROGRAM ERROR!" << endl;
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//创建失败
return 0;
}
}
传入环境
总结
根据上述划分,可以分为五部分:
GLSL 语句文件。- 工具类来实现读取文件、创建和编译着色器、链接统一管理程序等功能。
- 在构造方法中,利用上下文环境来使用这些方法。
- 在
surfaceChanged 中确定图形尺寸。 - 在
drawFrame 中进行图形绘制。
如果是GLSL 语句发生变化,改变其文件即可;绘制图形变化,改变drawFrame 方法即可。所以这样只要哪一个部分改变,修改那个部分即可,实现了分离,利于维护和扩展代码。
|