From 5caddd3d745c3dc621c339c083841cc15e59d66a Mon Sep 17 00:00:00 2001 From: Mattia Iavarone Date: Mon, 5 Aug 2019 19:31:15 +0200 Subject: [PATCH] Move GL drawing code into BaseFilter --- .../cameraview/filters/AutoFixFilter.java | 51 ++--- .../cameraview/filters/BaseFilter.java | 216 ++++++++++++------ .../filters/BlackAndWhiteFilter.java | 14 +- .../cameraview/filters/BrightnessFilter.java | 16 +- .../cameraview/filters/ContrastFilter.java | 22 +- .../filters/CrossProcessFilter.java | 49 ++-- .../cameraview/filters/CustomFilter.java | 27 --- .../cameraview/filters/DocumentaryFilter.java | 37 +-- .../cameraview/filters/DuotoneFilter.java | 25 +- .../cameraview/filters/FillLightFilter.java | 18 +- .../cameraview/filters/Filter.java | 6 + .../cameraview/filters/Filters.java | 2 +- .../cameraview/filters/GammaFilter.java | 13 +- .../cameraview/filters/GrainFilter.java | 29 ++- .../cameraview/filters/GrayscaleFilter.java | 20 +- .../cameraview/filters/HueFilter.java | 56 ++--- .../filters/InvertColorsFilter.java | 15 +- ...{LamoishFilter.java => LomoishFilter.java} | 59 +++-- .../cameraview/filters/NoFilter.java | 2 +- .../cameraview/filters/PosterizeFilter.java | 15 +- .../cameraview/filters/SaturationFilter.java | 23 +- .../cameraview/filters/SepiaFilter.java | 24 +- .../cameraview/filters/SharpnessFilter.java | 22 +- .../cameraview/filters/TemperatureFilter.java | 20 +- .../cameraview/filters/TintFilter.java | 18 +- .../cameraview/filters/VignetteFilter.java | 33 +-- .../{egl/EglElement.java => GlUtils.java} | 35 +-- .../internal/egl/EglBaseSurface.java | 7 +- .../cameraview/internal/egl/EglViewport.java | 105 ++------- 29 files changed, 440 insertions(+), 539 deletions(-) delete mode 100644 cameraview/src/main/java/com/otaliastudios/cameraview/filters/CustomFilter.java rename cameraview/src/main/java/com/otaliastudios/cameraview/filters/{LamoishFilter.java => LomoishFilter.java} (76%) rename cameraview/src/main/java/com/otaliastudios/cameraview/internal/{egl/EglElement.java => GlUtils.java} (74%) 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 88cee44f..bc3d2aea 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/AutoFixFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/AutoFixFilter.java @@ -9,11 +9,7 @@ public class AutoFixFilter extends BaseFilter { private float scale = 1.0f; - /** - * Initialize Effect - */ - public AutoFixFilter() { - } + public AutoFixFilter() { } public float getScale() { return scale; @@ -35,34 +31,25 @@ public class AutoFixFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + 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" + + "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" @@ -88,9 +75,7 @@ public class AutoFixFilter extends BaseFilter { + " gl_FragColor = color;\n" + " } else {\n" + " gl_FragColor = vec4(color.rgb * dst_energy / energy, color.a);\n" - + " }\n" + "}\n"; - - return shader; - + + " }\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java index 27c532d5..3134fd50 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BaseFilter.java @@ -1,7 +1,14 @@ package com.otaliastudios.cameraview.filters; +import android.opengl.GLES20; + import androidx.annotation.NonNull; +import com.otaliastudios.cameraview.CameraLogger; +import com.otaliastudios.cameraview.internal.GlUtils; + +import java.nio.FloatBuffer; + /** * A Base abstract class that every effect must extend so that there is a common getShader method. *

@@ -22,99 +29,164 @@ import androidx.annotation.NonNull; */ public abstract class BaseFilter implements Filter { - /** - * Vertex shader code written in Shader Language (C) and stored as String. - * This wil be used by GL to apply any effect. - */ + private final static String TAG = BaseFilter.class.getSimpleName(); + private final static CameraLogger LOG = CameraLogger.create(TAG); + + private final static String DEFAULT_VERTEX_POSITION_NAME = "aPosition"; + private final static String DEFAULT_VERTEX_TEXTURE_COORDINATE_NAME = "aTextureCoord"; + private final static String DEFAULT_VERTEX_MVP_MATRIX_NAME = "uMVPMatrix"; + private final static String DEFAULT_VERTEX_TRANSFORM_MATRIX_NAME = "uTexMatrix"; + private final static String DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME = "vTextureCoord"; + @NonNull - String mVertexShader = - "uniform mat4 uMVPMatrix;\n" + - "uniform mat4 uTexMatrix;\n" + - "attribute vec4 aPosition;\n" + - "attribute vec4 aTextureCoord;\n" + - "varying vec2 vTextureCoord;\n" + - "void main() {\n" + - " gl_Position = uMVPMatrix * aPosition;\n" + - " vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" + - "}\n"; - - - /** - * Fragment shader code written in Shader Language (C) and stored as String. - * This wil be used by GL to apply any effect. - */ + private static String createDefaultVertexShader(@NonNull String vertexPositionName, + @NonNull String vertexTextureCoordinateName, + @NonNull String vertexModelViewProjectionMatrixName, + @NonNull String vertexTransformMatrixName, + @NonNull String fragmentTextureCoordinateName) { + return "uniform mat4 "+vertexModelViewProjectionMatrixName+";\n" + + "uniform mat4 "+vertexTransformMatrixName+";\n" + + "attribute vec4 "+vertexPositionName+";\n" + + "attribute vec4 "+vertexTextureCoordinateName+";\n" + + "varying vec2 "+fragmentTextureCoordinateName+";\n" + + "void main() {\n" + + " gl_Position = "+vertexModelViewProjectionMatrixName+" * "+vertexPositionName+";\n" + + " vTextureCoord = ("+vertexTransformMatrixName+" * "+vertexTextureCoordinateName+").xy;\n" + + "}\n"; + } + @NonNull - String mFragmentShader = - "#extension GL_OES_EGL_image_external : require\n" - + "precision mediump float;\n" - + "varying vec2 vTextureCoord;\n" - + "uniform samplerExternalOES sTexture;\n" - + "void main() {\n" - + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" - + "}\n"; - - /** - * Width and height of previewing GlSurfaceview. - * This will be used by a few effects. - */ - int mPreviewingViewWidth = 0; - int mPreviewingViewHeight = 0; + private static String createDefaultFragmentShader(@NonNull String fragmentTextureCoordinateName) { + return "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "varying vec2 "+fragmentTextureCoordinateName+";\n" + + "uniform samplerExternalOES sTexture;\n" + + "void main() {\n" + + " gl_FragColor = texture2D(sTexture, "+fragmentTextureCoordinateName+");\n" + + "}\n"; + } - public void setOutputSize(int width, int height) { - mPreviewingViewWidth = width; - mPreviewingViewHeight = height; + // When the model/view/projection matrix is identity, this will exactly cover the viewport. + private static final FloatBuffer VERTEX_POSITION = GlUtils.floatBuffer(new float[]{ + -1.0f, -1.0f, // 0 bottom left + 1.0f, -1.0f, // 1 bottom right + -1.0f, 1.0f, // 2 top left + 1.0f, 1.0f, // 3 top right + }); + + private static final FloatBuffer TEXTURE_COORDINATES = GlUtils.floatBuffer(new float[]{ + 0.0f, 0.0f, // 0 bottom left + 1.0f, 0.0f, // 1 bottom right + 0.0f, 1.0f, // 2 top left + 1.0f, 1.0f // 3 top right + }); + + + private int vertexModelViewProjectionMatrixLocation = -1; + private int vertexTranformMatrixLocation = -1; + private int vertexPositionLocation = -1; + private int vertexTextureCoordinateLocation = -1; + + @SuppressWarnings("WeakerAccess") + protected String vertexPositionName = DEFAULT_VERTEX_POSITION_NAME; + @SuppressWarnings("WeakerAccess") + protected String vertexTextureCoordinateName = DEFAULT_VERTEX_TEXTURE_COORDINATE_NAME; + @SuppressWarnings("WeakerAccess") + protected String vertexModelViewProjectionMatrixName = DEFAULT_VERTEX_MVP_MATRIX_NAME; + @SuppressWarnings("WeakerAccess") + protected String vertexTransformMatrixName = DEFAULT_VERTEX_TRANSFORM_MATRIX_NAME; + @SuppressWarnings({"unused", "WeakerAccess"}) + protected String fragmentTextureCoordinateName = DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME; + + @SuppressWarnings("WeakerAccess") + @NonNull + protected String createDefaultVertexShader() { + return createDefaultVertexShader(vertexPositionName, + vertexTextureCoordinateName, + vertexModelViewProjectionMatrixName, + vertexTransformMatrixName, + fragmentTextureCoordinateName); } - /** - * Local variable name which were used in the shader code. - * These will be used by openGL program to render these vertex and fragment shader - */ - private String mPositionVariableName = "aPosition"; - private String mTextureCoordinateVariableName = "aTextureCoord"; - private String mMVPMatrixVariableName = "uMVPMatrix"; - private String mTextureMatrixVariableName = "uTexMatrix"; - - public String getPositionVariableName() { - return mPositionVariableName; + @SuppressWarnings("WeakerAccess") + @NonNull + protected String createDefaultFragmentShader() { + return createDefaultFragmentShader(fragmentTextureCoordinateName); } - public void setPositionVariableName(String positionVariableName) { - this.mPositionVariableName = positionVariableName; + @Override + public void onCreate(int programHandle) { + vertexPositionLocation = GLES20.glGetAttribLocation(programHandle, vertexPositionName); + GlUtils.checkLocation(vertexPositionLocation, vertexPositionName); + vertexTextureCoordinateLocation = GLES20.glGetAttribLocation(programHandle, vertexTextureCoordinateName); + GlUtils.checkLocation(vertexTextureCoordinateLocation, vertexTextureCoordinateName); + vertexModelViewProjectionMatrixLocation = GLES20.glGetUniformLocation(programHandle, vertexModelViewProjectionMatrixName); + GlUtils.checkLocation(vertexModelViewProjectionMatrixLocation, vertexModelViewProjectionMatrixName); + vertexTranformMatrixLocation = GLES20.glGetUniformLocation(programHandle, vertexTransformMatrixName); + GlUtils.checkLocation(vertexTranformMatrixLocation, vertexTransformMatrixName); } - public String getTexttureCoordinateVariableName() { - return mTextureCoordinateVariableName; + @Override + public void onDestroy() { + vertexModelViewProjectionMatrixLocation = -1; + vertexTranformMatrixLocation = -1; + vertexTextureCoordinateLocation = -1; + vertexPositionLocation = -1; } - public void setTexttureCoordinateVariableName(String texttureCoordinateVariableName) { - this.mTextureCoordinateVariableName = texttureCoordinateVariableName; + @NonNull + @Override + public String getVertexShader() { + return createDefaultVertexShader(); } - public String getMVPMatrixVariableName() { - return mMVPMatrixVariableName; + @Override + public void setOutputSize(int width, int height) { + } - public void setMVPMatrixVariableName(String mvpMatrixVariableName) { - this.mMVPMatrixVariableName = mvpMatrixVariableName; + @Override + public void draw(float[] transformMatrix) { + onPreDraw(transformMatrix); + onDraw(); + onPostDraw(); } - public String getTextureMatrixVariableName() { - return mTextureMatrixVariableName; + @SuppressWarnings("WeakerAccess") + protected void onPreDraw(float[] transformMatrix) { + // Copy the model / view / projection matrix over. + GLES20.glUniformMatrix4fv(vertexModelViewProjectionMatrixLocation, 1, false, GlUtils.IDENTITY_MATRIX, 0); + GlUtils.checkError("glUniformMatrix4fv"); + + // Copy the texture transformation matrix over. + GLES20.glUniformMatrix4fv(vertexTranformMatrixLocation, 1, false, transformMatrix, 0); + GlUtils.checkError("glUniformMatrix4fv"); + + // Enable the "aPosition" vertex attribute. + // Connect vertexBuffer to "aPosition". + GLES20.glEnableVertexAttribArray(vertexPositionLocation); + GlUtils.checkError("glEnableVertexAttribArray"); + GLES20.glVertexAttribPointer(vertexPositionLocation, 2, GLES20.GL_FLOAT, false, 8, VERTEX_POSITION); + GlUtils.checkError("glVertexAttribPointer"); + + // Enable the "aTextureCoord" vertex attribute. + // Connect texBuffer to "aTextureCoord". + GLES20.glEnableVertexAttribArray(vertexTextureCoordinateLocation); + GlUtils.checkError("glEnableVertexAttribArray"); + GLES20.glVertexAttribPointer(vertexTextureCoordinateLocation, 2, GLES20.GL_FLOAT, false, 8, TEXTURE_COORDINATES); + GlUtils.checkError("glVertexAttribPointer"); } - public void setTextureMatrixVariableName(String textureMatrixVariableName) { - this.mTextureMatrixVariableName = textureMatrixVariableName; + @SuppressWarnings("WeakerAccess") + protected void onDraw() { + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + GlUtils.checkError("glDrawArrays"); } - /** - * Get vertex Shader code - * - * @return complete shader code in C - */ - @Override - @NonNull - public String getVertexShader() { - return mVertexShader; + @SuppressWarnings("WeakerAccess") + protected void onPostDraw() { + GLES20.glDisableVertexAttribArray(vertexPositionLocation); + GLES20.glDisableVertexAttribArray(vertexTextureCoordinateLocation); } } 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 bc4af92a..4e85e1cc 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BlackAndWhiteFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BlackAndWhiteFilter.java @@ -3,22 +3,17 @@ package com.otaliastudios.cameraview.filters; import androidx.annotation.NonNull; /** - * Converts the preview into black and white colors + * Converts the frames into black and white colors. */ public class BlackAndWhiteFilter extends BaseFilter { - /** - * Initialize effect - */ - public BlackAndWhiteFilter() { - } + public BlackAndWhiteFilter() { } @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "varying vec2 vTextureCoord;\n" + "uniform samplerExternalOES sTexture;\n" + "void main() {\n" @@ -28,8 +23,5 @@ public class BlackAndWhiteFilter extends BaseFilter { + " float colorB = (color.r + color.g + color.b) / 3.0;\n" + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" + "}\n"; - - return 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 61c79ade..dfb95e88 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BrightnessFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/BrightnessFilter.java @@ -39,18 +39,16 @@ public class BrightnessFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + 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 =" + brightnessValue - + ";\n" + + "float brightness ;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " brightness =" + brightnessValue + ";\n" + " vec4 color = texture2D(sTexture, vTextureCoord);\n" - + " gl_FragColor = brightness * color;\n" + "}\n"; - - return shader; - + + " gl_FragColor = brightness * color;\n" + + "}\n"; } } 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 9f79a93b..c1c17e9c 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/ContrastFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/ContrastFilter.java @@ -8,11 +8,7 @@ import androidx.annotation.NonNull; public class ContrastFilter extends BaseFilter { private float contrast = 2.0f; - /** - * Initialize Effect - */ - public ContrastFilter() { - } + public ContrastFilter() { } /** * setContrast @@ -39,16 +35,18 @@ public class ContrastFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + 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" + + "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"; - return shader; + + " color -= 0.5;\n" + + " color *= contrast;\n" + + " color += 0.5;\n" + + " gl_FragColor = color;\n" + "}\n"; } 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 985ca7e4..9ac3d852 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrossProcessFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrossProcessFilter.java @@ -8,37 +8,44 @@ import androidx.annotation.NonNull; */ public class CrossProcessFilter extends BaseFilter { - /** - * Initialize Effect - */ - public CrossProcessFilter() { - } + public CrossProcessFilter() { } @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" - + "varying vec2 vTextureCoord;\n" + "void main() {\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" + + " 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" + + " 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" + + " 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 shader; - + + " gl_FragColor = vec4(ncolor.rgb, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CustomFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CustomFilter.java deleted file mode 100644 index 876fc366..00000000 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/CustomFilter.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.otaliastudios.cameraview.filters; - -import androidx.annotation.NonNull; - - -/** - * This class is to implement any custom effect. - */ -public class CustomFilter extends BaseFilter { - - /** - * Parameterized constructor with vertex and fragment shader as parameter - * - * @param vertexShader - * @param fragmentShader - */ - public CustomFilter(String vertexShader, String fragmentShader) { - this.mVertexShader = vertexShader; - this.mFragmentShader = fragmentShader; - } - - @NonNull - @Override - public String getFragmentShader() { - return mFragmentShader; - } -} 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 c1fa3370..fda3751a 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DocumentaryFilter.java @@ -9,30 +9,38 @@ import java.util.Random; * Applies black and white documentary style effect on preview. */ public class DocumentaryFilter extends BaseFilter { - private Random mRandom; + private final Random mRandom = new Random(new Date().getTime()); + private int mOutputWidth = 1; + private int mOutputHeight = 1; public DocumentaryFilter() { - mRandom = new Random(new Date().getTime()); + } + + @Override + public void setOutputSize(int width, int height) { + super.setOutputSize(width, height); + mOutputWidth = width; + mOutputHeight = height; } @NonNull @Override public String getFragmentShader() { - float scale[] = new float[2]; - if (mPreviewingViewWidth > mPreviewingViewHeight) { + float[] scale = new float[2]; + if (mOutputWidth > mOutputHeight) { scale[0] = 1f; - scale[1] = ((float) mPreviewingViewHeight) / mPreviewingViewWidth; + scale[1] = ((float) mOutputHeight) / mOutputWidth; } else { - scale[0] = ((float) mPreviewingViewWidth) / mPreviewingViewHeight; + 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()}; + float[] seed = {mRandom.nextFloat(), mRandom.nextFloat()}; - String scaleString[] = new String[2]; - String seedString[] = new String[2]; + String[] scaleString = new String[2]; + String[] seedString = new String[2]; scaleString[0] = "scale[0] = " + scale[0] + ";\n"; scaleString[1] = "scale[1] = " + scale[1] + ";\n"; @@ -43,7 +51,7 @@ public class DocumentaryFilter extends BaseFilter { String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; String stepsizeString = "stepsize = " + 1.0f / 255.0f + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + " vec2 seed;\n" @@ -78,19 +86,14 @@ public class DocumentaryFilter extends BaseFilter { + " 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" + + " 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" + + " 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 shader; - } } 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 97fba11c..83583879 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DuotoneFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/DuotoneFilter.java @@ -12,9 +12,7 @@ public class DuotoneFilter extends BaseFilter { private int mFirstColor = Color.MAGENTA; private int mSecondColor = Color.YELLOW; - /** - * Initialize effect - */ + public DuotoneFilter() { } @@ -42,14 +40,14 @@ public class DuotoneFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - float first[] = {Color.red(mFirstColor) / 255f, + float[] first = {Color.red(mFirstColor) / 255f, Color.green(mFirstColor) / 255f, Color.blue(mFirstColor) / 255f}; - float second[] = {Color.red(mSecondColor) / 255f, + float[] second = {Color.red(mSecondColor) / 255f, Color.green(mSecondColor) / 255f, Color.blue(mSecondColor) / 255f}; - String firstColorString[] = new String[3]; - String secondColorString[] = new String[3]; + String[] firstColorString = new String[3]; + String[] secondColorString = new String[3]; firstColorString[0] = "first[0] = " + first[0] + ";\n"; firstColorString[1] = "first[1] = " + first[1] + ";\n"; @@ -59,11 +57,11 @@ public class DuotoneFilter extends BaseFilter { secondColorString[1] = "second[1] = " + second[1] + ";\n"; secondColorString[2] = "second[2] = " + second[2] + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" - + " vec3 first;\n" - + " vec3 second;\n" + + "vec3 first;\n" + + "vec3 second;\n" + "varying vec2 vTextureCoord;\n" + "void main() {\n" // Parameters that were created above @@ -73,13 +71,10 @@ public class DuotoneFilter extends BaseFilter { + 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"; - - return shader; - + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/FillLightFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/FillLightFilter.java index 48fed323..75a633a0 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/FillLightFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/FillLightFilter.java @@ -8,11 +8,7 @@ import androidx.annotation.NonNull; public class FillLightFilter extends BaseFilter { private float strength = 0.5f; - /** - * Initialize Effect - */ - public FillLightFilter() { - } + public FillLightFilter() { } /** * setStrength @@ -44,18 +40,16 @@ public class FillLightFilter extends BaseFilter { String multString = "mult = " + mult + ";\n"; String igammaString = "igamma = " + igamma + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + " float mult;\n" + " float igamma;\n" + "varying vec2 vTextureCoord;\n" - + "void main()\n" - + "{\n" + + "void main() {\n" // Parameters that were created above + multString + igammaString - + " const vec3 color_weights = vec3(0.25, 0.5, 0.25);\n" + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + " float lightmask = dot(color.rgb, color_weights);\n" @@ -64,10 +58,8 @@ public class FillLightFilter extends BaseFilter { + " vec3 diff = pow(mult * color.rgb, igamma * ones) - color.rgb;\n" + " diff = min(diff, 1.0);\n" + " vec3 new_color = min(color.rgb + diff * backmask, 1.0);\n" - + " gl_FragColor = vec4(new_color, color.a);\n" + "}\n"; - - return shader; - + + " gl_FragColor = vec4(new_color, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java index 1a106dc6..709adbd9 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filter.java @@ -5,6 +5,12 @@ import androidx.annotation.NonNull; public interface Filter { + void onCreate(int programHandle); + + void onDestroy(); + + void draw(float[] transformMatrix); + void setOutputSize(int width, int height); @NonNull diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java index 620527c5..870baded 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/Filters.java @@ -23,7 +23,7 @@ public enum Filters { GRAYSCALE(GrayscaleFilter.class), HUE(HueFilter.class), INVERT_COLORS(InvertColorsFilter.class), - LAMOISH(LamoishFilter.class), + LOMOISH(LomoishFilter.class), POSTERIZE(PosterizeFilter.class), SATURATION(SaturationFilter.class), SEPIA(SepiaFilter.class), diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GammaFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GammaFilter.java index a6a53c00..8c589e0b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GammaFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GammaFilter.java @@ -39,21 +39,14 @@ public class GammaFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" - + "varying vec2 vTextureCoord;\n" + "uniform samplerExternalOES sTexture;\n" + "float gamma=" + gammaValue + ";\n" - + "void main() {\n" - - + "vec4 textureColor = texture2D(sTexture, vTextureCoord);\n" - + "gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n" - + + " vec4 textureColor = texture2D(sTexture, vTextureCoord);\n" + + " gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n" + "}\n"; - - return shader; } } \ No newline at end of file diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrainFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrainFilter.java index 55938ecb..9cbbeb99 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrainFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrainFilter.java @@ -9,14 +9,20 @@ import java.util.Random; * Applies film grain effect to preview. */ public class GrainFilter extends BaseFilter { + private float strength = 0.5f; - private Random mRandom; + private Random mRandom = new Random(new Date().getTime()); + private int mOutputWidth = 1; + private int mOutputHeight = 1; - /** - * Initialize Effect - */ - public GrainFilter() { - mRandom = new Random(new Date().getTime()); + + public GrainFilter() { } + + @Override + public void setOutputSize(int width, int height) { + super.setOutputSize(width, height); + mOutputWidth = width; + mOutputHeight = height; } /** @@ -40,17 +46,17 @@ public class GrainFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - float seed[] = {mRandom.nextFloat(), mRandom.nextFloat()}; + float[] seed = {mRandom.nextFloat(), mRandom.nextFloat()}; String scaleString = "scale = " + strength + ";\n"; - String seedString[] = new String[2]; + String[] seedString = new String[2]; seedString[0] = "seed[0] = " + seed[0] + ";\n"; seedString[1] = "seed[1] = " + seed[1] + ";\n"; - String stepX = "stepX = " + 0.5f / mPreviewingViewWidth + ";\n"; - String stepY = "stepY = " + 0.5f / mPreviewingViewHeight + ";\n"; + String stepX = "stepX = " + 0.5f / mOutputWidth + ";\n"; + String stepY = "stepY = " + 0.5f / mOutputHeight + ";\n"; // locString[1] = "loc[1] = loc[1]+" + seedString[1] + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + " vec2 seed;\n" + "varying vec2 vTextureCoord;\n" @@ -92,7 +98,6 @@ public class GrainFilter extends BaseFilter { + " gl_FragColor = vec4(color.rgb * weight, color.a);\n" + " gl_FragColor = gl_FragColor+vec4(rand(vTextureCoord + seed), rand(vTextureCoord + seed),rand(vTextureCoord + seed),1);\n" + "}\n"; - return shader; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrayscaleFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrayscaleFilter.java index 0f0d3bd8..8ebd2a83 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrayscaleFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrayscaleFilter.java @@ -6,26 +6,20 @@ import androidx.annotation.NonNull; * Converts preview to GreyScale. */ public class GrayscaleFilter extends BaseFilter { - /** - * Initialize Effect - */ - public GrayscaleFilter() { - } + + public GrayscaleFilter() { } @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" - + "varying vec2 vTextureCoord;\n" + "void main() {\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + " float y = dot(color, vec4(0.299, 0.587, 0.114, 0));\n" - + " gl_FragColor = vec4(y, y, y, color.a);\n" + "}\n"; - ; - - return shader; - + + " gl_FragColor = vec4(y, y, y, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/HueFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/HueFilter.java index ee0ed2eb..d3194d8c 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/HueFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/HueFilter.java @@ -6,7 +6,7 @@ import androidx.annotation.NonNull; * Apply Hue effect on the preview */ public class HueFilter extends BaseFilter { - float hueValue = 0.0f; + private float hueValue = 0.0f; /** * Initialize Effect @@ -27,46 +27,30 @@ public class HueFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" - + "varying vec2 vTextureCoord;\n" + "uniform samplerExternalOES sTexture;\n" + "float hue=" + hueValue + ";\n" - + "void main() {\n" - - + "vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\n" - + "vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\n" - + "vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\n" - - + "vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\n" - + "vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\n" - + "vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\n" - - - + "vec4 color = texture2D(sTexture, vTextureCoord);\n" - - + "float YPrime = dot(color, kRGBToYPrime);\n" - + "float I = dot(color, kRGBToI);\n" - + "float Q = dot(color, kRGBToQ);\n" - - + "float chroma = sqrt (I * I + Q * Q);\n" - - + "Q = chroma * sin (hue);\n" - - + "I = chroma * cos (hue);\n" - - + "vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\n" - - + "color.r = dot (yIQ, kYIQToR);\n" - + "color.g = dot (yIQ, kYIQToG);\n" - + "color.b = dot (yIQ, kYIQToB);\n" - + "gl_FragColor = color;\n" - + + " vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\n" + + " vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\n" + + " vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\n" + + " vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\n" + + " vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\n" + + " vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\n" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " float YPrime = dot(color, kRGBToYPrime);\n" + + " float I = dot(color, kRGBToI);\n" + + " float Q = dot(color, kRGBToQ);\n" + + " float chroma = sqrt (I * I + Q * Q);\n" + + " Q = chroma * sin (hue);\n" + + " I = chroma * cos (hue);\n" + + " vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\n" + + " color.r = dot (yIQ, kYIQToR);\n" + + " color.g = dot (yIQ, kYIQToG);\n" + + " color.b = dot (yIQ, kYIQToB);\n" + + " gl_FragColor = color;\n" + "}\n"; - - return shader; } } \ No newline at end of file diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/InvertColorsFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/InvertColorsFilter.java index df22216a..a20686ff 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/InvertColorsFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/InvertColorsFilter.java @@ -6,20 +6,17 @@ import androidx.annotation.NonNull; * Inverts the preview colors. This can also be known as negative Effect. */ public class InvertColorsFilter extends BaseFilter { - /** - * Initialize Effect - */ - public InvertColorsFilter() { - } + + public InvertColorsFilter() { } @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "varying vec2 vTextureCoord;\n" - + "uniform samplerExternalOES sTexture;\n" + "void main() {\n" + + "uniform samplerExternalOES sTexture;\n" + + "void main() {\n" + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + " float colorR = (1.0 - color.r) / 1.0;\n" + " float colorG = (1.0 - color.g) / 1.0;\n" @@ -27,7 +24,5 @@ public class InvertColorsFilter extends BaseFilter { + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" + "}\n"; - return shader; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/LamoishFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/LomoishFilter.java similarity index 76% rename from cameraview/src/main/java/com/otaliastudios/cameraview/filters/LamoishFilter.java rename to cameraview/src/main/java/com/otaliastudios/cameraview/filters/LomoishFilter.java index 5734585b..40685677 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/LamoishFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/LomoishFilter.java @@ -8,34 +8,40 @@ import java.util.Random; /** * Applies lomo-camera style effect to preview. */ -public class LamoishFilter extends BaseFilter { - private Random mRandom; +public class LomoishFilter extends BaseFilter { - /** - * Initialize Effect - */ - public LamoishFilter() { - mRandom = new Random(new Date().getTime()); + private final Random mRandom = new Random(new Date().getTime()); + private int mOutputWidth = 1; + private int mOutputHeight = 1; + + public LomoishFilter() { + } + + @Override + public void setOutputSize(int width, int height) { + super.setOutputSize(width, height); + mOutputWidth = width; + mOutputHeight = height; } @NonNull @Override public String getFragmentShader() { - float scale[] = new float[2]; - if (mPreviewingViewWidth > mPreviewingViewHeight) { + float[] scale = new float[2]; + if (mOutputWidth > mOutputHeight) { scale[0] = 1f; - scale[1] = ((float) mPreviewingViewHeight) / mPreviewingViewWidth; + scale[1] = ((float) mOutputHeight) / mOutputWidth; } else { - scale[0] = ((float) mPreviewingViewWidth) / mPreviewingViewHeight; + 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()}; + float[] seed = {mRandom.nextFloat(), mRandom.nextFloat()}; - String scaleString[] = new String[2]; - String seedString[] = new String[2]; + String[] scaleString = new String[2]; + String[] seedString = new String[2]; scaleString[0] = "scale[0] = " + scale[0] + ";\n"; scaleString[1] = "scale[1] = " + scale[1] + ";\n"; @@ -45,10 +51,10 @@ public class LamoishFilter extends BaseFilter { String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; String stepsizeString = "stepsize = " + 1.0f / 255.0f + ";\n"; - String stepsizeXString = "stepsizeX = " + 1.0f / mPreviewingViewWidth + ";\n"; - String stepsizeYString = "stepsizeY = " + 1.0f / mPreviewingViewHeight + ";\n"; + String stepsizeXString = "stepsizeX = " + 1.0f / mOutputWidth + ";\n"; + String stepsizeYString = "stepsizeY = " + 1.0f / mOutputHeight + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + " vec2 seed;\n" @@ -62,13 +68,13 @@ public class LamoishFilter extends BaseFilter { + " 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 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" + + " return fract(part1 + part2 + part3);\n" + + "}\n" + "void main() {\n" // Parameters that were created above + scaleString[0] @@ -96,9 +102,8 @@ public class LamoishFilter extends BaseFilter { + " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n" + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n" + " vec3 s_color = vec3(color.rgb + 0.3 * nbr_color);\n" - + // cross process - " vec3 c_color = vec3(0.0, 0.0, 0.0);\n" + + " vec3 c_color = vec3(0.0, 0.0, 0.0);\n" + " float value;\n" + " if (s_color.r < 0.5) {\n" + " value = s_color.r;\n" @@ -123,21 +128,15 @@ public class LamoishFilter extends BaseFilter { + " c_color.g = 1.0 - green;\n" + " }\n" + " c_color.b = s_color.b * 0.5 + 0.25;\n" - + // blackwhite - " float dither = rand(vTextureCoord + seed);\n" + + " float dither = rand(vTextureCoord + seed);\n" + " vec3 xform = clamp((c_color.rgb - 0.15) * 1.53846, 0.0, 1.0);\n" + " vec3 temp = clamp((color.rgb + stepsize - 0.15) * 1.53846, 0.0, 1.0);\n" + " vec3 bw_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" - + // vignette - " coord = vTextureCoord - vec2(0.5, 0.5);\n" + + " 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.73) * 20.0)) + 0.15;\n" + " gl_FragColor = vec4(bw_color * lumen, color.a);\n" + "}\n"; - ; - - return shader; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/NoFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/NoFilter.java index 005a5887..cf94e23f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/NoFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/NoFilter.java @@ -7,6 +7,6 @@ public class NoFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - return mFragmentShader; + return createDefaultFragmentShader(); } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/PosterizeFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/PosterizeFilter.java index 86eee47f..5a0efe16 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/PosterizeFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/PosterizeFilter.java @@ -6,17 +6,13 @@ import androidx.annotation.NonNull; * Applies Posterization effect to Preview. */ public class PosterizeFilter extends BaseFilter { - /** - * Initialize Effect - */ - public PosterizeFilter() { - } + + public PosterizeFilter() { } @NonNull @Override public String getFragmentShader() { - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + "varying vec2 vTextureCoord;\n" + "void main() {\n" @@ -25,8 +21,7 @@ public class PosterizeFilter extends BaseFilter { + " pcolor.r = (color.r >= 0.5) ? 0.75 : 0.25;\n" + " pcolor.g = (color.g >= 0.5) ? 0.75 : 0.25;\n" + " pcolor.b = (color.b >= 0.5) ? 0.75 : 0.25;\n" - + " gl_FragColor = vec4(pcolor, color.a);\n" + "}\n"; - return shader; - + + " gl_FragColor = vec4(pcolor, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SaturationFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SaturationFilter.java index 73ed84f5..f10b94ee 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SaturationFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SaturationFilter.java @@ -40,11 +40,11 @@ public class SaturationFilter extends BaseFilter { @Override public String getFragmentShader() { float shift = 1.0f / 255.0f; - float weights[] = {2f / 8f, 5f / 8f, 1f / 8f}; - float exponents[] = new float[3]; + float[] weights = {2f / 8f, 5f / 8f, 1f / 8f}; + float[] exponents = new float[3]; - String weightsString[] = new String[3]; - String exponentsString[] = new String[3]; + String[] weightsString = new String[3]; + String[] exponentsString = new String[3]; exponentsString[0] = ""; exponentsString[1] = ""; exponentsString[2] = ""; @@ -65,11 +65,15 @@ public class SaturationFilter extends BaseFilter { weightsString[2] = "weights[2] = " + weights[2] + ";\n"; String shiftString = "shift = " + shift + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + 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" + + "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] @@ -94,9 +98,6 @@ public class SaturationFilter extends BaseFilter { + " 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"; - - return shader; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SepiaFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SepiaFilter.java index 8de33517..bba0ca5a 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SepiaFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SepiaFilter.java @@ -6,20 +6,17 @@ import androidx.annotation.NonNull; * Converts preview to Sepia tone. */ public class SepiaFilter extends BaseFilter { - /** - * Initialize Effect - */ - public SepiaFilter() { - } + + public SepiaFilter() { } @NonNull @Override public String getFragmentShader() { - float weights[] = {805.0f / 2048.0f, 715.0f / 2048.0f, + float[] weights = {805.0f / 2048.0f, 715.0f / 2048.0f, 557.0f / 2048.0f, 1575.0f / 2048.0f, 1405.0f / 2048.0f, 1097.0f / 2048.0f, 387.0f / 2048.0f, 344.0f / 2048.0f, 268.0f / 2048.0f}; - String matrixString[] = new String[9]; + String[] matrixString = new String[9]; matrixString[0] = " matrix[0][0]=" + weights[0] + ";\n"; matrixString[1] = " matrix[0][1]=" + weights[1] + ";\n"; @@ -31,18 +28,19 @@ public class SepiaFilter extends BaseFilter { matrixString[7] = " matrix[2][1]=" + weights[7] + ";\n"; matrixString[8] = " matrix[2][2]=" + weights[8] + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" - + "uniform samplerExternalOES sTexture;\n" + " mat3 matrix;\n" - + "varying vec2 vTextureCoord;\n" + "void main() {\n" + + "uniform samplerExternalOES sTexture;\n" + + "mat3 matrix;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + matrixString[0] + matrixString[1] + matrixString[2] + matrixString[3] + matrixString[4] + matrixString[5] + matrixString[6] + matrixString[7] + matrixString[8] + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + " vec3 new_color = min(matrix * color.rgb, 1.0);\n" - + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n"; - - return shader; + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SharpnessFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SharpnessFilter.java index c2013806..b2b1d32f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SharpnessFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/SharpnessFilter.java @@ -7,11 +7,16 @@ import androidx.annotation.NonNull; */ public class SharpnessFilter extends BaseFilter { private float scale = 0.5f; + private int mOutputWidth = 1; + private int mOutputHeight = 1; - /** - * Initialize Effect - */ - public SharpnessFilter() { + public SharpnessFilter() { } + + @Override + public void setOutputSize(int width, int height) { + super.setOutputSize(width, height); + mOutputWidth = width; + mOutputHeight = height; } /** @@ -33,12 +38,11 @@ public class SharpnessFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - - String stepsizeXString = "stepsizeX = " + 1.0f / mPreviewingViewWidth + ";\n"; - String stepsizeYString = "stepsizeY = " + 1.0f / mPreviewingViewHeight + ";\n"; + String stepsizeXString = "stepsizeX = " + 1.0f / mOutputWidth + ";\n"; + String stepsizeYString = "stepsizeY = " + 1.0f / mOutputHeight + ";\n"; String scaleString = "scale = " + scale + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + " float scale;\n" @@ -68,8 +72,6 @@ public class SharpnessFilter extends BaseFilter { + " gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n" + "}\n"; - return shader; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TemperatureFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TemperatureFilter.java index 178494a7..2e931f8e 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TemperatureFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TemperatureFilter.java @@ -8,11 +8,7 @@ import androidx.annotation.NonNull; public class TemperatureFilter extends BaseFilter { private float scale = 0f; - /** - * Initialize Effect - */ - public TemperatureFilter() { - } + public TemperatureFilter() { } /** * @param scale Float, between 0 and 1, with 0 indicating cool, and 1 @@ -33,13 +29,11 @@ public class TemperatureFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - String scaleString = "scale = " + (2.0f * scale - 1.0f) + ";\n"; - - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" - + " float scale;\n" + + "float scale;\n" + "varying vec2 vTextureCoord;\n" + "void main() {\n" // Parameters that were created above + scaleString @@ -52,10 +46,10 @@ public class TemperatureFilter extends BaseFilter { + " }\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"; - - return shader; + + " new_color /= max_value;\n" + + " } \n" + + " gl_FragColor = vec4(new_color, color.a);\n" + + "}\n"; } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TintFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TintFilter.java index 67f1f9f2..8e07797e 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TintFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/TintFilter.java @@ -11,11 +11,7 @@ import androidx.annotation.NonNull; public class TintFilter extends BaseFilter { private int mTint = 0xFFFF0000; - /** - * Initialize Effect - */ - public TintFilter() { - } + public TintFilter() { } public void setTintColor(int color) { this.mTint = color; @@ -28,21 +24,21 @@ public class TintFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - float color_ratio[] = {0.21f, 0.71f, 0.07f}; - String color_ratioString[] = new String[3]; + float[] color_ratio = {0.21f, 0.71f, 0.07f}; + String[] color_ratioString = new String[3]; color_ratioString[0] = "color_ratio[0] = " + color_ratio[0] + ";\n"; 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, + float[] tint_color = {Color.red(mTint) / 255f, Color.green(mTint) / 255f, Color.blue(mTint) / 255f}; - String tintString[] = new String[3]; + String[] tintString = new String[3]; tintString[0] = "tint[0] = " + tint_color[0] + ";\n"; tintString[1] = "tint[1] = " + tint_color[1] + ";\n"; tintString[2] = "tint[2] = " + tint_color[2] + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + " vec3 tint;\n" @@ -60,7 +56,5 @@ public class TintFilter extends BaseFilter { + " 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"; - return shader; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/VignetteFilter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/VignetteFilter.java index 1d861225..0d306f2f 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/filters/VignetteFilter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/filters/VignetteFilter.java @@ -7,13 +7,19 @@ import androidx.annotation.NonNull; * Applies lomo-camera style effect to your preview. */ public class VignetteFilter extends BaseFilter { + private float mScale = 0.85f; private float mShade = 0.5f; + private int mOutputWidth = 1; + private int mOutputHeight = 1; - /** - * Initialize Effect - */ - public VignetteFilter() { + public VignetteFilter() { } + + @Override + public void setOutputSize(int width, int height) { + super.setOutputSize(width, height); + mOutputWidth = width; + mOutputHeight = height; } /** @@ -45,32 +51,30 @@ public class VignetteFilter extends BaseFilter { @NonNull @Override public String getFragmentShader() { - float scale[] = new float[2]; - if (mPreviewingViewWidth > mPreviewingViewHeight) { + float[] scale = new float[2]; + if (mOutputWidth > mOutputHeight) { scale[0] = 1f; - scale[1] = ((float) mPreviewingViewHeight) / mPreviewingViewWidth; + scale[1] = ((float) mOutputHeight) / mOutputWidth; } else { - scale[0] = ((float) mPreviewingViewWidth) / mPreviewingViewHeight; + scale[0] = ((float) mOutputWidth) / mOutputHeight; scale[1] = 1f; } float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] * scale[1])) * 0.5f; - String scaleString[] = new String[2]; - + String[] scaleString = new String[2]; scaleString[0] = "scale[0] = " + scale[0] + ";\n"; scaleString[1] = "scale[1] = " + scale[1] + ";\n"; String inv_max_distString = "inv_max_dist = " + 1.0f / max_dist + ";\n"; String shadeString = "shade = " + mShade + ";\n"; - // 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 // less than 1/256 and will cause nothing. String rangeString = "range = " + (1.30f - (float) Math.sqrt(mScale) * 0.7f) + ";\n"; - String shader = "#extension GL_OES_EGL_image_external : require\n" + return "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + " float range;\n" @@ -92,8 +96,5 @@ public class VignetteFilter extends BaseFilter { + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + " gl_FragColor = vec4(color.rgb * lumen, color.a);\n" + "}\n"; - - return shader; - } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglElement.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlUtils.java similarity index 74% rename from cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglElement.java rename to cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlUtils.java index 5be000fa..c5af965b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglElement.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/GlUtils.java @@ -1,27 +1,29 @@ -package com.otaliastudios.cameraview.internal.egl; +package com.otaliastudios.cameraview.internal; import android.opengl.GLES20; import android.opengl.Matrix; +import androidx.annotation.NonNull; + import com.otaliastudios.cameraview.CameraLogger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; -class EglElement { +public class GlUtils { - private final static CameraLogger LOG = CameraLogger.create(EglElement.class.getSimpleName()); + private final static String TAG = GlUtils.class.getSimpleName(); + private final static CameraLogger LOG = CameraLogger.create(TAG); // Identity matrix for general use. - protected static final float[] IDENTITY_MATRIX = new float[16]; + public static final float[] IDENTITY_MATRIX = new float[16]; static { Matrix.setIdentityM(IDENTITY_MATRIX, 0); } - // Check for GLES errors. - protected static void check(String opName) { + public static void checkError(@NonNull String opName) { int error = GLES20.glGetError(); if (error != GLES20.GL_NO_ERROR) { String message = LOG.e("Error during", opName, "glError 0x", Integer.toHexString(error)); @@ -29,18 +31,17 @@ class EglElement { } } - // Check for valid location. - protected static void checkLocation(int location, String label) { + public static void checkLocation(int location, @NonNull String name) { if (location < 0) { - String message = LOG.e("Unable to locate", label, "in program"); + String message = LOG.e("Unable to locate", name, "in program"); throw new RuntimeException(message); } } - // Compiles the given shader, returns a handle. - protected static int loadShader(int shaderType, String source) { + @SuppressWarnings("WeakerAccess") + public static int loadShader(int shaderType, @NonNull String source) { int shader = GLES20.glCreateShader(shaderType); - check("glCreateShader type=" + shaderType); + checkError("glCreateShader type=" + shaderType); GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); int[] compiled = new int[1]; @@ -54,21 +55,21 @@ class EglElement { } // Creates a program with given vertex shader and pixel shader. - protected static int createProgram(String vertexSource, String fragmentSource) { + public static int createProgram(@NonNull String vertexSource, @NonNull String fragmentSource) { int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) return 0; int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) return 0; int program = GLES20.glCreateProgram(); - check("glCreateProgram"); + checkError("glCreateProgram"); if (program == 0) { LOG.e("Could not create program"); } GLES20.glAttachShader(program, vertexShader); - check("glAttachShader"); + checkError("glAttachShader"); GLES20.glAttachShader(program, pixelShader); - check("glAttachShader"); + checkError("glAttachShader"); GLES20.glLinkProgram(program); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); @@ -81,7 +82,7 @@ class EglElement { } // Allocates a direct float buffer, and populates it with the float array data. - protected static FloatBuffer floatBuffer(float[] coords) { + public static FloatBuffer floatBuffer(@NonNull float[] coords) { // Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it. ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * 4); bb.order(ByteOrder.nativeOrder()); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java index de2919fa..9ec4315a 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglBaseSurface.java @@ -25,6 +25,7 @@ import androidx.annotation.RequiresApi; import android.util.Log; import com.otaliastudios.cameraview.CameraLogger; +import com.otaliastudios.cameraview.internal.GlUtils; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; @@ -40,7 +41,7 @@ import java.nio.ByteOrder; * There can be multiple surfaces associated with a single context. */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) -public class EglBaseSurface extends EglElement { +public class EglBaseSurface { protected static final String TAG = EglBaseSurface.class.getSimpleName(); private final static CameraLogger LOG = CameraLogger.create(TAG); @@ -187,7 +188,7 @@ public class EglBaseSurface extends EglElement { buf.order(ByteOrder.LITTLE_ENDIAN); GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); - check("glReadPixels"); + GlUtils.checkError("glReadPixels"); buf.rewind(); BufferedOutputStream bos = null; @@ -229,7 +230,7 @@ public class EglBaseSurface extends EglElement { ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); buf.order(ByteOrder.LITTLE_ENDIAN); GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); - check("glReadPixels"); + GlUtils.checkError("glReadPixels"); buf.rewind(); ByteArrayOutputStream bos = new ByteArrayOutputStream(buf.array().length); 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 a1fa2eaf..bcec19bc 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 @@ -9,51 +9,17 @@ import androidx.annotation.NonNull; import com.otaliastudios.cameraview.CameraLogger; import com.otaliastudios.cameraview.filters.Filter; import com.otaliastudios.cameraview.filters.NoFilter; +import com.otaliastudios.cameraview.internal.GlUtils; -import java.nio.FloatBuffer; -/** - * This is a mix of 3 grafika classes, FullFrameRect, Texture2dProgram, Drawable2d. - */ -public class EglViewport extends EglElement { +public class EglViewport { private final static CameraLogger LOG = CameraLogger.create(EglViewport.class.getSimpleName()); - // Stuff from Drawable2d.FULL_RECTANGLE - // A full square, extending from -1 to +1 in both dimensions. - // When the model/view/projection matrix is identity, this will exactly cover the viewport. - private static final float[] FULL_RECTANGLE_COORDS = { - -1.0f, -1.0f, // 0 bottom left - 1.0f, -1.0f, // 1 bottom right - -1.0f, 1.0f, // 2 top left - 1.0f, 1.0f, // 3 top right - }; - - // Stuff from Drawable2d.FULL_RECTANGLE - // A full square, extending from -1 to +1 in both dimensions. - private static final float[] FULL_RECTANGLE_TEX_COORDS = { - 0.0f, 0.0f, // 0 bottom left - 1.0f, 0.0f, // 1 bottom right - 0.0f, 1.0f, // 2 top left - 1.0f, 1.0f // 3 top right - }; - - // Stuff from Drawable2d.FULL_RECTANGLE - private final static int VERTEX_COUNT = FULL_RECTANGLE_COORDS.length / 2; - private FloatBuffer mVertexCoordinatesArray = floatBuffer(FULL_RECTANGLE_COORDS); - private FloatBuffer mTextureCoordinatesArray = floatBuffer(FULL_RECTANGLE_TEX_COORDS); - - // Stuff from Texture2dProgram private int mProgramHandle = -1; private int mTextureTarget; private int mTextureUnit; - // Program attributes - private int muMVPMatrixLocation; - private int muTexMatrixLocation; - private int maPositionLocation; - private int maTextureCoordLocation; - private Filter mFilter; private boolean mFilterChanged = false; @@ -70,19 +36,13 @@ public class EglViewport extends EglElement { private void createProgram() { release(); // Release old program if present. - mProgramHandle = createProgram(mFilter.getVertexShader(), mFilter.getFragmentShader()); - maPositionLocation = GLES20.glGetAttribLocation(mProgramHandle, mFilter.getPositionVariableName()); - checkLocation(maPositionLocation, mFilter.getPositionVariableName()); - maTextureCoordLocation = GLES20.glGetAttribLocation(mProgramHandle, mFilter.getTexttureCoordinateVariableName()); - checkLocation(maTextureCoordLocation, mFilter.getTexttureCoordinateVariableName()); - muMVPMatrixLocation = GLES20.glGetUniformLocation(mProgramHandle, mFilter.getMVPMatrixVariableName()); - checkLocation(muMVPMatrixLocation, mFilter.getMVPMatrixVariableName()); - muTexMatrixLocation = GLES20.glGetUniformLocation(mProgramHandle, mFilter.getTextureMatrixVariableName()); - checkLocation(muTexMatrixLocation, mFilter.getTextureMatrixVariableName()); + mProgramHandle = GlUtils.createProgram(mFilter.getVertexShader(), mFilter.getFragmentShader()); + mFilter.onCreate(mProgramHandle); } public void release() { if (mProgramHandle != -1) { + mFilter.onDestroy(); GLES20.glDeleteProgram(mProgramHandle); mProgramHandle = -1; } @@ -91,18 +51,18 @@ public class EglViewport extends EglElement { public int createTexture() { int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); - check("glGenTextures"); + GlUtils.checkError("glGenTextures"); int texId = textures[0]; GLES20.glActiveTexture(mTextureUnit); GLES20.glBindTexture(mTextureTarget, texId); - check("glBindTexture " + texId); + GlUtils.checkError("glBindTexture " + texId); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - check("glTexParameter"); + GlUtils.checkError("glTexParameter"); return texId; } @@ -113,60 +73,23 @@ public class EglViewport extends EglElement { } public void drawFrame(int textureId, float[] textureMatrix) { - drawFrame(textureId, textureMatrix, - mVertexCoordinatesArray, - mTextureCoordinatesArray); - } - - private void drawFrame(int textureId, float[] textureMatrix, - FloatBuffer vertexBuffer, - FloatBuffer texBuffer) { - if (mFilterChanged) { createProgram(); mFilterChanged = false; } - check("draw start"); + GlUtils.checkError("draw start"); - // Select the program. + // Select the program and the active texture. GLES20.glUseProgram(mProgramHandle); - check("glUseProgram"); - - // Set the texture. + GlUtils.checkError("glUseProgram"); GLES20.glActiveTexture(mTextureUnit); GLES20.glBindTexture(mTextureTarget, textureId); - // Copy the model / view / projection matrix over. - GLES20.glUniformMatrix4fv(muMVPMatrixLocation, 1, false, IDENTITY_MATRIX, 0); - check("glUniformMatrix4fv"); - - // Copy the texture transformation matrix over. - GLES20.glUniformMatrix4fv(muTexMatrixLocation, 1, false, textureMatrix, 0); - check("glUniformMatrix4fv"); - - // Enable the "aPosition" vertex attribute. - // Connect vertexBuffer to "aPosition". - GLES20.glEnableVertexAttribArray(maPositionLocation); - check("glEnableVertexAttribArray"); - GLES20.glVertexAttribPointer(maPositionLocation, 2, GLES20.GL_FLOAT, false, 8, vertexBuffer); - check("glVertexAttribPointer"); - - // Enable the "aTextureCoord" vertex attribute. - // Connect texBuffer to "aTextureCoord". - GLES20.glEnableVertexAttribArray(maTextureCoordLocation); - check("glEnableVertexAttribArray"); - GLES20.glVertexAttribPointer(maTextureCoordLocation, 2, GLES20.GL_FLOAT, false, 8, texBuffer); - check("glVertexAttribPointer"); - - - // Draw the rect. - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_COUNT); - check("glDrawArrays"); + // Draw. + mFilter.draw(textureMatrix); - // Done -- disable vertex array, texture, and program. - GLES20.glDisableVertexAttribArray(maPositionLocation); - GLES20.glDisableVertexAttribArray(maTextureCoordLocation); + // Release. GLES20.glBindTexture(mTextureTarget, 0); GLES20.glUseProgram(0); }