Update all filters with onPreDraw

pull/535/head
Mattia Iavarone 6 years ago
parent c4118ab3f9
commit fce6597364
  1. 113
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/SharpnessFilter.java
  2. 77
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/TemperatureFilter.java
  3. 89
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/TintFilter.java
  4. 132
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/VignetteFilter.java

@ -1,17 +1,49 @@
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;
/** /**
* Sharpens the input frames. * Sharpens the input frames.
*/ */
public class SharpnessFilter extends BaseFilter { public class SharpnessFilter 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 float stepsizeX;\n"
+ "uniform float stepsizeY;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n"
+ " vec2 coord;\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " coord.x = vTextureCoord.x - 0.5 * stepsizeX;\n"
+ " coord.y = vTextureCoord.y - stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " coord.x = vTextureCoord.x - stepsizeX;\n"
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " coord.x = vTextureCoord.x + stepsizeX;\n"
+ " coord.y = vTextureCoord.y - 0.5 * stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " coord.x = vTextureCoord.x + stepsizeX;\n"
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n"
+ "}\n";
private float scale = 0.5f; private float scale = 0.5f;
private int mOutputWidth = 1; private int width = 1;
private int mOutputHeight = 1; private int height = 1;
private int scaleLocation = -1;
private int stepSizeXLocation = -1;
private int stepSizeYLocation = -1;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public SharpnessFilter() { } public SharpnessFilter() { }
@ -19,8 +51,8 @@ public class SharpnessFilter extends BaseFilter {
@Override @Override
public void setSize(int width, int height) { public void setSize(int width, int height) {
super.setSize(width, height); super.setSize(width, height);
mOutputWidth = width; this.width = width;
mOutputHeight = height; this.height = height;
} }
/** /**
@ -48,50 +80,45 @@ public class SharpnessFilter extends BaseFilter {
return scale; return scale;
} }
@Override
protected BaseFilter onCopy() {
SharpnessFilter filter = new SharpnessFilter();
filter.setSharpness(getSharpness());
return filter;
}
@NonNull @NonNull
@Override @Override
public String getFragmentShader() { public String getFragmentShader() {
String stepsizeXString = "stepsizeX = " + 1.0f / mOutputWidth + ";\n"; return FRAGMENT_SHADER;
String stepsizeYString = "stepsizeY = " + 1.0f / mOutputHeight + ";\n"; }
String scaleString = "scale = " + scale + ";\n";
return "#extension GL_OES_EGL_image_external : require\n" @Override
+ "precision mediump float;\n" public void onCreate(int programHandle) {
+ "uniform samplerExternalOES sTexture;\n" super.onCreate(programHandle);
+ " float scale;\n" scaleLocation = GLES20.glGetUniformLocation(programHandle, "scale");
+ " float stepsizeX;\n" GlUtils.checkLocation(scaleLocation, "scale");
+ " float stepsizeY;\n" stepSizeXLocation = GLES20.glGetUniformLocation(programHandle, "stepsizeX");
+ "varying vec2 vTextureCoord;\n" GlUtils.checkLocation(stepSizeXLocation, "stepsizeX");
+ "void main() {\n" stepSizeYLocation = GLES20.glGetUniformLocation(programHandle, "stepsizeY");
// Parameters that were created above GlUtils.checkLocation(stepSizeYLocation, "stepsizeY");
+ stepsizeXString }
+ stepsizeYString
+ scaleString
+ " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n"
+ " vec2 coord;\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " coord.x = vTextureCoord.x - 0.5 * stepsizeX;\n"
+ " coord.y = vTextureCoord.y - stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " coord.x = vTextureCoord.x - stepsizeX;\n"
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " coord.x = vTextureCoord.x + stepsizeX;\n"
+ " coord.y = vTextureCoord.y - 0.5 * stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " coord.x = vTextureCoord.x + stepsizeX;\n"
+ " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ " gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n"
+ "}\n";
@Override
public void onDestroy() {
super.onDestroy();
scaleLocation = -1;
stepSizeXLocation = -1;
stepSizeYLocation = -1;
} }
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
GLES20.glUniform1f(scaleLocation, scale);
GlUtils.checkError("glUniform1f");
GLES20.glUniform1f(stepSizeXLocation, 1.0F / width);
GlUtils.checkError("glUniform1f");
GLES20.glUniform1f(stepSizeYLocation, 1.0F / height);
GlUtils.checkError("glUniform1f");
}
@Override
protected BaseFilter onCopy() {
SharpnessFilter filter = new SharpnessFilter();
filter.setSharpness(getSharpness());
return filter;
}
} }

@ -1,15 +1,39 @@
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 temperature. * Adjusts color temperature.
*/ */
public class TemperatureFilter extends BaseFilter { public class TemperatureFilter 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"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " vec3 new_color = color.rgb;\n"
+ " new_color.r = color.r + color.r * ( 1.0 - color.r) * scale;\n"
+ " new_color.b = color.b - color.b * ( 1.0 - color.b) * scale;\n"
+ " if (scale > 0.0) { \n"
+ " new_color.g = color.g + color.g * ( 1.0 - color.g) * scale * 0.25;\n"
+ " }\n"
+ " float max_value = max(new_color.r, max(new_color.g, new_color.b));\n"
+ " if (max_value > 1.0) { \n"
+ " new_color /= max_value;\n"
+ " } \n"
+ " gl_FragColor = vec4(new_color, color.a);\n"
+ "}\n";
private float scale = 0f; private float scale = 0f;
private int scaleLocation = -1;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public TemperatureFilter() { } public TemperatureFilter() { }
@ -40,37 +64,36 @@ public class TemperatureFilter extends BaseFilter {
return scale; return scale;
} }
@NonNull
@Override @Override
protected BaseFilter onCopy() { public String getFragmentShader() {
TemperatureFilter filter = new TemperatureFilter(); return FRAGMENT_SHADER;
filter.setTemperature(getTemperature());
return filter;
} }
@NonNull
@Override @Override
public String getFragmentShader() { public void onCreate(int programHandle) {
String scaleString = "scale = " + (2.0f * scale - 1.0f) + ";\n"; super.onCreate(programHandle);
return "#extension GL_OES_EGL_image_external : require\n" scaleLocation = GLES20.glGetUniformLocation(programHandle, "scale");
+ "precision mediump float;\n" GlUtils.checkLocation(scaleLocation, "scale");
+ "uniform samplerExternalOES sTexture;\n" }
+ "float scale;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n" // Parameters that were created above
+ scaleString
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " vec3 new_color = color.rgb;\n"
+ " new_color.r = color.r + color.r * ( 1.0 - color.r) * scale;\n"
+ " new_color.b = color.b - color.b * ( 1.0 - color.b) * scale;\n"
+ " if (scale > 0.0) { \n"
+ " new_color.g = color.g + color.g * ( 1.0 - color.g) * scale * 0.25;\n"
+ " }\n"
+ " float max_value = max(new_color.r, max(new_color.g, new_color.b));\n"
+ " if (max_value > 1.0) { \n"
+ " new_color /= max_value;\n"
+ " } \n"
+ " gl_FragColor = vec4(new_color, color.a);\n"
+ "}\n";
@Override
public void onDestroy() {
super.onDestroy();
scaleLocation = -1;
}
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
GLES20.glUniform1f(scaleLocation, (2.0f * scale - 1.0f));
GlUtils.checkError("glUniform1f");
}
@Override
protected BaseFilter onCopy() {
TemperatureFilter filter = new TemperatureFilter();
filter.setTemperature(getTemperature());
return filter;
} }
} }

