|
|
@ -1,15 +1,45 @@ |
|
|
|
package com.otaliastudios.cameraview.filters; |
|
|
|
package com.otaliastudios.cameraview.filters; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.opengl.GLES20; |
|
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull; |
|
|
|
import androidx.annotation.NonNull; |
|
|
|
|
|
|
|
|
|
|
|
import com.otaliastudios.cameraview.filter.BaseFilter; |
|
|
|
import com.otaliastudios.cameraview.filter.BaseFilter; |
|
|
|
|
|
|
|
import com.otaliastudios.cameraview.internal.GlUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Adjusts color saturation. |
|
|
|
* Adjusts color saturation. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class SaturationFilter extends BaseFilter { |
|
|
|
public class SaturationFilter extends BaseFilter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" |
|
|
|
|
|
|
|
+ "precision mediump float;\n" |
|
|
|
|
|
|
|
+ "uniform samplerExternalOES sTexture;\n" |
|
|
|
|
|
|
|
+ "uniform float scale;\n" |
|
|
|
|
|
|
|
+ "uniform vec3 exponents;\n" |
|
|
|
|
|
|
|
+ "float shift;\n" |
|
|
|
|
|
|
|
+ "vec3 weights;\n" |
|
|
|
|
|
|
|
+ "varying vec2 vTextureCoord;\n" |
|
|
|
|
|
|
|
+ "void main() {\n" |
|
|
|
|
|
|
|
+ " weights[0] = " + 2f / 8f + ";\n" |
|
|
|
|
|
|
|
+ " weights[1] = " + 5f / 8f + ";\n" |
|
|
|
|
|
|
|
+ " weights[2] = " + 1f / 8f + ";\n" |
|
|
|
|
|
|
|
+ " shift = " + 1.0f / 255.0f + ";\n" |
|
|
|
|
|
|
|
+ " vec4 oldcolor = texture2D(sTexture, vTextureCoord);\n" |
|
|
|
|
|
|
|
+ " float kv = dot(oldcolor.rgb, weights) + shift;\n" |
|
|
|
|
|
|
|
+ " vec3 new_color = scale * oldcolor.rgb + (1.0 - scale) * kv;\n" |
|
|
|
|
|
|
|
+ " gl_FragColor = vec4(new_color, oldcolor.a);\n" |
|
|
|
|
|
|
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
|
|
|
|
|
|
|
+ " float de = dot(color.rgb, weights);\n" |
|
|
|
|
|
|
|
+ " float inv_de = 1.0 / de;\n" |
|
|
|
|
|
|
|
+ " vec3 verynew_color = de * pow(color.rgb * inv_de, exponents);\n" |
|
|
|
|
|
|
|
+ " float max_color = max(max(max(verynew_color.r, verynew_color.g), verynew_color.b), 1.0);\n" |
|
|
|
|
|
|
|
+ " gl_FragColor = gl_FragColor+vec4(verynew_color / max_color, color.a);\n" |
|
|
|
|
|
|
|
+ "}\n"; |
|
|
|
|
|
|
|
|
|
|
|
private float scale = 1.0f; |
|
|
|
private float scale = 1.0f; |
|
|
|
|
|
|
|
private int scaleLocation = -1; |
|
|
|
|
|
|
|
private int exponentsLocation = -1; |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("WeakerAccess") |
|
|
|
@SuppressWarnings("WeakerAccess") |
|
|
|
public SaturationFilter() { } |
|
|
|
public SaturationFilter() { } |
|
|
@ -45,75 +75,52 @@ public class SaturationFilter extends BaseFilter { |
|
|
|
return (scale + 1.0f) / 2.0f; |
|
|
|
return (scale + 1.0f) / 2.0f; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@NonNull |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected BaseFilter onCopy() { |
|
|
|
public String getFragmentShader() { |
|
|
|
SaturationFilter filter = new SaturationFilter(); |
|
|
|
return FRAGMENT_SHADER; |
|
|
|
filter.setSaturation(getSaturation()); |
|
|
|
|
|
|
|
return filter; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@NonNull |
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public String getFragmentShader() { |
|
|
|
public void onCreate(int programHandle) { |
|
|
|
float shift = 1.0f / 255.0f; |
|
|
|
super.onCreate(programHandle); |
|
|
|
float[] weights = {2f / 8f, 5f / 8f, 1f / 8f}; |
|
|
|
scaleLocation = GLES20.glGetUniformLocation(programHandle, "scale"); |
|
|
|
float[] exponents = new float[3]; |
|
|
|
GlUtils.checkLocation(scaleLocation, "scale"); |
|
|
|
|
|
|
|
exponentsLocation = GLES20.glGetUniformLocation(programHandle, "exponents"); |
|
|
|
|
|
|
|
GlUtils.checkLocation(exponentsLocation, "exponents"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String[] weightsString = new String[3]; |
|
|
|
@Override |
|
|
|
String[] exponentsString = new String[3]; |
|
|
|
public void onDestroy() { |
|
|
|
exponentsString[0] = ""; |
|
|
|
super.onDestroy(); |
|
|
|
exponentsString[1] = ""; |
|
|
|
scaleLocation = -1; |
|
|
|
exponentsString[2] = ""; |
|
|
|
exponentsLocation = -1; |
|
|
|
String scaleString = ""; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void onPreDraw(float[] transformMatrix) { |
|
|
|
|
|
|
|
super.onPreDraw(transformMatrix); |
|
|
|
if (scale > 0.0f) { |
|
|
|
if (scale > 0.0f) { |
|
|
|
exponents[0] = (0.9f * scale) + 1.0f; |
|
|
|
GLES20.glUniform1f(scaleLocation, 0F); |
|
|
|
exponents[1] = (2.1f * scale) + 1.0f; |
|
|
|
GlUtils.checkError("glUniform1f"); |
|
|
|
exponents[2] = (2.7f * scale) + 1.0f; |
|
|
|
GLES20.glUniform3f(exponentsLocation, |
|
|
|
exponentsString[0] = "exponents[0] = " + exponents[0] + ";\n"; |
|
|
|
(0.9f * scale) + 1.0f, |
|
|
|
exponentsString[1] = "exponents[1] = " + exponents[1] + ";\n"; |
|
|
|
(2.1f * scale) + 1.0f, |
|
|
|
exponentsString[2] = "exponents[2] = " + exponents[2] + ";\n"; |
|
|
|
(2.7f * scale) + 1.0f |
|
|
|
} else |
|
|
|
); |
|
|
|
scaleString = "scale = " + (1.0f + scale) + ";\n"; |
|
|
|
GlUtils.checkError("glUniform3f"); |
|
|
|
|
|
|
|
} else { |
|
|
|
weightsString[0] = "weights[0] = " + weights[0] + ";\n"; |
|
|
|
GLES20.glUniform1f(scaleLocation, 1.0F + scale); |
|
|
|
weightsString[1] = "weights[1] = " + weights[1] + ";\n"; |
|
|
|
GlUtils.checkError("glUniform1f"); |
|
|
|
weightsString[2] = "weights[2] = " + weights[2] + ";\n"; |
|
|
|
GLES20.glUniform3f(exponentsLocation, 0F, 0F, 0F); |
|
|
|
String shiftString = "shift = " + shift + ";\n"; |
|
|
|
GlUtils.checkError("glUniform3f"); |
|
|
|
|
|
|
|
} |
|
|
|
return "#extension GL_OES_EGL_image_external : require\n" |
|
|
|
|
|
|
|
+ "precision mediump float;\n" |
|
|
|
|
|
|
|
+ "uniform samplerExternalOES sTexture;\n" |
|
|
|
|
|
|
|
+ "float scale;\n" |
|
|
|
|
|
|
|
+ "float shift;\n" |
|
|
|
|
|
|
|
+ "vec3 weights;\n" |
|
|
|
|
|
|
|
+ "vec3 exponents;\n" |
|
|
|
|
|
|
|
+ "varying vec2 vTextureCoord;\n" |
|
|
|
|
|
|
|
+ "void main() {\n" |
|
|
|
|
|
|
|
// Parameters that were created above
|
|
|
|
|
|
|
|
+ weightsString[0] |
|
|
|
|
|
|
|
+ weightsString[1] |
|
|
|
|
|
|
|
+ weightsString[2] |
|
|
|
|
|
|
|
+ shiftString |
|
|
|
|
|
|
|
+ scaleString |
|
|
|
|
|
|
|
+ " vec4 oldcolor = texture2D(sTexture, vTextureCoord);\n" |
|
|
|
|
|
|
|
+ " float kv = dot(oldcolor.rgb, weights) + shift;\n" |
|
|
|
|
|
|
|
+ " vec3 new_color = scale * oldcolor.rgb + (1.0 - scale) * kv;\n" |
|
|
|
|
|
|
|
+ " gl_FragColor= vec4(new_color, oldcolor.a);\n" |
|
|
|
|
|
|
|
// Parameters that were created above
|
|
|
|
|
|
|
|
+ weightsString[0] |
|
|
|
|
|
|
|
+ weightsString[1] |
|
|
|
|
|
|
|
+ weightsString[2] |
|
|
|
|
|
|
|
+ exponentsString[0] |
|
|
|
|
|
|
|
+ exponentsString[1] |
|
|
|
|
|
|
|
+ exponentsString[2] |
|
|
|
|
|
|
|
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n" |
|
|
|
|
|
|
|
+ " float de = dot(color.rgb, weights);\n" |
|
|
|
|
|
|
|
+ " float inv_de = 1.0 / de;\n" |
|
|
|
|
|
|
|
+ " vec3 verynew_color = de * pow(color.rgb * inv_de, exponents);\n" |
|
|
|
|
|
|
|
+ " float max_color = max(max(max(verynew_color.r, verynew_color.g), verynew_color.b), 1.0);\n" |
|
|
|
|
|
|
|
+ " gl_FragColor = gl_FragColor+vec4(verynew_color / max_color, color.a);\n" |
|
|
|
|
|
|
|
+ "}\n"; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected BaseFilter onCopy() { |
|
|
|
|
|
|
|
SaturationFilter filter = new SaturationFilter(); |
|
|
|
|
|
|
|
filter.setSaturation(getSaturation()); |
|
|
|
|
|
|
|
return filter; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|