package com.marshalchen.common.uimodule.imageprocessing.filter.processing;
import android.opengl.GLES20;
import com.marshalchen.common.uimodule.imageprocessing.filter.CompositeFilter;
import com.marshalchen.common.uimodule.imageprocessing.inputprocess.GLTextureOutputRenderer;
/**
* A simulated tilt shift lens effect
* blurSize: A multiplier for the size of the out-of-focus blur, ranging from 0.0 on up
* topFocusLevel: The normalized location of the top of the in-focus area in the image, this value should be lower than bottomFocusLevel
* bottomFocusLevel: The normalized location of the bottom of the in-focus area in the image, this value should be higher than topFocusLevel
* focusFallOffRate: The rate at which the image gets blurry away from the in-focus region
* @author Chris Batt
*/
public class TiltShiftFilter extends CompositeFilter {
protected static final String UNIFORM_FOCUS_FALLOFF = "u_FocusFalloff";
protected static final String UNIFORM_TOP_FOCUS = "u_TopFocus";
protected static final String UNIFORM_BOTTOM_FOCUS = "u_BottomFocus";
private float focusFallOffRate;
private float topFocusLevel;
private float bottomFocusLevel;
private int focusFallOffRateHandle;
private int topFocusLevelHandle;
private int bottomFocusLevelHandle;
private GaussianBlurFilter blur;
public TiltShiftFilter(float blurSize, float topFocusLevel, float bottomFocusLevel, float focusFallOffRate) {
super(2);
this.topFocusLevel = topFocusLevel;
this.bottomFocusLevel = bottomFocusLevel;
this.focusFallOffRate = focusFallOffRate;
blur = new GaussianBlurFilter(blurSize);
blur.addTarget(this);
registerInitialFilter(blur);
registerTerminalFilter(blur);
}
@Override
protected String getFragmentShader() {
return
"precision mediump float;\n"
+"uniform sampler2D "+UNIFORM_TEXTURE0+";\n"
+"uniform sampler2D "+UNIFORM_TEXTUREBASE+1+";\n"
+"varying vec2 "+VARYING_TEXCOORD+";\n"
+"uniform float "+UNIFORM_FOCUS_FALLOFF+";\n"
+"uniform float "+UNIFORM_TOP_FOCUS+";\n"
+"uniform float "+UNIFORM_BOTTOM_FOCUS+";\n"
+"void main(){\n"
+" vec4 sharpImageColor = texture2D("+UNIFORM_TEXTURE0+", "+VARYING_TEXCOORD+");\n"
+" vec4 blurredImageColor = texture2D("+UNIFORM_TEXTUREBASE+1+", "+VARYING_TEXCOORD+");\n"
+" float blurIntensity = 1.0 - smoothstep("+UNIFORM_TOP_FOCUS+" - "+UNIFORM_FOCUS_FALLOFF+", "+UNIFORM_TOP_FOCUS+", "+VARYING_TEXCOORD+".y);\n"
+" blurIntensity += smoothstep("+UNIFORM_BOTTOM_FOCUS+", "+UNIFORM_BOTTOM_FOCUS+" + "+UNIFORM_FOCUS_FALLOFF+", "+VARYING_TEXCOORD+".y);\n"
+" gl_FragColor = mix(sharpImageColor, blurredImageColor, blurIntensity);\n"
+"}\n";
}
@Override
protected void initShaderHandles() {
super.initShaderHandles();
focusFallOffRateHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_FOCUS_FALLOFF);
topFocusLevelHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_TOP_FOCUS);
bottomFocusLevelHandle = GLES20.glGetUniformLocation(programHandle, UNIFORM_BOTTOM_FOCUS);
}
@Override
public void newTextureReady(int texture, GLTextureOutputRenderer source, boolean newData) {
if(filterLocations.size() < 2 || !filterLocations.contains(source)) {
clearRegisteredFilterLocations();
registerFilterLocation(source, 0);
registerFilterLocation(blur, 1);
registerInputOutputFilter(source);
}
super.newTextureReady(texture, source, newData);
}
@Override
protected void passShaderValues() {
super.passShaderValues();
GLES20.glUniform1f(focusFallOffRateHandle, focusFallOffRate);
GLES20.glUniform1f(topFocusLevelHandle, topFocusLevel);
GLES20.glUniform1f(bottomFocusLevelHandle, bottomFocusLevel);
}
}