@ -1,18 +1,37 @@
package com.otaliastudios.cameraview.filters; package com.otaliastudios.cameraview.filters;
import android.graphics.Color; import android.graphics.Color;
import android.opengl.GLES20;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
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;
/** /**
* Tints the frames with specified color. * Tints the frames with specified color.
*/ */
public class TintFilter extends BaseFilter { public class TintFilter extends BaseFilter {
private int mTint = 0xFFFF0000;
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "uniform vec3 tint;\n"
+ "vec3 color_ratio;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " color_ratio[0] = " + 0.21f + ";\n"
+ " color_ratio[1] = " + 0.71f + ";\n"
+ " color_ratio[2] = " + 0.07f + ";\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " float avg_color = dot(color_ratio, color.rgb);\n"
+ " vec3 new_color = min(0.8 * avg_color + 0.2 * tint, 1.0);\n"
+ " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n";
private int tint = Color.RED;
private int tintLocation = -1;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public TintFilter() { } public TintFilter() { }
@ -23,7 +42,7 @@ public class TintFilter extends BaseFilter {
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public void setTint(@ColorInt int color) { public void setTint(@ColorInt int color) {
this.mTint = color; this.tint = color;
} }
/** /**
@ -35,50 +54,44 @@ public class TintFilter extends BaseFilter {
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@ColorInt @ColorInt
public int getTint() { public int getTint() {
return mTint; return tint;
} }
@NonNull
@Override @Override
protected BaseFilter onCopy() { public String getFragmentShader() {
TintFilter filter = new TintFilter(); return FRAGMENT_SHADER;
filter.setTint(getTint());
return filter;
} }
@NonNull
@Override @Override
public String getFragmentShader() { public void onCreate(int programHandle) {
float[] color_ratio = {0.21f, 0.71f, 0.07f}; super.onCreate(programHandle);
String[] color_ratioString = new String[3]; tintLocation = GLES20.glGetUniformLocation(programHandle, "tint");
color_ratioString[0] = "color_ratio[0] = " + color_ratio[0] + ";\n"; GlUtils.checkLocation(tintLocation, "tint");
color_ratioString[1] = "color_ratio[1] = " + color_ratio[1] + ";\n"; }
color_ratioString[2] = "color_ratio[2] = " + color_ratio[2] + ";\n";
float[] tint_color = {Color.red(mTint) / 255f, @Override
Color.green(mTint) / 255f, Color.blue(mTint) / 255f}; public void onDestroy() {
super.onDestroy();
tintLocation = -1;
}
String[] tintString = new String[3]; @Override
tintString[0] = "tint[0] = " + tint_color[0] + ";\n"; protected void onPreDraw(float[] transformMatrix) {
tintString[1] = "tint[1] = " + tint_color[1] + ";\n"; super.onPreDraw(transformMatrix);
tintString[2] = "tint[2] = " + tint_color[2] + ";\n"; float[] channels = new float[]{
Color.red(tint) / 255f,
Color.green(tint) / 255f,
Color.blue(tint) / 255f
};
GLES20.glUniform3fv(tintLocation, 1, channels, 0);
GlUtils.checkError("glUniform3fv");
}
return "#extension GL_OES_EGL_image_external : require\n" @Override
+ "precision mediump float;\n" protected BaseFilter onCopy() {
+ "uniform samplerExternalOES sTexture;\n" TintFilter filter = new TintFilter();
+ " vec3 tint;\n" filter.setTint(getTint());
+ " vec3 color_ratio;\n" return filter;
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
// Parameters that were created above
+ color_ratioString[0]
+ color_ratioString[1]
+ color_ratioString[2]
+ tintString[0]
+ tintString[1]
+ tintString[2]
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " float avg_color = dot(color_ratio, color.rgb);\n"
+ " vec3 new_color = min(0.8 * avg_color + 0.2 * tint, 1.0);\n"
+ " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n";
} }
} }

@ -1,8 +1,11 @@
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;
/** /**
@ -10,10 +13,32 @@ import com.otaliastudios.cameraview.filter.BaseFilter;
*/ */
public class VignetteFilter extends BaseFilter { public class VignetteFilter 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 range;\n"
+ "uniform float inv_max_dist;\n"
+ "uniform float shade;\n"
+ "uniform vec2 scale;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " const float slope = 20.0;\n"
+ " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n"
+ " float dist = length(coord * scale);\n"
+ " float lumen = shade / (1.0 + exp((dist * inv_max_dist - range) * slope)) + (1.0 - shade);\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " gl_FragColor = vec4(color.rgb * lumen, color.a);\n"
+ "}\n";
private float mScale = 0.85f; private float mScale = 0.85f;
private float mShade = 0.5f; private float mShade = 0.5f;
private int mOutputWidth = 1; private int mWidth = 1;
private int mOutputHeight = 1; private int mHeight = 1;
private int mRangeLocation = -1;
private int mMaxDistLocation = -1;
private int mShadeLocation = -1;
private int mScaleLocation = -1;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public VignetteFilter() { } public VignetteFilter() { }
@ -21,8 +46,8 @@ public class VignetteFilter extends BaseFilter {
@Override @Override
public void setSize(int width, int height) { public void setSize(int width, int height) {
super.setSize(width, height); super.setSize(width, height);
mOutputWidth = width; mWidth = width;
mOutputHeight = height; mHeight = height;
} }
/** /**
@ -31,11 +56,9 @@ public class VignetteFilter extends BaseFilter {
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public void setVignetteScale(float scale) { public void setVignetteScale(float scale) {
if (scale < 0.0f) if (scale < 0.0f) scale = 0.0f;
scale = 0.0f; if (scale > 1.0f) scale = 1.0f;
else if (scale > 1.0f) mScale = scale;
scale = 1.0f;
this.mScale = scale;
} }
/** /**
@ -71,61 +94,68 @@ public class VignetteFilter extends BaseFilter {
return mShade; return mShade;
} }
@NonNull
@Override @Override
protected BaseFilter onCopy() { public String getFragmentShader() {
VignetteFilter filter = new VignetteFilter(); return FRAGMENT_SHADER;
filter.setVignetteScale(getVignetteScale());
filter.setVignetteShade(getVignetteShade());
return filter;
} }
@NonNull
@Override @Override
public String getFragmentShader() { public void onCreate(int programHandle) {
super.onCreate(programHandle);
mRangeLocation = GLES20.glGetUniformLocation(programHandle, "range");
GlUtils.checkLocation(mRangeLocation, "range");
mMaxDistLocation = GLES20.glGetUniformLocation(programHandle, "inv_max_dist");
GlUtils.checkLocation(mMaxDistLocation, "inv_max_dist");
mShadeLocation = GLES20.glGetUniformLocation(programHandle, "shade");
GlUtils.checkLocation(mShadeLocation, "shade");
mScaleLocation = GLES20.glGetUniformLocation(programHandle, "scale");
GlUtils.checkLocation(mScaleLocation, "scale");
}
@Override
public void onDestroy() {
super.onDestroy();
mRangeLocation = -1;
mMaxDistLocation = -1;
mShadeLocation = -1;
mScaleLocation = -1;
}
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
float[] scale = new float[2]; float[] scale = new float[2];
if (mOutputWidth > mOutputHeight) { if (mWidth > mHeight) {
scale[0] = 1f; scale[0] = 1f;
scale[1] = ((float) mOutputHeight) / mOutputWidth; scale[1] = ((float) mHeight) / mWidth;
} else { } else {
scale[0] = ((float) mOutputWidth) / mOutputHeight; scale[0] = ((float) mWidth) / mHeight;
scale[1] = 1f; scale[1] = 1f;
} }
float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] GLES20.glUniform2fv(mScaleLocation, 1, scale, 0);
* scale[1])) * 0.5f; GlUtils.checkError("glUniform2fv");
String[] scaleString = new String[2]; float maxDist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] * scale[1])) * 0.5f;
scaleString[0] = "scale[0] = " + scale[0] + ";\n"; GLES20.glUniform1f(mMaxDistLocation, 1F / maxDist);
scaleString[1] = "scale[1] = " + scale[1] + ";\n"; GlUtils.checkError("glUniform1f");
String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n";
String shadeString = "shade = " + mShade + ";\n"; GLES20.glUniform1f(mShadeLocation, mShade);
GlUtils.checkError("glUniform1f");
// The 'range' is between 1.3 to 0.6. When scale is zero then range is 1.3 // The 'range' is between 1.3 to 0.6. When scale is zero then range is 1.3
// which means no vignette at all because the luminousity difference is // which means no vignette at all because the luminousity difference is
// less than 1/256 and will cause nothing. // less than 1/256 and will cause nothing.
String rangeString = "range = " float range = (1.30f - (float) Math.sqrt(mScale) * 0.7f);
+ (1.30f - (float) Math.sqrt(mScale) * 0.7f) + ";\n"; GLES20.glUniform1f(mRangeLocation, range);
GlUtils.checkError("glUniform1f");
return "#extension GL_OES_EGL_image_external : require\n" }
+ "precision mediump float;\n"
+ "uniform samplerExternalOES sTexture;\n" @Override
+ " float range;\n" protected BaseFilter onCopy() {
+ " float inv_max_dist;\n" VignetteFilter filter = new VignetteFilter();
+ " float shade;\n" filter.setVignetteScale(getVignetteScale());
+ " vec2 scale;\n" filter.setVignetteShade(getVignetteShade());
+ "varying vec2 vTextureCoord;\n" return filter;
+ "void main() {\n"
// Parameters that were created above
+ scaleString[0]
+ scaleString[1]
+ inv_max_distString
+ shadeString
+ rangeString
+ " const float slope = 20.0;\n"
+ " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n"
+ " float dist = length(coord * scale);\n"
+ " float lumen = shade / (1.0 + exp((dist * inv_max_dist - range) * slope)) + (1.0 - shade);\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " gl_FragColor = vec4(color.rgb * lumen, color.a);\n"
+ "}\n";
} }
} }

Loading…
Cancel
Save