package com.marshalchen.common.uimodule.imageprocessing.filter;
import android.opengl.GLES20;
/**
* An extension of BasicFilter. This class allows for a filter program to be applied twice to a given input.
* The same fragment and vertex shaders will be used for both of the passes. Also the same values will be passed
* for both passes unless specifically changed. To check which pass is currently being run during passShaderValues(),
* getCurrentPass() can be called. The current pass will either be 1 or 2.
* @author Chris Batt
*/
public abstract class TwoPassFilter extends BasicFilter {
private int[] firstPassFrameBuffer;
private int[] firstPassTextureOut;
private int[] firstPassDepthRenderBuffer;
private int currentPass;
/* (non-Javadoc)
* @see com.marshalchen.common.uimodule.imageprocessing.input.GLTextureOutputRenderer#destroy()
*/
@Override
public void destroy() {
super.destroy();
if(firstPassFrameBuffer != null) {
GLES20.glDeleteFramebuffers(1, firstPassFrameBuffer, 0);
firstPassFrameBuffer = null;
}
if(firstPassTextureOut != null) {
GLES20.glDeleteTextures(1, firstPassTextureOut, 0);
firstPassTextureOut = null;
}
if(firstPassDepthRenderBuffer != null) {
GLES20.glDeleteRenderbuffers(1, firstPassDepthRenderBuffer, 0);
firstPassDepthRenderBuffer = null;
}
}
@Override
protected void drawFrame() {
currentPass = 1;
if(firstPassFrameBuffer == null) {
if(getWidth() != 0 && getHeight() != 0) {
initFBO();
} else {
return;
}
}
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, firstPassFrameBuffer[0]);
if(texture_in == 0) {
return;
}
GLES20.glViewport(0, 0, getWidth(), getHeight());
GLES20.glUseProgram(programHandle);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(getBackgroundRed(), getBackgroundGreen(), getBackgroundBlue(), getBackgroundAlpha());
passShaderValues();
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
texture_in = firstPassTextureOut[0];
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
currentPass = 2;
super.drawFrame();
}
protected int getCurrentPass() {
return currentPass;
}
private void initFBO() {
if(firstPassFrameBuffer != null) {
GLES20.glDeleteFramebuffers(1, firstPassFrameBuffer, 0);
firstPassFrameBuffer = null;
}
if(firstPassTextureOut != null) {
GLES20.glDeleteTextures(1, firstPassTextureOut, 0);
firstPassTextureOut = null;
}
if(firstPassDepthRenderBuffer != null) {
GLES20.glDeleteRenderbuffers(1, firstPassDepthRenderBuffer, 0);
firstPassDepthRenderBuffer = null;
}
firstPassFrameBuffer = new int[1];
firstPassTextureOut = new int[1];
firstPassDepthRenderBuffer = new int[1];
GLES20.glGenFramebuffers(1, firstPassFrameBuffer, 0);
GLES20.glGenRenderbuffers(1, firstPassDepthRenderBuffer, 0);
GLES20.glGenTextures(1, firstPassTextureOut, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, firstPassFrameBuffer[0]);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, firstPassTextureOut[0]);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, getWidth(), getHeight(), 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, null);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, firstPassTextureOut[0], 0);
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, firstPassDepthRenderBuffer[0]);
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, getWidth(), getHeight());
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, firstPassDepthRenderBuffer[0]);
int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException(this+": Failed to set up render buffer with status "+status+" and error "+GLES20.glGetError());
}
}
}