package com.marshalchen.common.uimodule.imageprocessing.filter.processing;
import com.marshalchen.common.uimodule.imageprocessing.filter.MultiPixelRenderer;
import android.opengl.GLES20;
/**
* A basic convolution filter implementation of the MultiPixelRenderer.
* This class works for convolution filters of any size; however, if the size is an even number,
* the filter will favour the bottom right.
* @author Chris Batt
*/
public class ConvolutionFilter extends MultiPixelRenderer {
protected static final String UNIFORM_FILTER = "u_Filter";
private float[] filter;
private int filterHandle;
private String filterBody;
private int filterSize;
/**
* @param filter
* The convolution filter that should be applied to each pixel in the input texture.
* @param filterWidth
* The width of the convolution filter.
* @param filterHeight
* The height of the convolution filter.
*/
public ConvolutionFilter(float[] filter, int filterWidth, int filterHeight) {
super();
this.filter = filter;
filterBody = createFilterBody(filterWidth, filterHeight);
filterSize = filterWidth*filterHeight;
}
private String createFilterBody(int width, int height) {
String filterBody = " vec3 color = ";
int middleWidth = (width-1)/2;
int middleHeight = (height-1)/2;
for(int j = 0; j < height; j++) {
for(int i = 0; i < width; i++) {
filterBody += " texture2D("+UNIFORM_TEXTURE0+","+VARYING_TEXCOORD+" + widthStep * " + (i-middleWidth) + ".0 + heightStep * " + (j-middleHeight) + ".0).rgb * "+UNIFORM_FILTER+"[" + (j*width+i) + "]";
if(i == width-1 && j == height-1) {
filterBody += ";\n";
} else {
filterBody += " +\n";
}
}
}
filterBody += " gl_FragColor = vec4(color, 1);\n";//texture2D("+UNIFORM_TEXTURE0+","+VARYING_TEXCOORD+").a);\n";
return filterBody;
}
private int getFilterSize() {
return filterSize;
}
@Override
protected String getFragmentShader() {
return
"precision mediump float;\n"
+"uniform sampler2D "+UNIFORM_TEXTURE0+";\n"
+"uniform float "+UNIFORM_TEXELWIDTH+";\n"
+"uniform float "+UNIFORM_TEXELHEIGHT+";\n"
+"uniform float "+UNIFORM_FILTER+"["+getFilterSize()+"];"
+"varying vec2 "+VARYING_TEXCOORD+";\n"
+"void main(){\n"
+" vec2 widthStep = vec2("+UNIFORM_TEXELWIDTH+", 0);"
+" vec2 heightStep = vec2(0, "+UNIFORM_TEXELHEIGHT+");"
+ filterBody
+"}\n";
}
@Override
protected void initShaderHandles() {
super.initShaderHandles();
filterHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_FILTER);
}
@Override
protected void passShaderValues() {
super.passShaderValues();
GLES20.glUniform1fv(filterHandle, filterSize, filter, 0);
}
}