下面列出了android.opengl.EGLContext#android.opengl.GLES20 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static void sendImage(int width, int height, Context context, FileUtils.FileSavedCallback fileSavedCallback) {
final IntBuffer pixelBuffer = IntBuffer.allocate(width * height);
//about 20-50ms
long start = System.nanoTime();
GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
pixelBuffer);
long end = System.nanoTime();
Log.d(TAG, "glReadPixels time: " + (end - start)/1000000+" ms");
//about 700-4000ms(png) 200-1000ms(jpeg)
//use jpeg instead of png to save time
//it will consume large memory and may take a long time, depends on the phone
new SaveBitmapTask(pixelBuffer,width,height,context,fileSavedCallback).execute();
}
@Override
protected int createTextureId() {
int[] textures = new int[1];
// Generate the texture to where android view will be rendered
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glGenTextures(1, textures, 0);
glCheck("Texture generate");
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[0]);
glCheck("Texture bind");
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
return textures[0];
}
@Override
public void onDraw() {
if (bitmap == null) {
createBitmap();
}
if (bitmap.getWidth() != inputResolution.getWidth() || bitmap.getHeight() != inputResolution.getHeight()) {
createBitmap();
}
bitmap.eraseColor(Color.argb(0, 0, 0, 0));
Canvas bitmapCanvas = new Canvas(bitmap);
bitmapCanvas.scale(1, -1, bitmapCanvas.getWidth() / 2, bitmapCanvas.getHeight() / 2);
drawCanvas(bitmapCanvas);
int offsetDepthMapTextureUniform = getHandle("oTexture");// 3
GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
if (bitmap != null && !bitmap.isRecycled()) {
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap, 0);
}
GLES20.glUniform1i(offsetDepthMapTextureUniform, 3);
}
/**
* Generate texture and framebuffer resources. An EGLContext must be bound on the current thread
* when calling this function. The framebuffer is not complete until setSize() is called.
*/
public GlTextureFrameBuffer(int pixelFormat) {
switch (pixelFormat) {
case GLES20.GL_LUMINANCE:
case GLES20.GL_RGB:
case GLES20.GL_RGBA:
this.pixelFormat = pixelFormat;
break;
default:
throw new IllegalArgumentException("Invalid pixel format: " + pixelFormat);
}
// Create texture.
textureId = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
this.width = 0;
this.height = 0;
// Create framebuffer object.
final int frameBuffers[] = new int[1];
GLES20.glGenFramebuffers(1, frameBuffers, 0);
frameBufferId = frameBuffers[0];
}
@CalledByNative
public void deallocate() {
if (mCamera == null)
return;
stopCapture();
try {
mCamera.setPreviewTexture(null);
if (mGlTextures != null)
GLES20.glDeleteTextures(1, mGlTextures, 0);
mCurrentCapability = null;
mCamera.release();
mCamera = null;
} catch (IOException ex) {
Log.e(TAG, "deallocate: failed to deallocate camera, " + ex);
return;
}
}
private void createFrameBuffer() {
GLES20.glGenFramebuffers(1, fboFrame, 0);
GLES20.glGenTextures(fboTexture.length, fboTexture, 0);
for (int i = 0; i < fboTexture.length; i++) {
// bind to fbo texture cause we are going to do setting.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTexture[i]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, surfaceWidth, surfaceHeight,
0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
// 设置缩小过滤为使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
// 设置放大过滤为使用纹理中坐标最接近的若干个颜色,通过加权平均算法得到需要绘制的像素颜色
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// 设置环绕方向S,截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
// 设置环绕方向T,截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// unbind fbo texture.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
}
}
private static int loadTexture(Bitmap bitmap, boolean recycle) {
int textures[] = new int[1];
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
if (recycle) {
bitmap.recycle();
}
return textures[0];
}
/**
* Creates a GL_TEXTURE_EXTERNAL_OES with default configuration of GL_LINEAR filtering and
* GL_CLAMP_TO_EDGE wrapping.
*/
public static int createExternalTexture() {
int[] texId = new int[1];
GLES20.glGenTextures(1, IntBuffer.wrap(texId));
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texId[0]);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
checkGlError();
return texId[0];
}
public void onDrawFrame(GL10 unused) {
// Redraw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Calculate the projection and view transformation
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
// Combine the rotation matrix with the projection and camera view
// Note that the mMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
// Draw triangle
mTriangle.draw(scratch);
}
/**
* Converts a raw text file, saved as a resource, into an OpenGL ES shader.
*
* @param type The type of shader we will be creating.
* @param resId The resource ID of the raw text file about to be turned into a shader.
* @return The shader object handler.
*/
public static int loadGLShader(String tag, Context context, int type, int resId) {
String code = readRawTextFile(context, resId);
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, code);
GLES20.glCompileShader(shader);
// Get the compilation status.
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
// If the compilation failed, delete the shader.
if (compileStatus[0] == 0) {
Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader));
GLES20.glDeleteShader(shader);
shader = 0;
}
if (shader == 0) {
throw new RuntimeException("Error creating shader.");
}
return shader;
}
/**
* Generates a frame of data using GL commands. We have an 8-frame animation
* sequence that wraps around. It looks like this:
* <pre>
* 0 1 2 3
* 7 6 5 4
* </pre>
* We draw one of the eight rectangles and leave the rest set to the clear color.
*/
private void generateSurfaceFrame(int frameIndex) {
frameIndex %= 8;
int startX, startY;
if (frameIndex < 4) {
// (0,0) is bottom-left in GL
startX = frameIndex * (mWidth / 4);
startY = mHeight / 2;
} else {
startX = (7 - frameIndex) * (mWidth / 4);
startY = 0;
}
GLES20.glClearColor(TEST_R0 / 255.0f, TEST_G0 / 255.0f, TEST_B0 / 255.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
GLES20.glScissor(startX, startY, mWidth / 4, mHeight / 2);
GLES20.glClearColor(TEST_R1 / 255.0f, TEST_G1 / 255.0f, TEST_B1 / 255.0f, 1.0f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
}
/**
* Renders the point cloud. ArCore point cloud is given in world space.
*
* @param cameraView the camera view matrix for this frame, typically from {@link
* com.google.ar.core.Camera#getViewMatrix(float[], int)}.
* @param cameraPerspective the camera projection matrix for this frame, typically from {@link
* com.google.ar.core.Camera#getProjectionMatrix(float[], int, float, float)}.
*/
public void draw(float[] cameraView, float[] cameraPerspective) {
float[] modelViewProjection = new float[16];
Matrix.multiplyMM(modelViewProjection, 0, cameraPerspective, 0, cameraView, 0);
ShaderUtil.checkGLError(TAG, "Before draw");
GLES20.glUseProgram(mProgramName);
GLES20.glEnableVertexAttribArray(mPositionAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVbo);
GLES20.glVertexAttribPointer(
mPositionAttribute, 4, GLES20.GL_FLOAT, false, BYTES_PER_POINT, 0);
GLES20.glUniform4f(mColorUniform, 31.0f / 255.0f, 188.0f / 255.0f, 210.0f / 255.0f, 1.0f);
GLES20.glUniformMatrix4fv(mModelViewProjectionUniform, 1, false, modelViewProjection, 0);
GLES20.glUniform1f(mPointSizeUniform, 5.0f);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, mNumPoints);
GLES20.glDisableVertexAttribArray(mPositionAttribute);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
ShaderUtil.checkGLError(TAG, "Draw");
}
/*********************************************************************\
|* Shaders *|
\*********************************************************************/
protected void updateUniformLocation(Shader shader, Uniform uniform) {
stringBuf.setLength(0);
stringBuf.append(uniform.getName()).append('\0');
updateNameBuffer();
if (verboseLogging) {
logger.log(Level.INFO, "GLES20.glGetUniformLocation({0}, {1})", new Object[]{shader.getId(), uniform.getName()});
}
int loc = GLES20.glGetUniformLocation(shader.getId(), uniform.getName());
checkGLError();
if (loc < 0) {
uniform.setLocation(-1);
// uniform is not declared in shader
if (verboseLogging) {
logger.log(Level.WARNING, "Uniform [{0}] is not declared in shader.", uniform.getName());
}
} else {
uniform.setLocation(loc);
}
}
/**
* Instantiate Sphere objects
* @param activity
* @param glTrue
* @param steps
* @param positions
* @param colors
* @param radii
*/
public Spheres(Context activity, int glTrue, int steps, float[] positions, float[] colors, float[] radii){
/** initialize the sphere program */
final String sphereVS = RawResourceReader.readTextFileFromRawResource(activity, R.raw.sphere_vertex_shader);
final String sphereFS = RawResourceReader.readTextFileFromRawResource(activity, R.raw.sphere_fragment_shader);
final int sphereVSHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, sphereVS);
final int sphereFSHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, sphereFS);
aSphereProgramHandle = ShaderHelper.createAndLinkProgram(sphereVSHandle, sphereFSHandle,
new String[]{"a_Position", "a_Color"});
// Second, copy these buffers into OpenGL's memory. After, we don't need to keep the client-side buffers around.
glSphereBuffer = new int[4];
GLES20.glGenBuffers(glSphereBuffer.length, glSphereBuffer, 0);
BLENDING = (glTrue == GLES20.GL_TRUE) ? true : false;
createBuffers(positions, colors, radii, steps);
}
private void setColor(Object3DData obj) {
// get handle to fragment shader's vColor member
int mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
GLUtil.checkGlError("glGetUniformLocation");
// Set color for drawing the triangle
float[] color = obj.getColor() != null ? obj.getColor() : DEFAULT_COLOR;
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
GLUtil.checkGlError("glUniform4fv");
}
public void checkGlError(String op) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e(TAG, op + ": glError " + error);
throw new RuntimeException(op + ": glError " + error);
}
}
void draw(float[] mvpMatrix, float r, float g, float b, float a) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
int vertexStride = COORDS_PER_VERTEX * 4;
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
int mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
float[] color = {r, g, b, a};
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
int mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
GLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the square
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public Triangle() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
// prepare shaders and OpenGL program
int vertexShader = MyGLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // create OpenGL program executables
}
public GLShape(float[] color) {
this.color = color;
int vertexShader = GLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE);
int fragmentShader = GLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}
@Override
public void onDrawFrame(final GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
runAll(mRunOnDraw);
mFilter.onDraw(mGLTextureId, mGLCubeBuffer, mGLTextureBuffer);
runAll(mRunOnDrawEnd);
if (mSurfaceTexture != null) {
mSurfaceTexture.updateTexImage();
}
}
/**
* draw specific texture with specific texture matrix
* @param tex_id texture ID
* @param tex_matrix texture matrix、if this is null, the last one use(we don't check size of this array and needs at least 16 of float)
*/
public void draw(int tex_id, float[] tex_matrix) {
GLES20.glUseProgram(hProgram);
if (tex_matrix != null)
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, tex_matrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mMvpMatrix, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex_id);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_NUM);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GLES20.glUseProgram(0);
}
@Override
protected void getGLSLValues() {
mTextureLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexture");
maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition");
muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix");
maTextureCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord");
}
public void draw() {
if (indexBuffer != null){
indexBuffer.position(0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, mNumIndices, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
} else {
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mNumIndices);
}
}
@Override
public void onDrawFrame(GL10 gl) {
//Log.i(LOGTAG, "onDrawFrame start");
if (!mHaveFBO)
return;
synchronized(this) {
if (mUpdateST) {
mSTexture.updateTexImage();
mUpdateST = false;
}
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
CameraTextureListener texListener = mView.getCameraTextureListener();
if(texListener != null) {
//Log.d(LOGTAG, "haveUserCallback");
// texCamera(OES) -> texFBO
drawTex(texCamera[0], true, FBO[0]);
// call user code (texFBO -> texDraw)
boolean modified = texListener.onCameraTexture(texFBO[0], texDraw[0], mCameraWidth, mCameraHeight);
if(modified) {
// texDraw -> screen
drawTex(texDraw[0], false, 0);
} else {
// texFBO -> screen
drawTex(texFBO[0], false, 0);
}
} else {
Log.d(LOGTAG, "texCamera(OES) -> screen");
// texCamera(OES) -> screen
drawTex(texCamera[0], true, 0);
}
//Log.i(LOGTAG, "onDrawFrame end");
}
}
@Override
protected void getLocations() {
maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition");
GlUtil.checkLocation(maPositionLoc, "aPosition");
maTextureCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord");
GlUtil.checkLocation(maTextureCoordLoc, "aTextureCoord");
muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix");
GlUtil.checkLocation(muMVPMatrixLoc, "uMVPMatrix");
muTexMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexMatrix");
GlUtil.checkLocation(muTexMatrixLoc, "uTexMatrix");
}
@Override
public void onDrawFrame(GL10 gl10) {
if (surfaceTexture == null) {
return;
}
if (renderedFrame < updatedFrame) {
surfaceTexture.updateTexImage();
++renderedFrame;
// Utils.debug(
// TAG, "renderedFrame: " + renderedFrame + " updatedFrame: " + updatedFrame
// );
}
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(program);
GLES20.glUniformMatrix4fv(mvpLocation, 1, false, mvp, 0);
// No vertex array in OpenGL ES 2.
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glEnableVertexAttribArray(positionLocation);
GLES20.glVertexAttribPointer(
positionLocation, 2, GLES20.GL_FLOAT, false, 2 * BYTES_PER_FLOAT, 0
);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glEnableVertexAttribArray(texCoordLocation);
GLES20.glVertexAttribPointer(
texCoordLocation, 2, GLES20.GL_FLOAT, false, 2 * BYTES_PER_FLOAT, 0
);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_INT, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glDisableVertexAttribArray(texCoordLocation);
GLES20.glDisableVertexAttribArray(positionLocation);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glUseProgram(0);
}
public void drawToFBO(int textureId,FBO fbo) {
runPreDrawTasks();
if (fboList==null || fbo==null) {
return;
}
int size = filters.size();
int previousTexture = textureId;
for (int i = 0; i < size; i++) {
AbsFilter filter = filters.get(i);
Log.d(TAG, "onDrawFrame: "+i+" / "+size +" "+filter.getClass().getSimpleName()+" "+
filter.surfaceWidth+" "+filter.surfaceHeight);
if (i < size - 1) {
filter.setViewport();
fboList[i].bind();
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
if(filter instanceof FilterGroup){
((FilterGroup) filter).drawToFBO(previousTexture,fboList[i]);
}else{
filter.onDrawFrame(previousTexture);
}
fboList[i].unbind();
previousTexture = fboList[i].getFrameBufferTextureId();
}else{
fbo.bind();
filter.setViewport();
if(filter instanceof FilterGroup){
((FilterGroup) filter).drawToFBO(previousTexture,fbo);
}else{
filter.onDrawFrame(previousTexture);
}
fbo.unbind();
}
}
}
@Override
protected void initGlFilter(Context context) {
String vertexShader = GlUtil.getStringFromRaw(context, R.raw.simple_vertex);
String fragmentShader = GlUtil.getStringFromRaw(context, R.raw.simple_fragment);
program = GlUtil.createProgram(vertexShader, fragmentShader);
aPositionHandle = GLES20.glGetAttribLocation(program, "aPosition");
aTextureHandle = GLES20.glGetAttribLocation(program, "aTextureCoord");
uMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
uSTMatrixHandle = GLES20.glGetUniformLocation(program, "uSTMatrix");
uSamplerHandle = GLES20.glGetUniformLocation(program, "uSampler");
}
/** Releases all allocated resources. */
@SuppressWarnings({"nullness:argument.type.incompatible"})
public void release() {
handler.removeCallbacks(this);
try {
if (texture != null) {
texture.release();
GLES20.glDeleteTextures(1, textureIdHolder, 0);
}
} finally {
if (display != null && !display.equals(EGL14.EGL_NO_DISPLAY)) {
EGL14.eglMakeCurrent(
display, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
}
if (surface != null && !surface.equals(EGL14.EGL_NO_SURFACE)) {
EGL14.eglDestroySurface(display, surface);
}
if (context != null) {
EGL14.eglDestroyContext(display, context);
}
// EGL14.eglReleaseThread could crash before Android K (see [internal: b/11327779]).
if (Util.SDK_INT >= 19) {
EGL14.eglReleaseThread();
}
if (display != null && !display.equals(EGL14.EGL_NO_DISPLAY)) {
// Android is unusual in that it uses a reference-counted EGLDisplay. So for
// every eglInitialize() we need an eglTerminate().
EGL14.eglTerminate(display);
}
display = null;
context = null;
surface = null;
texture = null;
}
}
/**
* Checks for a GL error using {@link GLES20#glGetError()}.
*
* @throws RuntimeException if there is a GL error
*/
static void checkGlError() {
int errorCode;
if ((errorCode = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
throw new RuntimeException("gl error: " + Integer.toHexString(errorCode));
}
}