From fa6dfa1f2d471e0cabf2859faf302f45f78ee173 Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Tue, 6 Aug 2019 12:53:32 +0200 Subject: [PATCH] Update DuotoneFilter with onPreDraw --- .../cameraview/filters/DocumentaryFilter.java | 84 +++++++------- .../cameraview/filters/DuotoneFilter.java | 103 ++++++++++-------- 2 files changed, 103 insertions(+), 84 deletions(-) diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java index 9a736a83..c4a1532f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java @@ -14,7 +14,48 @@ import java.util.Random; */ public class DocumentaryFilter extends BaseFilter { - private final Random mRandom = new Random(); + private final static Random RANDOM = new Random(); + private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "uniform samplerExternalOES sTexture;\n" + + "vec2 seed;\n" + + "float stepsize;\n" + + "uniform float inv_max_dist;\n" + + "uniform vec2 scale;\n" + + "varying vec2 vTextureCoord;\n" + + "float rand(vec2 loc) {\n" + + " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" + + " float theta2 = dot(loc, vec2(12.0, 78.0));\n" + + " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" + + + // keep value of part1 in range: (2^-14 to 2^14). + " float temp = mod(197.0 * value, 1.0) + value;\n" + + " float part1 = mod(220.0 * temp, 1.0) + temp;\n" + + " float part2 = value * 0.5453;\n" + + " float part3 = cos(theta1 + theta2) * 0.43758;\n" + + " return fract(part1 + part2 + part3);\n" + + "}\n" + + "void main() {\n" + + " seed[0] = " + RANDOM.nextFloat() + ";\n" + + " seed[1] = " + RANDOM.nextFloat() + ";\n" + + " stepsize = " + 1.0f / 255.0f + ";\n" + + // black white + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " float dither = rand(vTextureCoord + seed);\n" + + " vec3 xform = clamp(2.0 * color.rgb, 0.0, 1.0);\n" + + " vec3 temp = clamp(2.0 * (color.rgb + stepsize), 0.0, 1.0);\n" + + " vec3 new_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" + // grayscale + + " float gray = dot(new_color, vec3(0.299, 0.587, 0.114));\n" + + " new_color = vec3(gray, gray, gray);\n" + // vignette + + " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n" + + " float dist = length(coord * scale);\n" + + " float lumen = 0.85 / (1.0 + exp((dist * inv_max_dist - 0.83) * 20.0)) + 0.15;\n" + + " gl_FragColor = vec4(new_color * lumen, color.a);\n" + + "}\n"; + private int mWidth = 1; private int mHeight = 1; private int mScaleLocation = -1; @@ -32,46 +73,7 @@ public class DocumentaryFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" - + "vec2 seed;\n" - + "float stepsize;\n" - + "uniform float inv_max_dist;\n" - + "uniform vec2 scale;\n" - + "varying vec2 vTextureCoord;\n" - + "float rand(vec2 loc) {\n" - + " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" - + " float theta2 = dot(loc, vec2(12.0, 78.0));\n" - + " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" - + - // keep value of part1 in range: (2^-14 to 2^14). - " float temp = mod(197.0 * value, 1.0) + value;\n" - + " float part1 = mod(220.0 * temp, 1.0) + temp;\n" - + " float part2 = value * 0.5453;\n" - + " float part3 = cos(theta1 + theta2) * 0.43758;\n" - + " return fract(part1 + part2 + part3);\n" - + "}\n" - + "void main() {\n" - + " seed[0] = " + mRandom.nextFloat() + ";\n" - + " seed[1] = " + mRandom.nextFloat() + ";\n" - + " stepsize = " + 1.0f / 255.0f + ";\n" - - // black white - + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " float dither = rand(vTextureCoord + seed);\n" - + " vec3 xform = clamp(2.0 * color.rgb, 0.0, 1.0);\n" - + " vec3 temp = clamp(2.0 * (color.rgb + stepsize), 0.0, 1.0);\n" - + " vec3 new_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" - // grayscale - + " float gray = dot(new_color, vec3(0.299, 0.587, 0.114));\n" - + " new_color = vec3(gray, gray, gray);\n" - // vignette - + " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n" - + " float dist = length(coord * scale);\n" - + " float lumen = 0.85 / (1.0 + exp((dist * inv_max_dist - 0.83) * 20.0)) + 0.15;\n" - + " gl_FragColor = vec4(new_color * lumen, color.a);\n" - + "}\n"; + return FRAGMENT_SHADER; } @Override diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DuotoneFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DuotoneFilter.java index c20b4823..7617cd6d 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DuotoneFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DuotoneFilter.java @@ -1,20 +1,37 @@ package com.otaliastudios.cameraview.filters; import android.graphics.Color; +import android.opengl.GLES20; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import com.otaliastudios.cameraview.filter.BaseFilter; +import com.otaliastudios.cameraview.internal.GlUtils; /** * Representation of input frames using only two color tones. */ public class DuotoneFilter 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 vec3 first;\n" + + "uniform vec3 second;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " float energy = (color.r + color.g + color.b) * 0.3333;\n" + + " vec3 new_color = (1.0 - energy) * first + energy * second;\n" + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + + "}\n"; + // Default values private int mFirstColor = Color.MAGENTA; private int mSecondColor = Color.YELLOW; + private int mFirstColorLocation = -1; + private int mSecondColorLocation = -1; @SuppressWarnings("WeakerAccess") public DuotoneFilter() { } @@ -58,7 +75,7 @@ public class DuotoneFilter extends BaseFilter { * @see #setFirstColor(int) * @return first */ - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "WeakerAccess"}) @ColorInt public int getFirstColor() { return mFirstColor; @@ -70,57 +87,57 @@ public class DuotoneFilter extends BaseFilter { * @see #setSecondColor(int) * @return second */ - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "WeakerAccess"}) @ColorInt public int getSecondColor() { return mSecondColor; } - @Override - protected BaseFilter onCopy() { - DuotoneFilter filter = new DuotoneFilter(); - filter.setColors(mFirstColor, mSecondColor); - return filter; - } @NonNull @Override public String getFragmentShader() { - float[] first = {Color.red(mFirstColor) / 255f, - Color.green(mFirstColor) / 255f, Color.blue(mFirstColor) / 255f}; - float[] second = {Color.red(mSecondColor) / 255f, + return FRAGMENT_SHADER; + } + + @Override + public void onCreate(int programHandle) { + super.onCreate(programHandle); + mFirstColorLocation = GLES20.glGetUniformLocation(programHandle, "first"); + GlUtils.checkLocation(mFirstColorLocation, "first"); + mSecondColorLocation = GLES20.glGetUniformLocation(programHandle, "second"); + GlUtils.checkLocation(mSecondColorLocation, "second"); + } + + @Override + protected void onPreDraw(float[] transformMatrix) { + super.onPreDraw(transformMatrix); + float[] first = new float[]{ + Color.red(mFirstColor) / 255f, + Color.green(mFirstColor) / 255f, + Color.blue(mFirstColor) / 255f + }; + float[] second = new float[]{ + Color.red(mSecondColor) / 255f, Color.green(mSecondColor) / 255f, - Color.blue(mSecondColor) / 255f}; - - String[] firstColorString = new String[3]; - String[] secondColorString = new String[3]; - - firstColorString[0] = "first[0] = " + first[0] + ";\n"; - firstColorString[1] = "first[1] = " + first[1] + ";\n"; - firstColorString[2] = "first[2] = " + first[2] + ";\n"; - - secondColorString[0] = "second[0] = " + second[0] + ";\n"; - secondColorString[1] = "second[1] = " + second[1] + ";\n"; - secondColorString[2] = "second[2] = " + second[2] + ";\n"; - - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" - + "vec3 first;\n" - + "vec3 second;\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - // Parameters that were created above - + firstColorString[0] - + firstColorString[1] - + firstColorString[2] - + secondColorString[0] - + secondColorString[1] - + secondColorString[2] - + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " float energy = (color.r + color.g + color.b) * 0.3333;\n" - + " vec3 new_color = (1.0 - energy) * first + energy * second;\n" - + " gl_FragColor = vec4(new_color.rgb, color.a);\n" - + "}\n"; + Color.blue(mSecondColor) / 255f + }; + GLES20.glUniform3fv(mFirstColorLocation, 1, first, 0); + GLES20.glUniform3fv(mSecondColorLocation, 1, second, 0); + GlUtils.checkError("glUniform3fv"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mFirstColorLocation = -1; + mSecondColorLocation = -1; + } + + @Override + protected BaseFilter onCopy() { + DuotoneFilter filter = new DuotoneFilter(); + filter.setColors(getFirstColor(), getSecondColor()); + return filter; } }