From 5543b93545f1a276d4bb6c3e1f59bfb7668a19b8 Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Tue, 6 Aug 2019 12:44:29 +0200 Subject: [PATCH] Update first 6 filters with onPreDraw --- .../otaliastudios/cameraview/CameraView.java | 30 +++- .../cameraview/filter/BaseFilter.java | 4 +- .../cameraview/filter/Filter.java | 4 +- .../cameraview/filters/AutoFixFilter.java | 128 +++++++++++------- .../filters/BlackAndWhiteFilter.java | 22 +-- .../cameraview/filters/BrightnessFilter.java | 58 +++++--- .../cameraview/filters/ContrastFilter.java | 60 +++++--- .../filters/CrossProcessFilter.java | 69 +++++----- .../cameraview/filters/DocumentaryFilter.java | 96 +++++++------ .../cameraview/internal/egl/EglViewport.java | 2 +- .../cameraview/demo/CameraActivity.java | 7 + 11 files changed, 303 insertions(+), 177 deletions(-) diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index 979d2630..bf7fb76e 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -2157,6 +2157,9 @@ public class CameraView extends FrameLayout implements LifecycleObserver { * Use {@link NoFilter} to clear the existing filter, * and take a look at the {@link Filters} class for commonly used filters. * + * This method will throw an exception if the current preview does not support real-time filters. + * Make sure you use {@link Preview#GL_SURFACE} (the default). + * * @see Filters * @param filter a new filter */ @@ -2164,12 +2167,35 @@ public class CameraView extends FrameLayout implements LifecycleObserver { if (mCameraPreview == null) { mPendingFilter = filter; } else if (!(filter instanceof NoFilter) && !mExperimental) { - LOG.w("Filters are an experimental features and need the experimental flag set."); + throw new RuntimeException("Filters are an experimental features and need the experimental flag set."); } else if (mCameraPreview instanceof FilterCameraPreview) { ((FilterCameraPreview) mCameraPreview).setFilter(filter); } else { - LOG.w("setFilter() is supported only for GL_SURFACE. Preview:", mPreview); + throw new RuntimeException("Filters are only supported by the GL_SURFACE preview. Current:" + mPreview); + } + } + + /** + * Returns the current real-time filter applied to the camera preview. + * + * This method will throw an exception if the current preview does not support real-time filters. + * Make sure you use {@link Preview#GL_SURFACE} (the default). + * + * @see #setFilter(Filter) + * @return the current filter + */ + @NonNull + public Filter getFilter() { + if (!mExperimental) { + throw new RuntimeException("Filters are an experimental features and need the experimental flag set."); + } else if (mCameraPreview == null) { + return mPendingFilter; + } else if (mCameraPreview instanceof FilterCameraPreview) { + return ((FilterCameraPreview) mCameraPreview).getCurrentFilter(); + } else { + throw new RuntimeException("Filters are only supported by the GL_SURFACE preview. Current:" + mPreview); } + } //endregion diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filter/BaseFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filter/BaseFilter.java index ea9b453a..d4236249 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filter/BaseFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filter/BaseFilter.java @@ -116,6 +116,7 @@ public abstract class BaseFilter implements Filter { fragmentTextureCoordinateName); } + @SuppressWarnings("WeakerAccess") @NonNull protected String createDefaultFragmentShader() { return createDefaultFragmentShader(fragmentTextureCoordinateName); @@ -134,7 +135,7 @@ public abstract class BaseFilter implements Filter { } @Override - public void onDestroy(int programHandle) { + public void onDestroy() { vertexPositionLocation = -1; vertexTextureCoordinateLocation = -1; vertexModelViewProjectionMatrixLocation = -1; @@ -196,6 +197,7 @@ public abstract class BaseFilter implements Filter { GLES20.glDisableVertexAttribArray(vertexTextureCoordinateLocation); } + @NonNull @Override public final BaseFilter copy() { BaseFilter copy = onCopy(); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filter/Filter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filter/Filter.java index a3c6f35e..021d2679 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filter/Filter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filter/Filter.java @@ -52,9 +52,8 @@ public interface Filter { /** * The filter program is about to be destroyed. * - * @param programHandle handle */ - void onDestroy(int programHandle); + void onDestroy(); /** * Called to render the actual texture. The given transformation matrix @@ -78,5 +77,6 @@ public interface Filter { * * @return a clone */ + @NonNull Filter copy(); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/AutoFixFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/AutoFixFilter.java index 445d59da..c5b92b39 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/AutoFixFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/AutoFixFilter.java @@ -1,15 +1,65 @@ package com.otaliastudios.cameraview.filters; +import android.opengl.GLES20; + import androidx.annotation.NonNull; import com.otaliastudios.cameraview.filter.BaseFilter; +import com.otaliastudios.cameraview.internal.GlUtils; /** * Attempts to auto-fix the frames based on histogram equalization. */ public class AutoFixFilter extends BaseFilter { + private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "uniform samplerExternalOES tex_sampler_0;\n" + + "uniform samplerExternalOES tex_sampler_1;\n" + + "uniform samplerExternalOES tex_sampler_2;\n" + + "uniform float scale;\n" + + "float shift_scale;\n" + + "float hist_offset;\n" + + "float hist_scale;\n" + + "float density_offset;\n" + + "float density_scale;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " shift_scale = " + (1.0f / 256f) + ";\n" + + " hist_offset = " + (0.5f / 766f) + ";\n" + + " hist_scale = " + (765f / 766f) + ";\n" + + " density_offset = " + (0.5f / 1024f) + ";\n" + + " density_scale = " + (1023f / 1024f) + ";\n" + + " const vec3 weights = vec3(0.33333, 0.33333, 0.33333);\n" + + " vec4 color = texture2D(tex_sampler_0, vTextureCoord);\n" + + " float energy = dot(color.rgb, weights);\n" + + " float mask_value = energy - 0.5;\n" + + " float alpha;\n" + + " if (mask_value > 0.0) {\n" + + " alpha = (pow(2.0 * mask_value, 1.5) - 1.0) * scale + 1.0;\n" + + " } else { \n" + + " alpha = (pow(2.0 * mask_value, 2.0) - 1.0) * scale + 1.0;\n" + + " }\n" + + " float index = energy * hist_scale + hist_offset;\n" + + " vec4 temp = texture2D(tex_sampler_1, vec2(index, 0.5));\n" + + " float value = temp.g + temp.r * shift_scale;\n" + + " index = value * density_scale + density_offset;\n" + + " temp = texture2D(tex_sampler_2, vec2(index, 0.5));\n" + + " value = temp.g + temp.r * shift_scale;\n" + + " float dst_energy = energy * alpha + value * (1.0 - alpha);\n" + + " float max_energy = energy / max(color.r, max(color.g, color.b));\n" + + " if (dst_energy > max_energy) {\n" + + " dst_energy = max_energy;\n" + + " }\n" + + " if (energy == 0.0) {\n" + + " gl_FragColor = color;\n" + + " } else {\n" + + " gl_FragColor = vec4(color.rgb * dst_energy / energy, color.a);\n" + + " }\n" + + "}\n"; + private float scale = 1.0f; + private int scaleLocation = -1; @SuppressWarnings("WeakerAccess") public AutoFixFilter() { } @@ -36,61 +86,37 @@ public class AutoFixFilter extends BaseFilter { return scale; } + @NonNull + @Override + public String getFragmentShader() { + return FRAGMENT_SHADER; + } + + @Override + public void onCreate(int programHandle) { + super.onCreate(programHandle); + scaleLocation = GLES20.glGetUniformLocation(programHandle, "scale"); + GlUtils.checkLocation(scaleLocation, "scale"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + scaleLocation = -1; + } + + @Override + protected void onPreDraw(float[] transformMatrix) { + super.onPreDraw(transformMatrix); + GLES20.glUniform1f(scaleLocation, scale); + GlUtils.checkError("glUniform1f"); + } + + @Override protected BaseFilter onCopy() { AutoFixFilter filter = new AutoFixFilter(); filter.setScale(getScale()); return filter; } - - @NonNull - @Override - public String getFragmentShader() { - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "uniform samplerExternalOES tex_sampler_0;\n" - + "uniform samplerExternalOES tex_sampler_1;\n" - + "uniform samplerExternalOES tex_sampler_2;\n" - + "float scale;\n" - + "float shift_scale;\n" - + "float hist_offset;\n" - + "float hist_scale;\n" - + "float density_offset;\n" - + "float density_scale;\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - + " shift_scale = " + (1.0f / 256f) + ";\n" - + " hist_offset = " + (0.5f / 766f) + ";\n" - + " hist_scale = " + (765f / 766f) + ";\n" - + " density_offset = " + (0.5f / 1024f) + ";\n" - + " density_scale = " + (1023f / 1024f) + ";\n" - + " scale = " + scale + ";\n" - + " const vec3 weights = vec3(0.33333, 0.33333, 0.33333);\n" - + " vec4 color = texture2D(tex_sampler_0, vTextureCoord);\n" - + " float energy = dot(color.rgb, weights);\n" - + " float mask_value = energy - 0.5;\n" - + " float alpha;\n" - + " if (mask_value > 0.0) {\n" - + " alpha = (pow(2.0 * mask_value, 1.5) - 1.0) * scale + 1.0;\n" - + " } else { \n" - + " alpha = (pow(2.0 * mask_value, 2.0) - 1.0) * scale + 1.0;\n" - + " }\n" - + " float index = energy * hist_scale + hist_offset;\n" - + " vec4 temp = texture2D(tex_sampler_1, vec2(index, 0.5));\n" - + " float value = temp.g + temp.r * shift_scale;\n" - + " index = value * density_scale + density_offset;\n" - + " temp = texture2D(tex_sampler_2, vec2(index, 0.5));\n" - + " value = temp.g + temp.r * shift_scale;\n" - + " float dst_energy = energy * alpha + value * (1.0 - alpha);\n" - + " float max_energy = energy / max(color.r, max(color.g, color.b));\n" - + " if (dst_energy > max_energy) {\n" - + " dst_energy = max_energy;\n" - + " }\n" - + " if (energy == 0.0) {\n" - + " gl_FragColor = color;\n" - + " } else {\n" - + " gl_FragColor = vec4(color.rgb * dst_energy / energy, color.a);\n" - + " }\n" - + "}\n"; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BlackAndWhiteFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BlackAndWhiteFilter.java index 705522ab..4395e713 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BlackAndWhiteFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BlackAndWhiteFilter.java @@ -9,20 +9,22 @@ import com.otaliastudios.cameraview.filter.BaseFilter; */ public class BlackAndWhiteFilter extends BaseFilter { + private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "varying vec2 vTextureCoord;\n" + + "uniform samplerExternalOES sTexture;\n" + "void main() {\n" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " float colorR = (color.r + color.g + color.b) / 3.0;\n" + + " float colorG = (color.r + color.g + color.b) / 3.0;\n" + + " float colorB = (color.r + color.g + color.b) / 3.0;\n" + + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" + + "}\n"; + public BlackAndWhiteFilter() { } @NonNull @Override public String getFragmentShader() { - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "varying vec2 vTextureCoord;\n" - + "uniform samplerExternalOES sTexture;\n" + "void main() {\n" - + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " float colorR = (color.r + color.g + color.b) / 3.0;\n" - + " float colorG = (color.r + color.g + color.b) / 3.0;\n" - + " float colorB = (color.r + color.g + color.b) / 3.0;\n" - + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" - + "}\n"; + return FRAGMENT_SHADER; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BrightnessFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BrightnessFilter.java index ae9dc5ac..b3a04bc3 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BrightnessFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BrightnessFilter.java @@ -1,15 +1,30 @@ package com.otaliastudios.cameraview.filters; +import android.opengl.GLES20; + import androidx.annotation.NonNull; import com.otaliastudios.cameraview.filter.BaseFilter; +import com.otaliastudios.cameraview.internal.GlUtils; /** * Adjusts the brightness of the frames. */ public class BrightnessFilter 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 brightness;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " gl_FragColor = brightness * color;\n" + + "}\n"; + private float brightness = 2.0f; + private int brightnessLocation = -1; + @SuppressWarnings("WeakerAccess") public BrightnessFilter() { } @@ -44,26 +59,37 @@ public class BrightnessFilter extends BaseFilter { return brightness - 1.0f; } + @NonNull @Override - protected BaseFilter onCopy() { - BrightnessFilter filter = new BrightnessFilter(); - filter.setBrightness(getBrightness()); - return filter; + public String getFragmentShader() { + return FRAGMENT_SHADER; } - @NonNull @Override - public String getFragmentShader() { - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" - + "float brightness ;\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - + " brightness =" + brightness + ";\n" - + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " gl_FragColor = brightness * color;\n" - + "}\n"; + public void onCreate(int programHandle) { + super.onCreate(programHandle); + brightnessLocation = GLES20.glGetUniformLocation(programHandle, "brightness"); + GlUtils.checkLocation(brightnessLocation, "brightness"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + brightnessLocation = -1; + } + + @Override + protected void onPreDraw(float[] transformMatrix) { + super.onPreDraw(transformMatrix); + GLES20.glUniform1f(brightnessLocation, brightness); + GlUtils.checkError("glUniform1f"); } + + @Override + protected BaseFilter onCopy() { + BrightnessFilter filter = new BrightnessFilter(); + filter.setBrightness(getBrightness()); + return filter; + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/ContrastFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/ContrastFilter.java index 069f9898..801e6733 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/ContrastFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/ContrastFilter.java @@ -1,14 +1,32 @@ package com.otaliastudios.cameraview.filters; +import android.opengl.GLES20; + import androidx.annotation.NonNull; import com.otaliastudios.cameraview.filter.BaseFilter; +import com.otaliastudios.cameraview.internal.GlUtils; /** * Adjusts the contrast. */ public class ContrastFilter 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 contrast;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " color -= 0.5;\n" + + " color *= contrast;\n" + + " color += 0.5;\n" + + " gl_FragColor = color;\n" + + "}\n"; + private float contrast = 2.0f; + private int contrastLocation = -1; @SuppressWarnings("WeakerAccess") public ContrastFilter() { } @@ -42,30 +60,36 @@ public class ContrastFilter extends BaseFilter { return contrast - 1.0f; } + @NonNull + @Override + public String getFragmentShader() { + return FRAGMENT_SHADER; + } @Override - protected BaseFilter onCopy() { - ContrastFilter filter = new ContrastFilter(); - filter.setContrast(getContrast()); - return filter; + public void onCreate(int programHandle) { + super.onCreate(programHandle); + contrastLocation = GLES20.glGetUniformLocation(programHandle, "contrast"); + GlUtils.checkLocation(contrastLocation, "contrast"); } - @NonNull @Override - public String getFragmentShader() { - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" - + "float contrast;\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - + " contrast =" + contrast + ";\n" - + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " color -= 0.5;\n" - + " color *= contrast;\n" - + " color += 0.5;\n" - + " gl_FragColor = color;\n" + "}\n"; + public void onDestroy() { + super.onDestroy(); + contrastLocation = -1; + } + @Override + protected void onPreDraw(float[] transformMatrix) { + super.onPreDraw(transformMatrix); + GLES20.glUniform1f(contrastLocation, contrast); + GlUtils.checkError("glUniform1f"); } + @Override + protected BaseFilter onCopy() { + ContrastFilter filter = new ContrastFilter(); + filter.setContrast(getContrast()); + return filter; + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrossProcessFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrossProcessFilter.java index 950b75ae..1ff8cca1 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrossProcessFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrossProcessFilter.java @@ -10,44 +10,45 @@ import com.otaliastudios.cameraview.filter.BaseFilter; */ public class CrossProcessFilter extends BaseFilter { + private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "uniform samplerExternalOES sTexture;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " vec3 ncolor = vec3(0.0, 0.0, 0.0);\n" + + " float value;\n" + + " if (color.r < 0.5) {\n" + + " value = color.r;\n" + + " } else {\n" + + " value = 1.0 - color.r;\n" + + " }\n" + + " float red = 4.0 * value * value * value;\n" + + " if (color.r < 0.5) {\n" + + " ncolor.r = red;\n" + + " } else {\n" + + " ncolor.r = 1.0 - red;\n" + + " }\n" + + " if (color.g < 0.5) {\n" + + " value = color.g;\n" + + " } else {\n" + + " value = 1.0 - color.g;\n" + + " }\n" + + " float green = 2.0 * value * value;\n" + + " if (color.g < 0.5) {\n" + + " ncolor.g = green;\n" + + " } else {\n" + + " ncolor.g = 1.0 - green;\n" + + " }\n" + + " ncolor.b = color.b * 0.5 + 0.25;\n" + + " gl_FragColor = vec4(ncolor.rgb, color.a);\n" + + "}\n"; + public CrossProcessFilter() { } @NonNull @Override public String getFragmentShader() { - return "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" - + "varying vec2 vTextureCoord;\n" - + "void main() {\n" - + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " vec3 ncolor = vec3(0.0, 0.0, 0.0);\n" - + " float value;\n" - + " if (color.r < 0.5) {\n" - + " value = color.r;\n" - + " } else {\n" - + " value = 1.0 - color.r;\n" - + " }\n" - + " float red = 4.0 * value * value * value;\n" - + " if (color.r < 0.5) {\n" - + " ncolor.r = red;\n" - + " } else {\n" - + " ncolor.r = 1.0 - red;\n" - + " }\n" - + " if (color.g < 0.5) {\n" - + " value = color.g;\n" - + " } else {\n" - + " value = 1.0 - color.g;\n" - + " }\n" - + " float green = 2.0 * value * value;\n" - + " if (color.g < 0.5) {\n" - + " ncolor.g = green;\n" - + " } else {\n" - + " ncolor.g = 1.0 - green;\n" - + " }\n" - + " ncolor.b = color.b * 0.5 + 0.25;\n" - + " gl_FragColor = vec4(ncolor.rgb, color.a);\n" - + "}\n"; + return FRAGMENT_SHADER; } - } 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 f9eca01a..9a736a83 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java @@ -1,10 +1,12 @@ package com.otaliastudios.cameraview.filters; +import android.opengl.GLES20; + import androidx.annotation.NonNull; import com.otaliastudios.cameraview.filter.BaseFilter; +import com.otaliastudios.cameraview.internal.GlUtils; -import java.util.Date; import java.util.Random; /** @@ -12,54 +14,31 @@ import java.util.Random; */ public class DocumentaryFilter extends BaseFilter { - private final Random mRandom = new Random(new Date().getTime()); - private int mOutputWidth = 1; - private int mOutputHeight = 1; + private final Random mRandom = new Random(); + private int mWidth = 1; + private int mHeight = 1; + private int mScaleLocation = -1; + private int mMaxDistLocation = -1; public DocumentaryFilter() { } @Override public void setSize(int width, int height) { super.setSize(width, height); - mOutputWidth = width; - mOutputHeight = height; + mWidth = width; + mHeight = height; } @NonNull @Override public String getFragmentShader() { - float[] scale = new float[2]; - if (mOutputWidth > mOutputHeight) { - scale[0] = 1f; - scale[1] = ((float) mOutputHeight) / mOutputWidth; - } else { - scale[0] = ((float) mOutputWidth) / mOutputHeight; - scale[1] = 1f; - } - float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] - * scale[1])) * 0.5f; - - float[] seed = {mRandom.nextFloat(), mRandom.nextFloat()}; - - String[] scaleString = new String[2]; - String[] seedString = new String[2]; - - scaleString[0] = "scale[0] = " + scale[0] + ";\n"; - scaleString[1] = "scale[1] = " + scale[1] + ";\n"; - - seedString[0] = "seed[0] = " + seed[0] + ";\n"; - seedString[1] = "seed[1] = " + seed[1] + ";\n"; - - String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; - String stepsizeString = "stepsize = " + 1.0f / 255.0f + ";\n"; - return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" - + " vec2 seed;\n" - + " float stepsize;\n" - + " float inv_max_dist;\n" - + " vec2 scale;\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" @@ -74,13 +53,9 @@ public class DocumentaryFilter extends BaseFilter { + " return fract(part1 + part2 + part3);\n" + "}\n" + "void main() {\n" - // Parameters that were created above - + scaleString[0] - + scaleString[1] - + seedString[0] - + seedString[1] - + inv_max_distString - + stepsizeString + + " seed[0] = " + mRandom.nextFloat() + ";\n" + + " seed[1] = " + mRandom.nextFloat() + ";\n" + + " stepsize = " + 1.0f / 255.0f + ";\n" // black white + " vec4 color = texture2D(sTexture, vTextureCoord);\n" @@ -98,4 +73,41 @@ public class DocumentaryFilter extends BaseFilter { + " gl_FragColor = vec4(new_color * lumen, color.a);\n" + "}\n"; } + + @Override + public void onCreate(int programHandle) { + super.onCreate(programHandle); + mScaleLocation = GLES20.glGetUniformLocation(programHandle, "scale"); + GlUtils.checkLocation(mScaleLocation, "scale"); + mMaxDistLocation = GLES20.glGetUniformLocation(programHandle, "inv_max_dist"); + GlUtils.checkLocation(mMaxDistLocation, "inv_max_dist"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mScaleLocation = -1; + mMaxDistLocation = -1; + } + + @Override + protected void onPreDraw(float[] transformMatrix) { + super.onPreDraw(transformMatrix); + float[] scale = new float[2]; + if (mWidth > mHeight) { + scale[0] = 1f; + scale[1] = ((float) mHeight) / mWidth; + } else { + scale[0] = ((float) mWidth) / mHeight; + scale[1] = 1f; + } + GLES20.glUniform2fv(mScaleLocation, 1, scale, 0); + GlUtils.checkError("glUniform2fv"); + + float maxDist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] * scale[1])) * 0.5f; + float invMaxDist = 1F / maxDist; + GLES20.glUniform1f(mMaxDistLocation, invMaxDist); + GlUtils.checkError("glUniform1f"); + + } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java index 1141810a..c7d03a87 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java @@ -42,7 +42,7 @@ public class EglViewport { public void release() { if (mProgramHandle != -1) { - mFilter.onDestroy(mProgramHandle); + mFilter.onDestroy(); GLES20.glDeleteProgram(mProgramHandle); mProgramHandle = -1; } diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java index 097e9312..cacd56c7 100644 --- a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java @@ -28,6 +28,7 @@ import com.otaliastudios.cameraview.controls.Mode; import com.otaliastudios.cameraview.VideoResult; import com.otaliastudios.cameraview.controls.Preview; import com.otaliastudios.cameraview.filter.Filters; +import com.otaliastudios.cameraview.filters.BrightnessFilter; import com.otaliastudios.cameraview.frame.Frame; import com.otaliastudios.cameraview.frame.FrameProcessor; @@ -331,6 +332,12 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis mCurrentFilter = 0; } camera.setFilter(mAllFilters[mCurrentFilter].newInstance()); + /* BrightnessFilter filter = (BrightnessFilter) camera.getFilter(); + if (filter.getBrightness() == 1.0F) { + filter.setBrightness(0.0F); + } else { + filter.setBrightness(filter.getBrightness() + 0.2F); + } */ } @Override