EGL是opengl的渲染环境(状态机模型环境),在使用opengl之前需要先初始化EGL环境
package com.example.gldemo;
import android.view.Surface;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
public class EGLHelper {
//仿照源码 里面的EglHelper 写 具体看 GLSurfaceView 里面 从start()方法 开始
private EGL10 mEgl;
private EGLDisplay mEglDisplay;//默认的显示设备
private EGLContext mEglContext;
private EGLSurface mEglSurface;
public void initEgl(Surface surface, EGLContext eglContext) {
//1.得到Egl实例
mEgl = (EGL10) EGLContext.getEGL();
//2.得到默认的显示设备(就是窗口)
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
//3.初始化默认显示设备
int[] version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
//4.配置属性自己写 设置显示设备的属性
int[] attrbutes = new int[]{
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 8,
EGL10.EGL_STENCIL_SIZE, 8,
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_NONE
};
//EGL10.EGL_NONE结尾
// EGL_DEPTH_SIZE, 24, //请求深度缓冲区
// EGL_STENCIL_SIZE, 8,//请求模版缓冲区
int[] num_config = new int[1];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, null, 1, num_config)) {
throw new IllegalArgumentException("eglChooseConfig failed");
}
//5.从系统中获取对应属性的配置
int numConfigs = num_config[0];
EGLConfig[] configs = new EGLConfig[numConfigs];
if (!mEgl.eglChooseConfig(mEglDisplay, attrbutes, configs, numConfigs,
num_config)) {
throw new IllegalArgumentException("eglChooseConfig#2 failed");
}
//!!!属性必须要设置, 是指定EGL上下文版本和OpenglES的版本。 如果不指定可能会报错误:
// "glDrawArrays is called with VERTEX_ARRAY client state disabled!!!"
int arrtibuteList[] = new int[]{EGL_CONTEXT_CLIENT_VERSION, 2/*OpenglES Version*/,
EGL10.EGL_NONE};
//6.创建EglContext
if (eglContext != null) {
mEglContext = mEgl.eglCreateContext(mEglDisplay, configs[0], eglContext, null);
} else {//如果没有就创建
mEglContext = mEgl.eglCreateContext(mEglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, null);
}
//7.创建渲染的Surface
//使用Android的surface创建egl surface, surface就是渲染的目标窗口。
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, configs[0], surface, null);
//8.绑定EglContext和Surface到显示设备中
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent fail");
}
}
//9.刷新数据,显示渲染场景
public boolean swapBuffers() {
if (mEgl != null) {
return mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
} else {
throw new RuntimeException("egl is null ");
}
}
//10. 回收数据
public void destoryEgl() {
if (mEgl != null) {
mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEglSurface = null;
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEglContext = null;
mEgl.eglTerminate(mEglDisplay);
mEglDisplay = null;
mEgl = null;
}
}
}
@@: OpenGL是GPU绘制接口,使用opengl绘制之后,数据会被放到显卡的缓存(GPU显存)中,需要调用 EGL的 eglSwapBuffers 将数据转换到目标 eglWindowSurface 中才会显示在屏幕上。
package com.example.gldemo;
import android.opengl.GLES20;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private SurfaceView mSV;
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragCol= vColor;" +
"}";
private int loadShader(int type, String shaderCode) {
//根据type创建顶点着色器或者片元着色器
int shader = GLES20.glCreateShader(type);
//将资源加入到着色器中,并编译
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
int st[] = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, st, 0);
if (st[0] == GLES20.GL_FALSE) {
GLES20.glDeleteShader(shader);
Log.e("Main", "loadShader: shader compile failed");
return GLES20.GL_FALSE;
}
return shader;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
mSV = (SurfaceView) findViewById(R.id.sv);
mSV.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(final SurfaceHolder holder,
int format, final int width, final int height) {
new Thread() {
@Override
public void run() {
super.run();
///////////1. 初始化EGL环境/////////////
EGLHelper eglHelper = new EGLHelper();
eglHelper.initEgl(holder.getSurface(), null);
float r = 0.0f;
float g = 1.0f;
float b = 1.0f;
float triangleCoords[] = {
0.5f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
};
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //白色
while (true) {
///////////2. 绘制背景设置/////////////
//设置视角
GLES20.glViewport(0, 0, width, height);
//清除缓存
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
//清除屏幕颜色
GLES20.glClearColor(r, g, b, 1.0f);
//将顶点坐标保存到浮点数组
FloatBuffer vertextBuffer = ByteBuffer.allocateDirect(triangleCoords.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(triangleCoords);
vertextBuffer.position(0);//重置读取位置到0.
///////////3. 着色器导入,编译/////////////
//导入顶点着色器和片元着色器
int vertextShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
///////////4. Program创建,链接,并绑定到OpenGL 2.0环境/////////////
//创建一个空的OpenGLES程序(运行在GPU的程序), 代表了对Shader的操作
int program = GLES20.glCreateProgram();
//将顶点着色器加入到程序
GLES20.glAttachShader(program, vertextShader);
//将片元着色器加入到程序中
GLES20.glAttachShader(program, fragmentShader);
//连接到着色器程序
GLES20.glLinkProgram(program);
int[] ls = new int[1];
GLES20.glGetProgramiv(program,GLES20.GL_LINK_STATUS, ls, 0);
if (ls[0] == GLES20.GL_FALSE) {
Log.e("Main", "run: glLinkProgram failed");
}
//将程序加入到OpenGLES2.0环境
GLES20.glUseProgram(program);
///////////5. 设置顶点数据/////////////
//获取顶点着色器的vPosition成员句柄
int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
//启用三角形顶点的句柄(必须先启动顶点属性数组才能设置)
GLES20.glEnableVertexAttribArray(vPosition);
//准备三角形坐标数据
GLES20.glVertexAttribPointer(vPosition, 3, GLES20.GL_FLOAT, false, 3*4,
vertextBuffer);
//禁止定点数据句柄,这个可以放在glVertexAttribPointer之前或者之后, 如果
//之前不行就放在之后试一下。。。
//glDisableVertexAttribArray(0);
///////////6. 设置片元数据/////////////
//获取片元着色器的vColor成员的句柄
int vColor = GLES20.glGetUniformLocation(program, "vColor");
//设置绘制三角形的颜色
GLES20.glUniform4fv(vColor, 1, color, 0);
///////////7. 绘制前面设置的数据/////////////
//绘制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, triangleCoords.length / 3);
//绘制完成后再禁止定点数据句柄
GLES20.glDisableVertexAttribArray(vPosition);
///////////8. 显示显示绘制结果/////////////
//[必须要] 绘制完成的数据在显存中, 必须要使用egl的eglSwapBuffer才能将数据显示在surface中,
//显示在屏幕上
eglHelper.swapBuffers();
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
}
public void surfaceChanged(final SurfaceHolder holder, int format, final int width, final int height) {
new Thread() {
@Override
public void run() {
super.run();
EGLHelper eglHelper = new EGLHelper();
eglHelper.initEgl(holder.getSurface(), null);
float r = 0.5f;
float g = 0.5f;
float b = 0.5f;
float triangleCoords[] = {
//x, y
//r, g, b, a
0.5f, 0.5f, // top
1.0f, 1.0f, 1.0f, 1.0f,
-0.5f, -0.5f, // bottom left
1.0f, 1.0f, 1.0f, 1.0f,
0.5f, -0.5f, // bottom right
1.0f, 1.0f, 1.0f, 1.0f,
};
glViewport(0, 0, width, height);
int vertextShader = loadShader(GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
int program = buildProgram(vertextShader, fragmentShader);
//将程序加入到OpenGLES2.0环境
glUseProgram(program);
FloatBuffer vertextBuffer = ByteBuffer.allocateDirect(triangleCoords.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(triangleCoords);
vertextBuffer.position(0);
while (true) {
glClearColor(r, g, b, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
{
/* vPosition */
vertextBuffer.position(0);
//获取顶点着色器的vPosition成员句柄
int vPosition = glGetAttribLocation(program, "vPosition");
//准备三角形坐标数据
glVertexAttribPointer(vPosition, 2, GL_FLOAT, false, 6 * 4, vertextBuffer);
//启用三角形顶点的句柄
glEnableVertexAttribArray(vPosition);
/* aColor */
vertextBuffer.position(2);
int aColor = glGetAttribLocation(program, "aColor");
//为shader属性赋值,一次调用是为所有的顶点赋予属性值
glVertexAttribPointer(aColor, //指定要设置的属性为aColor(颜色属性)
4, //一个顶点读取四个元素
GL_FLOAT, //元素类型是浮点型float
false,
6 * 4, //颜色数值的步长为
//((2(定点2个) + 4(颜色4个)) * 4(一个元素四个字节))个字节
vertextBuffer// 要赋值的buffer的其实偏移地址(颜色越过一个定点
//(两个坐标)从第三个偏移位置上开始)
);
glEnableVertexAttribArray(aColor);//启用定点属性(默认是关闭,
//关闭的话opengl拿不到定点的数据, 绘制失败)
//绘制三角形
glDrawArrays(GL_TRIANGLE_FAN, 0, 3/*从上面的设置中取三组(顶点和颜色)数据*/);
//禁止定点数据句柄
//禁止必须要在绘制之后, 否则绘制失败
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
eglHelper.swapBuffers();
try {
Thread.sleep(16);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
private EGL10 mEgl;
private EGLDisplay mEglDisplay;
private EGLConfig mEglConfig;
private EGLContext mEglContext;
private EGLSurface mEglSurface;
private static final String sSimpleVS =
"attribute vec4 position;\n" +
"attribute vec2 texCoords;\n" +
"varying vec2 outTexCoords;\n" +
"uniform mat4 projection;\n" +
"\nvoid main(void) {\n" +
" outTexCoords = texCoords;\n" +
" gl_Position = projection * position;\n" +
"}\n\n";
private static final String sSimpleFS =
"precision mediump float;\n\n" +
"varying vec2 outTexCoords;\n" +
"uniform sampler2D texture;\n" +
"\nvoid main(void) {\n" +
" gl_FragColor = texture2D(texture, outTexCoords);\n" +
"}\n\n";
private static final int FLOAT_SIZE_BYTES = 4;
private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
//初始化EGL环境
if (!initGL(sh)) return false;
final float right = left + mBackground.getWidth() * mScale;
final float bottom = top + mBackground.getHeight() * mScale;
final Rect frame = sh.getSurfaceFrame();
final Matrix4f ortho = new Matrix4f();
ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
//创建顶点数据缓存结构
final FloatBuffer triangleVertices = createMesh(left, top, right, bottom);
//导入Texure(Bitmap位图数据)
final int texture = loadTexture(mBackground);
//创建Program,链接顶点和片元着色器
final int program = buildProgram(sSimpleVS, sSimpleFS);
final int attribPosition = glGetAttribLocation(program, "position");
final int attribTexCoords = glGetAttribLocation(program, "texCoords");
final int uniformTexture = glGetUniformLocation(program, "texture");
final int uniformProjection = glGetUniformLocation(program, "projection");
checkGlError();
glViewport(0, 0, frame.width(), frame.height());
//绑定纹理,绑定之后,所有的操作都针对当前的纹理进行操作
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(program);//绑定program到当前的opengl版本环境
glEnableVertexAttribArray(attribPosition);
glEnableVertexAttribArray(attribTexCoords);
glUniform1i(uniformTexture, 0);
glUniformMatrix4fv(uniformProjection, 1, false, ortho.getArray(), 0);
checkGlError();
if (w > 0 || h > 0) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
// drawQuad
triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
//绘制
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//显示绘制内容
boolean status = mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
checkEglError();
finishGL(texture, program);
return status;
}
//初始化EGL环境
private boolean initGL(SurfaceHolder surfaceHolder) {
mEgl = (EGL10) EGLContext.getEGL();
mEglDisplay = mEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}
int[] version = new int[2];
if (!mEgl.eglInitialize(mEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}
mEglConfig = chooseEglConfig();
if (mEglConfig == null) {
throw new RuntimeException("eglConfig not initialized");
}
mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
if (mEglContext == EGL_NO_CONTEXT) {
throw new RuntimeException("createContext failed " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}
int attribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
EGLSurface tmpSurface = mEgl.eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
mEgl.eglMakeCurrent(mEglDisplay, tmpSurface, tmpSurface, mEglContext);
int[] maxSize = new int[1];
Rect frame = surfaceHolder.getSurfaceFrame();
glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0);
mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, tmpSurface);
if(frame.width() > maxSize[0] || frame.height() > maxSize[
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEgl.eglTerminate(mEglDisplay);
Log.e(GL_LOG_TAG, "requested texture size " +
frame.width() + "x" + frame.height() + " exceeds the support maximum of " +
maxSize[0] + "x" + maxSize[0]);
return false;
}
mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null);
if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
int error = mEgl.eglGetError();
if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) {
Log.e(GL_LOG_TAG, "createWindowSurface returned " +
GLUtils.getEGLErrorString(error) + ".");
return false;
}
throw new RuntimeException("createWindowSurface failed " +
GLUtils.getEGLErrorString(error));
}
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent failed " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
}
return true;
}
private EGLConfig chooseEglConfig() {
int[] configsCount = new int[1];
EGLConfig[] configs = new EGLConfig[1];
int[] configSpec = getConfig();
if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
throw new IllegalArgumentException("eglChooseConfig failed " +
GLUtils.getEGLErrorString(mEgl.eglGetError()));
} else if (configsCount[0] > 0) {
return configs[0];
}
return null;
}
private int[] getConfig() {
return new int[] {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 0,
EGL_STENCIL_SIZE, 0,
EGL_CONFIG_CAVEAT, EGL_NONE,
EGL_NONE
};
}
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
return egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);
}
private int loadTexture(Bitmap bitmap) {
int[] textures = new int[1];
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, textures, 0);
checkGlError();
int texture = textures[0];
glBindTexture(GL_TEXTURE_2D, texture);
checkGlError();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//设置要绘制的内容为2D,并设置纹理类型和格式等参数,和纹理图片数据(bitmap)
GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
checkGlError();
return texture;
}
private int buildProgram(String vertex, String fragment) {
int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
if (vertexShader == 0) return 0;
int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
if (fragmentShader == 0) return 0;
int program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
checkGlError();
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
int[] status = new int[1];
glGetProgramiv(program, GL_LINK_STATUS, status, 0);
if (status[0] != GL_TRUE) {
String error = glGetProgramInfoLog(program);
Log.d(GL_LOG_TAG, "Error while linking program:\n" + error);
glDeleteProgram(program);
return 0;
}
private FloatBuffer createMesh(int left, int top, float right, float bottom) {
final float[] verticesData = {
// X, Y, Z, U, V
left, bottom, 0.0f, 0.0f, 1.0f,
right, bottom, 0.0f, 1.0f, 1.0f,
left, top, 0.0f, 0.0f, 0.0f,
right, top, 0.0f, 1.0f, 0.0f,
};
final int bytes = verticesData.length * FLOAT_SIZE_BYTES;
final FloatBuffer triangleVertices = ByteBuffer.allocateDirect(bytes).order(
ByteOrder.nativeOrder()).asFloatBuffer();
triangleVertices.put(verticesData).position(0);
return triangleVertices;
}
private int buildShader(String source, int type) {
int shader = glCreateShader(type);
glShaderSource(shader, source);
checkGlError();
glCompileShader(shader);
checkGlError();
int[] status = new int[1];
glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
if (status[0] != GL_TRUE) {
String error = glGetShaderInfoLog(shader);
Log.d(GL_LOG_TAG, "Error while compiling shader:\n" + error);
glDeleteShader(shader);
return 0;
}
return shader;
}
private void finishGL(int texture, int program) {
int[] textures = new int[1];
textures[0] = texture;
glDeleteTextures(1, textures, 0);
glDeleteProgram(program);
mEgl.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEgl.eglTerminate(mEglDisplay);
}
步骤:
GLuint texId; //创建一张用于附着到FB的问题
glActiveTexture(GL_TEXTURE_2D);
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId); //绑定使用该纹理
//设置纹理参数
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//创建framebuffer和renderbuffer
GLuint fb, renderBuffer;
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);//绑定renderbuffer
//设置renderbuffer的缓冲大小
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
min(esContext->width, GL_MAX_RENDERBUFFER_SIZE),
min(esContext->height, GL_MAX_RENDERBUFFER_SIZE));
//附着纹理到framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
//绑定renderbuffer到FB
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
esLogMessage("!GL_FRAMEBUFFER_COMPLETE(%x)\n", status);
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
return;
}
//各种draw()...
const size_t size = (const size_t) (esContext->width * esContext->height * 4);
void *const ptr = malloc(size);
//glReadPixels 是从当前使用的FB中读取图形缓存数据,通过这个可以将渲染的数据拿出来(离屏渲染).
glReadPixels(0, 0, esContext->width, esContext->height, GL_RGB565, GL_UNSIGNED_BYTE, ptr);
//纹理拷贝
//创建一张空纹理, 用于拷贝当前FB中的数据,拷贝前需要绑定.
GLuint tex2[1];
glGenTextures(1, tex2);
glBindTexture(GL_TEXTURE_2D ,tex2[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//glCopyTexImage2D 可以从当前绑定的FB中将其附着的纹理中的数据拷贝到当前正在绑定使用的一张纹理上.
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0,esContext->width , esContext->height,0);
//使用完后,要将framebuffer切换回默认的framebuffer(屏幕使用的FB)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
混合是根据一定的设置, 将多张纹理/绘制目标进行一定的混合计算,最后渲染到屏幕上.
混合的目的是对目标纹理和源纹理进行透明度或者颜色交叉计算.
一半在由透明渲染需求的时候, 会用到混合.
步骤:
//绘制源纹理
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, 3);
...
//在启用混合之前,都属于源纹理
//启用混合之后,绘制的都属于目标纹理
glEnable(GL_BLEND); //启用混合
glBlendColor(1, 1, 1, 0.5f); //设置混合颜色
//使用glBlendColor设置的混合颜色,进行混合.
//这里表示源和目标都使用Alpha来进行混合(只混合透明度)
glBlendFunc(GL_CONSTANT_ALPHA, GL_CONSTANT_ALPHA);
//绘制目标纹理
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 0, 3);
...
//关闭混合
glDisable(GL_BLEND);