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 54114c9d..e015cb7b 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 @@ -5,6 +5,8 @@ import android.opengl.GLES11Ext; import android.opengl.GLES20; import com.otaliastudios.cameraview.CameraLogger; +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; +import com.otaliastudios.cameraview.shadereffects.effects.BlackAndWhiteEffect; import java.nio.FloatBuffer; @@ -76,7 +78,12 @@ public class EglViewport extends EglElement { public EglViewport() { mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES; - mProgramHandle = createProgram(SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER); + + //mProgramHandle = createProgram(SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER); + + ShaderInterface effect = new BlackAndWhiteEffect(); + mProgramHandle = createProgram(SIMPLE_VERTEX_SHADER, effect.getShader(null)); + maPositionLocation = GLES20.glGetAttribLocation(mProgramHandle, "aPosition"); checkLocation(maPositionLocation, "aPosition"); maTextureCoordLocation = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord"); diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/ShaderInterface.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/ShaderInterface.java new file mode 100644 index 00000000..09a39c24 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/ShaderInterface.java @@ -0,0 +1,20 @@ +package com.otaliastudios.cameraview.shadereffects; + +import android.opengl.GLSurfaceView; + +/** + * An interface that every effect must implement so that there is a common + * getShader method that every effect class is force to override + */ +public interface ShaderInterface { + /** + * Returns Shader code + * + * @param mGlSurfaceView + * send this for every shader but this will only be used when the + * shader needs it. + * @return complete shader code in C + */ + public String getShader(GLSurfaceView mGlSurfaceView); + +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/AutoFixEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/AutoFixEffect.java new file mode 100644 index 00000000..3e9efcce --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/AutoFixEffect.java @@ -0,0 +1,88 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Attempts to auto-fix the preview based on histogram equalization. + */ +public class AutoFixEffect implements ShaderInterface { + private float scale; + + /** + * Initialize Effect + * + * @param scale Float, between 0 and 1. Zero means no adjustment, while 1 + * indicates the maximum amount of adjustment. + */ + public AutoFixEffect(float scale) { + if (scale < 0.0f) + scale = 0.0f; + if (scale > 1.0f) + scale = 1.0f; + + this.scale = scale; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String 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" + + " 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"; + + return shader; + + } +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/BlackAndWhiteEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/BlackAndWhiteEffect.java new file mode 100644 index 00000000..cdea63b3 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/BlackAndWhiteEffect.java @@ -0,0 +1,34 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Converts the preview into black and white colors + */ +public class BlackAndWhiteEffect implements ShaderInterface { + /** + * Initialize Effect + */ + public BlackAndWhiteEffect() { + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String 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"; + + return shader; + + } +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/BrightnessEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/BrightnessEffect.java new file mode 100644 index 00000000..0d399834 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/BrightnessEffect.java @@ -0,0 +1,43 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Adjusts the brightness of the preview. + */ +public class BrightnessEffect implements ShaderInterface { + private float brightnessValue; + + /** + * Initialize Effect + * + * @param brightnessvalue Range should be between 0.1- 2.0 with 1.0 being normal. + */ + public BrightnessEffect(float brightnessvalue) { + if (brightnessvalue < 0.1f) + brightnessvalue = 0.1f; + if (brightnessvalue > 2.0f) + brightnessvalue = 2.0f; + + this.brightnessValue = brightnessvalue; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String shader = "#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" + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " gl_FragColor = brightness * color;\n" + "}\n"; + + return shader; + + } + +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/ContrastEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/ContrastEffect.java new file mode 100644 index 00000000..6dddb63a --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/ContrastEffect.java @@ -0,0 +1,41 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; +/** + * Adjusts the contrast of the preview. + */ +public class ContrastEffect implements ShaderInterface { + private float contrast; + + /** + * Initialize Effect + * + * @param contrast Range should be between 0.1- 2.0 with 1.0 being normal. + */ + public ContrastEffect(float contrast) { + if (contrast < 0.1f) + contrast = 0.1f; + if (contrast > 2.0f) + contrast = 2.0f; + + this.contrast = contrast; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String shader = "#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"; + return shader; + + } + +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/CrossProcessEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/CrossProcessEffect.java new file mode 100644 index 00000000..d576901d --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/CrossProcessEffect.java @@ -0,0 +1,45 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Applies a cross process effect on preview, in which the red and green channels + * are enhanced while the blue channel is restricted. + */ +public class CrossProcessEffect implements ShaderInterface { + + /** + * Initialize Effect + */ + public CrossProcessEffect() { + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String 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"; + + return shader; + + } + +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/DocumentaryEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/DocumentaryEffect.java new file mode 100644 index 00000000..8eb0e713 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/DocumentaryEffect.java @@ -0,0 +1,114 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +import java.util.Date; +import java.util.Random; + +/** + * Applies black and white documentary style effect on preview. + */ +public class DocumentaryEffect implements ShaderInterface { + private int mWidth; + private int mHeight; + private Random mRandom; + + /** + * Initialize Effect + */ + public DocumentaryEffect() { + + } + + /** + * Init all values that will be used by this shader. + * + * @param mGlSurfaceView which is responsible for displaying your video + */ + private void initValues(GLSurfaceView mGlSurfaceView) { + mWidth = mGlSurfaceView.getWidth(); + mHeight = mGlSurfaceView.getHeight(); + mRandom = new Random(new Date().getTime()); + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + initValues(mGlSurfaceView); + 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; + } + 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"; + + String shader = "#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" + + "varying vec2 vTextureCoord;\n" + + "float rand(vec2 loc) {\n" + + " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" + + " float theta2 = dot(loc, vec2(12.0, 78.0));\n" + + " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" + + + // keep value of part1 in range: (2^-14 to 2^14). + " float temp = mod(197.0 * value, 1.0) + value;\n" + + " float part1 = mod(220.0 * temp, 1.0) + temp;\n" + + " float part2 = value * 0.5453;\n" + + " float part3 = cos(theta1 + theta2) * 0.43758;\n" + + " return fract(part1 + part2 + part3);\n" + + "}\n" + + "void main() {\n" + // Parameters that were created above + + scaleString[0] + + scaleString[1] + + seedString[0] + + seedString[1] + + inv_max_distString + + stepsizeString + + // black white + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " float dither = rand(vTextureCoord + seed);\n" + + " vec3 xform = clamp(2.0 * color.rgb, 0.0, 1.0);\n" + + " vec3 temp = clamp(2.0 * (color.rgb + stepsize), 0.0, 1.0);\n" + + " vec3 new_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" + + + // grayscale + " float gray = dot(new_color, vec3(0.299, 0.587, 0.114));\n" + + " new_color = vec3(gray, gray, gray);\n" + + + // vignette + " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n" + + " float dist = length(coord * scale);\n" + + " float lumen = 0.85 / (1.0 + exp((dist * inv_max_dist - 0.83) * 20.0)) + 0.15;\n" + + " gl_FragColor = vec4(new_color * lumen, color.a);\n" + + "}\n"; + + return shader; + + } +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/DuotoneEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/DuotoneEffect.java new file mode 100644 index 00000000..9ef654af --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/DuotoneEffect.java @@ -0,0 +1,71 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.graphics.Color; +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Representation of preview using only two color tones. + */ +public class DuotoneEffect implements ShaderInterface { + // Default values + private int mFirstColor = Color.MAGENTA; + private int mSecondColor = Color.YELLOW; + + /** + * Initialize effect + * + * @param mFirstColor Integer, representing an ARGB color with 8 bits per channel. + * May be created using Color class. + * @param mSecondColor Integer, representing an ARGB color with 8 bits per channel. + * May be created using Color class. + */ + public DuotoneEffect(int mFirstColor, int mSecondColor) { + this.mFirstColor = mFirstColor; + this.mSecondColor = mSecondColor; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + float first[] = {Color.red(mFirstColor) / 255f, + Color.green(mFirstColor) / 255f, Color.blue(mFirstColor) / 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]; + + firstColorString[0] = "first[0] = " + first[0] + ";\n"; + firstColorString[1] = "first[1] = " + first[1] + ";\n"; + firstColorString[2] = "first[2] = " + first[2] + ";\n"; + + secondColorString[0] = "second[0] = " + second[0] + ";\n"; + secondColorString[1] = "second[1] = " + second[1] + ";\n"; + secondColorString[2] = "second[2] = " + second[2] + ";\n"; + + String shader = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "uniform samplerExternalOES sTexture;\n" + + " vec3 first;\n" + + " vec3 second;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + // Parameters that were created above + + firstColorString[0] + + firstColorString[1] + + firstColorString[2] + + secondColorString[0] + + secondColorString[1] + + secondColorString[2] + + + " vec4 color = texture2D(sTexture, vTextureCoord);\n" + + " float energy = (color.r + color.g + color.b) * 0.3333;\n" + + " vec3 new_color = (1.0 - energy) * first + energy * second;\n" + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n"; + + return shader; + + } +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/FillLightEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/FillLightEffect.java new file mode 100644 index 00000000..99da3d2c --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/FillLightEffect.java @@ -0,0 +1,64 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Applies back-light filling to the preview. + */ +public class FillLightEffect implements ShaderInterface { + private float strength = 0f; + + /** + * Initialize Effect + * + * @param strength Float, between 0 and 1. 0 means no change. + */ + public FillLightEffect(float strength) { + if (strength < 0.0f) + strength = 0f; + if (strength > 1.0f) + strength = 1f; + + this.strength = strength; + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + float fade_gamma = 0.3f; + float amt = 1.0f - strength; + float mult = 1.0f / (amt * 0.7f + 0.3f); + float faded = fade_gamma + (1.0f - fade_gamma) * mult; + float igamma = 1.0f / faded; + + String multString = "mult = " + mult + ";\n"; + String igammaString = "igamma = " + igamma + ";\n"; + + String shader = "#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" + // 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" + + " float backmask = (1.0 - lightmask);\n" + + " vec3 ones = vec3(1.0, 1.0, 1.0);\n" + + " 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; + + } + +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GammaEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GammaEffect.java new file mode 100644 index 00000000..c18293d0 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GammaEffect.java @@ -0,0 +1,46 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Apply Gamma Effect on preview being played + */ +public class GammaEffect implements ShaderInterface { + private float gammaValue; + + /** + * Initialize Effect + * + * @param gammaValue Range should be between 0.0 - 2.0 with 1.0 being normal. + */ + public GammaEffect(float gammaValue) { + if (gammaValue < 0.0f) + gammaValue = 0.0f; + if (gammaValue > 2.0f) + gammaValue = 2.0f; + this.gammaValue = gammaValue; + + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String shader = "#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" + + + "}\n"; + + return shader; + } +} \ No newline at end of file diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GrainEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GrainEffect.java new file mode 100644 index 00000000..26e7a3b9 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GrainEffect.java @@ -0,0 +1,103 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +import java.util.Date; +import java.util.Random; + +/** + * Applies film grain effect to preview. + */ +public class GrainEffect implements ShaderInterface { + private int mWidth; + private int mHeight; + private float strength; + private Random mRandom; + + /** + * Initialize Effect + * + * @param strength Float, between 0 and 1. Zero means no distortion, while 1 + * indicates the maximum amount of adjustment. + */ + public GrainEffect(float strength) { + if (strength < 0.0f) + strength = 0.0f; + if (strength > 1.0f) + strength = 1.0f; + this.strength = strength; + } + + /** + * Init all values that will be used by this shader. + * + * @param mGlSurfaceView which is responsible for displaying your video + */ + private void initValues(GLSurfaceView mGlSurfaceView) { + mWidth = mGlSurfaceView.getWidth(); + mHeight = mGlSurfaceView.getHeight(); + mRandom = new Random(new Date().getTime()); + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + initValues(mGlSurfaceView); + + float seed[] = {mRandom.nextFloat(), mRandom.nextFloat()}; + String scaleString = "scale = " + strength + ";\n"; + String seedString[] = new String[2]; + seedString[0] = "seed[0] = " + seed[0] + ";\n"; + seedString[1] = "seed[1] = " + seed[1] + ";\n"; + String stepX = "stepX = " + 0.5f / mWidth + ";\n"; + String stepY = "stepY = " + 0.5f / mHeight + ";\n"; + + // locString[1] = "loc[1] = loc[1]+" + seedString[1] + ";\n"; + + String shader = "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + " vec2 seed;\n" + + "varying vec2 vTextureCoord;\n" + + "uniform samplerExternalOES tex_sampler_0;\n" + + "uniform samplerExternalOES tex_sampler_1;\n" + + "float scale;\n" + + " float stepX;\n" + + " float stepY;\n" + + "float rand(vec2 loc) {\n" + + " float theta1 = dot(loc, vec2(0.9898, 0.233));\n" + + " float theta2 = dot(loc, vec2(12.0, 78.0));\n" + + " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n" + + + // keep value of part1 in range: (2^-14 to 2^14). + " float temp = mod(197.0 * value, 1.0) + value;\n" + + " float part1 = mod(220.0 * temp, 1.0) + temp;\n" + + " float part2 = value * 0.5453;\n" + + " float part3 = cos(theta1 + theta2) * 0.43758;\n" + + " float sum = (part1 + part2 + part3);\n" + + " return fract(sum)*scale;\n" + + "}\n" + + "void main() {\n" + // Parameters that were created above + + seedString[0] + + seedString[1] + + scaleString + + stepX + + stepY + + " float noise = texture2D(tex_sampler_1, vTextureCoord + vec2(-stepX, -stepY)).r * 0.224;\n" + + " noise += texture2D(tex_sampler_1, vTextureCoord + vec2(-stepX, stepY)).r * 0.224;\n" + + " noise += texture2D(tex_sampler_1, vTextureCoord + vec2(stepX, -stepY)).r * 0.224;\n" + + " noise += texture2D(tex_sampler_1, vTextureCoord + vec2(stepX, stepY)).r * 0.224;\n" + + " noise += 0.4448;\n" + + " noise *= scale;\n" + + " vec4 color = texture2D(tex_sampler_0, vTextureCoord);\n" + + " float energy = 0.33333 * color.r + 0.33333 * color.g + 0.33333 * color.b;\n" + + " float mask = (1.0 - sqrt(energy));\n" + + " float weight = 1.0 - 1.333 * mask * noise;\n" + + " 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/shadereffects/effects/GreyScaleEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GreyScaleEffect.java new file mode 100644 index 00000000..2f3ed4de --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/GreyScaleEffect.java @@ -0,0 +1,32 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Converts preview to GreyScale. + */ +public class GreyScaleEffect implements ShaderInterface { + /** + * Initialize Effect + */ + public GreyScaleEffect() { + } + + @Override + public String getShader(GLSurfaceView mGlSurfaceView) { + + String 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" + + " 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; + + } +} diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/HueEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/HueEffect.java new file mode 100644 index 00000000..08582505 --- /dev/null +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/HueEffect.java @@ -0,0 +1,70 @@ +package com.otaliastudios.cameraview.shadereffects.effects; + +import android.opengl.GLSurfaceView; + +import com.otaliastudios.cameraview.shadereffects.ShaderInterface; + +/** + * Apply Hue effect on the preview + */ +public class HueEffect implements ShaderInterface { + float hueValue; + + /** + * Initialize Effect + *
+ *
+ *
+ * @param hueDegrees Range of value should be between 0 to 360 degrees as described in the image above
+ */
+ public HueEffect(float hueDegrees) {
+// manipulating input value so that we can map it on 360 degree circle
+ hueValue = ((hueDegrees - 45) / 45f + 0.5f) * -1;
+
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+
+ String shader = "#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"
+
+ + "}\n";
+
+ return shader;
+ }
+}
\ No newline at end of file
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/InvertColorsEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/InvertColorsEffect.java
new file mode 100644
index 00000000..ed406e28
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/InvertColorsEffect.java
@@ -0,0 +1,34 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Inverts the preview colors. This can also be known as negative Effect.
+ */
+public class InvertColorsEffect implements ShaderInterface {
+ /**
+ * Initialize Effect
+ */
+ public InvertColorsEffect() {
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+
+ String 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 = (1.0 - color.r) / 1.0;\n"
+ + " float colorG = (1.0 - color.g) / 1.0;\n"
+ + " float colorB = (1.0 - color.b) / 1.0;\n"
+ + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n"
+ + "}\n";
+
+ return shader;
+
+ }
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/LamoishEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/LamoishEffect.java
new file mode 100644
index 00000000..0f1f8748
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/LamoishEffect.java
@@ -0,0 +1,158 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * Applies lomo-camera style effect to preview.
+ */
+public class LamoishEffect implements ShaderInterface {
+ private int mWidth;
+ private int mHeight;
+ private Random mRandom;
+
+ /**
+ * Initialize Effect
+ */
+ public LamoishEffect() {
+
+ }
+
+ /**
+ * Init all values that will be used by this shader.
+ *
+ * @param mGlSurfaceView which is responsible for displaying your video
+ */
+ private void initValues(GLSurfaceView mGlSurfaceView) {
+ mWidth = mGlSurfaceView.getWidth();
+ mHeight = mGlSurfaceView.getHeight();
+ mRandom = new Random(new Date().getTime());
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+ initValues(mGlSurfaceView);
+ 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;
+ }
+ 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";
+ String stepsizeXString = "stepsizeX = " + 1.0f / mWidth + ";\n";
+ String stepsizeYString = "stepsizeY = " + 1.0f / mHeight + ";\n";
+
+ String shader = "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n"
+ + "uniform samplerExternalOES sTexture;\n"
+ + " vec2 seed;\n"
+ + " float stepsizeX;\n"
+ + " float stepsizeY;\n"
+ + " float stepsize;\n"
+ + " vec2 scale;\n"
+ + " float inv_max_dist;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "float rand(vec2 loc) {\n"
+ + " float theta1 = dot(loc, vec2(0.9898, 0.233));\n"
+ + " float theta2 = dot(loc, vec2(12.0, 78.0));\n"
+ + " float value = cos(theta1) * sin(theta2) + sin(theta1) * cos(theta2);\n"
+ +
+ // keep value of part1 in range: (2^-14 to 2^14).
+ " float temp = mod(197.0 * value, 1.0) + value;\n"
+ + " float part1 = mod(220.0 * temp, 1.0) + temp;\n"
+ + " float part2 = value * 0.5453;\n"
+ + " float part3 = cos(theta1 + theta2) * 0.43758;\n"
+ + " return fract(part1 + part2 + part3);\n" + "}\n"
+ + "void main() {\n"
+ // Parameters that were created above
+ + scaleString[0]
+ + scaleString[1]
+ + seedString[0]
+ + seedString[1]
+ + inv_max_distString
+ + stepsizeString
+ + stepsizeXString
+ + stepsizeYString
+ // sharpen
+ + " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n"
+ + " vec2 coord;\n"
+ + " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ + " coord.x = vTextureCoord.x - 0.5 * stepsizeX;\n"
+ + " coord.y = vTextureCoord.y - stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " coord.x = vTextureCoord.x - stepsizeX;\n"
+ + " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " coord.x = vTextureCoord.x + stepsizeX;\n"
+ + " coord.y = vTextureCoord.y - 0.5 * stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " coord.x = vTextureCoord.x + stepsizeX;\n"
+ + " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " vec3 s_color = vec3(color.rgb + 0.3 * nbr_color);\n"
+ +
+ // cross process
+ " 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"
+ + " } else {\n"
+ + " value = 1.0 - s_color.r;\n"
+ + " }\n"
+ + " float red = 4.0 * value * value * value;\n"
+ + " if (s_color.r < 0.5) {\n"
+ + " c_color.r = red;\n"
+ + " } else {\n"
+ + " c_color.r = 1.0 - red;\n"
+ + " }\n"
+ + " if (s_color.g < 0.5) {\n"
+ + " value = s_color.g;\n"
+ + " } else {\n"
+ + " value = 1.0 - s_color.g;\n"
+ + " }\n"
+ + " float green = 2.0 * value * value;\n"
+ + " if (s_color.g < 0.5) {\n"
+ + " c_color.g = green;\n"
+ + " } else {\n"
+ + " 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"
+ + " 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"
+ + " 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/shadereffects/effects/NoEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/NoEffect.java
new file mode 100644
index 00000000..f5872662
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/NoEffect.java
@@ -0,0 +1,31 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Displays the normal preview without any effect.
+ */
+public class NoEffect implements ShaderInterface {
+ /**
+ * Initialize
+ */
+ public NoEffect() {
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+
+ String shader = "#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";
+
+ return shader;
+
+ }
+}
\ No newline at end of file
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/PosterizeEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/PosterizeEffect.java
new file mode 100644
index 00000000..414241be
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/PosterizeEffect.java
@@ -0,0 +1,33 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Applies Posterization effect to Preview.
+ */
+public class PosterizeEffect implements ShaderInterface {
+ /**
+ * Initialize Effect
+ */
+ public PosterizeEffect() {
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+
+ String 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 pcolor;\n"
+ + " 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;
+
+ }
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SaturationEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SaturationEffect.java
new file mode 100644
index 00000000..4f919d19
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SaturationEffect.java
@@ -0,0 +1,86 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Adjusts color saturation of preview.
+ */
+public class SaturationEffect implements ShaderInterface {
+ private float scale = 0f;
+
+ /**
+ * Initialize Effect
+ *
+ * @param scale Float, between -1 and 1. 0 means no change, while -1 indicates
+ * full desaturation, i.e. grayscale.
+ */
+ public SaturationEffect(float scale) {
+
+ this.scale = scale;
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+ float shift = 1.0f / 255.0f;
+ float weights[] = {2f / 8f, 5f / 8f, 1f / 8f};
+ float exponents[] = new float[3];
+
+ String weightsString[] = new String[3];
+ String exponentsString[] = new String[3];
+ exponentsString[0] = "";
+ exponentsString[1] = "";
+ exponentsString[2] = "";
+ String scaleString = "";
+
+ if (scale > 0.0f) {
+ exponents[0] = (0.9f * scale) + 1.0f;
+ exponents[1] = (2.1f * scale) + 1.0f;
+ exponents[2] = (2.7f * scale) + 1.0f;
+ exponentsString[0] = "exponents[0] = " + exponents[0] + ";\n";
+ exponentsString[1] = "exponents[1] = " + exponents[1] + ";\n";
+ exponentsString[2] = "exponents[2] = " + exponents[2] + ";\n";
+ } else
+ scaleString = "scale = " + (1.0f + scale) + ";\n";
+
+ weightsString[0] = "weights[0] = " + weights[0] + ";\n";
+ weightsString[1] = "weights[1] = " + weights[1] + ";\n";
+ weightsString[2] = "weights[2] = " + weights[2] + ";\n";
+ String shiftString = "shift = " + shift + ";\n";
+
+ String shader = "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n"
+ + "uniform samplerExternalOES sTexture;\n" + " float scale;\n"
+ + " float shift;\n" + " vec3 weights;\n" + " vec3 exponents;\n"
+ + "varying vec2 vTextureCoord;\n" + "void main() {\n"
+ // Parameters that were created above
+ + weightsString[0]
+ + weightsString[1]
+ + weightsString[2]
+ + shiftString
+ + scaleString
+ + " vec4 oldcolor = texture2D(sTexture, vTextureCoord);\n"
+ + " float kv = dot(oldcolor.rgb, weights) + shift;\n"
+ + " vec3 new_color = scale * oldcolor.rgb + (1.0 - scale) * kv;\n"
+ + " gl_FragColor= vec4(new_color, oldcolor.a);\n"
+ // Parameters that were created above
+ + weightsString[0]
+ + weightsString[1]
+ + weightsString[2]
+ + exponentsString[0]
+ + exponentsString[1]
+ + exponentsString[2]
+ + " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ + " float de = dot(color.rgb, weights);\n"
+ + " float inv_de = 1.0 / de;\n"
+ + " vec3 verynew_color = de * pow(color.rgb * inv_de, exponents);\n"
+ + " float max_color = max(max(max(verynew_color.r, verynew_color.g), verynew_color.b), 1.0);\n"
+ + " gl_FragColor = gl_FragColor+vec4(verynew_color / max_color, color.a);\n"
+ + "}\n";
+
+ return shader;
+
+ }
+
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SepiaEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SepiaEffect.java
new file mode 100644
index 00000000..5034b75e
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SepiaEffect.java
@@ -0,0 +1,49 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Converts preview to Sepia tone.
+ */
+public class SepiaEffect implements ShaderInterface {
+ /**
+ * Initialize Effect
+ */
+ public SepiaEffect() {
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+ 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];
+
+ matrixString[0] = " matrix[0][0]=" + weights[0] + ";\n";
+ matrixString[1] = " matrix[0][1]=" + weights[1] + ";\n";
+ matrixString[2] = " matrix[0][2]=" + weights[2] + ";\n";
+ matrixString[3] = " matrix[1][0]=" + weights[3] + ";\n";
+ matrixString[4] = " matrix[1][1]=" + weights[4] + ";\n";
+ matrixString[5] = " matrix[1][2]=" + weights[5] + ";\n";
+ matrixString[6] = " matrix[2][0]=" + weights[6] + ";\n";
+ 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"
+ + "precision mediump float;\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;
+
+ }
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SharpnessEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SharpnessEffect.java
new file mode 100644
index 00000000..494a6136
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/SharpnessEffect.java
@@ -0,0 +1,80 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Sharpens the preview.
+ */
+public class SharpnessEffect implements ShaderInterface {
+ private int mWidth;
+ private int mHeight;
+ private float scale = 0f;
+
+ /**
+ * Initialize Effect
+ *
+ * @param scale Float, between 0 and 1. 0 means no change.
+ */
+ public SharpnessEffect(float scale) {
+ if (scale < 0.0f)
+ scale = 0.0f;
+ if (scale > 1.0f)
+ scale = 1.0f;
+
+ this.scale = scale;
+ }
+
+ /**
+ * Init all values that will be used by this shader.
+ *
+ * @param mGlSurfaceView which is responsible for displaying your video
+ */
+ private void initValues(GLSurfaceView mGlSurfaceView) {
+ mWidth = mGlSurfaceView.getWidth();
+ mHeight = mGlSurfaceView.getHeight();
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+ initValues(mGlSurfaceView);
+
+ String stepsizeXString = "stepsizeX = " + 1.0f / mWidth + ";\n";
+ String stepsizeYString = "stepsizeY = " + 1.0f / mHeight + ";\n";
+ String scaleString = "scale = " + scale + ";\n";
+
+ String shader = "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n"
+ + "uniform samplerExternalOES sTexture;\n"
+ + " float scale;\n"
+ + " float stepsizeX;\n"
+ + " float stepsizeY;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ // Parameters that were created above
+ + stepsizeXString
+ + stepsizeYString
+ + scaleString
+ + " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n"
+ + " vec2 coord;\n"
+ + " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ + " coord.x = vTextureCoord.x - 0.5 * stepsizeX;\n"
+ + " coord.y = vTextureCoord.y - stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " coord.x = vTextureCoord.x - stepsizeX;\n"
+ + " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " coord.x = vTextureCoord.x + stepsizeX;\n"
+ + " coord.y = vTextureCoord.y - 0.5 * stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " coord.x = vTextureCoord.x + stepsizeX;\n"
+ + " coord.y = vTextureCoord.y + 0.5 * stepsizeY;\n"
+ + " nbr_color += texture2D(sTexture, coord).rgb - color.rgb;\n"
+ + " gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n"
+ + "}\n";
+
+ return shader;
+
+ }
+
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/TemperatureEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/TemperatureEffect.java
new file mode 100644
index 00000000..bf3e61b6
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/TemperatureEffect.java
@@ -0,0 +1,55 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+/**
+ * Adjusts color temperature of the preview.
+ */
+public class TemperatureEffect implements ShaderInterface {
+ private float scale = 0f;
+
+ /**
+ * Initialize Effect
+ *
+ * @param scale Float, between 0 and 1, with 0 indicating cool, and 1
+ * indicating warm. A value of of 0.5 indicates no change.
+ */
+ public TemperatureEffect(float scale) {
+ if (scale < 0.0f)
+ scale = 0.0f;
+ if (scale > 1.0f)
+ scale = 1.0f;
+ this.scale = scale;
+
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+
+ String scaleString = "scale = " + (2.0f * scale - 1.0f) + ";\n";
+
+ String shader = "#extension GL_OES_EGL_image_external : require\n"
+ + "precision mediump float;\n"
+ + "uniform samplerExternalOES sTexture;\n"
+ + " float scale;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n" // Parameters that were created above
+ + scaleString
+ + " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ + " vec3 new_color = color.rgb;\n"
+ + " new_color.r = color.r + color.r * ( 1.0 - color.r) * scale;\n"
+ + " new_color.b = color.b - color.b * ( 1.0 - color.b) * scale;\n"
+ + " if (scale > 0.0) { \n"
+ + " new_color.g = color.g + color.g * ( 1.0 - color.g) * scale * 0.25;\n"
+ + " }\n"
+ + " float max_value = max(new_color.r, max(new_color.g, new_color.b));\n"
+ + " if (max_value > 1.0) { \n"
+ + " new_color /= max_value;\n" + " } \n"
+ + " gl_FragColor = vec4(new_color, color.a);\n" + "}\n";
+
+ return shader;
+
+ }
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/TintEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/TintEffect.java
new file mode 100644
index 00000000..abfd6a7b
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/TintEffect.java
@@ -0,0 +1,63 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.graphics.Color;
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+
+/**
+ * Tints the preview with specified color..
+ */
+public class TintEffect implements ShaderInterface {
+ private int mTint = 0xFF0000FF;
+
+ /**
+ * Initialize Effect
+ *
+ * @param color Integer, representing an ARGB color with 8 bits per channel.
+ * May be created using Color class.
+ */
+ public TintEffect(int color) {
+ this.mTint = color;
+
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+ 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,
+ Color.green(mTint) / 255f, Color.blue(mTint) / 255f};
+
+ 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"
+ + "precision mediump float;\n"
+ + "uniform samplerExternalOES sTexture;\n"
+ + " vec3 tint;\n"
+ + " vec3 color_ratio;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ // Parameters that were created above
+ + color_ratioString[0]
+ + color_ratioString[1]
+ + color_ratioString[2]
+ + tintString[0]
+ + tintString[1]
+ + tintString[2]
+ + " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ + " float avg_color = dot(color_ratio, color.rgb);\n"
+ + " vec3 new_color = min(0.8 * avg_color + 0.2 * tint, 1.0);\n"
+ + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + "}\n";
+ return shader;
+
+ }
+}
diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/VignetteEffect.java b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/VignetteEffect.java
new file mode 100644
index 00000000..01792e42
--- /dev/null
+++ b/cameraview/src/main/java/com/otaliastudios/cameraview/shadereffects/effects/VignetteEffect.java
@@ -0,0 +1,95 @@
+package com.otaliastudios.cameraview.shadereffects.effects;
+
+import android.opengl.GLSurfaceView;
+
+import com.otaliastudios.cameraview.shadereffects.ShaderInterface;
+
+
+/**
+ * Applies lomo-camera style effect to your preview.
+ */
+public class VignetteEffect implements ShaderInterface {
+ private int mWidth = 0;
+ private int mHeight = 0;
+ private float mScale = 0f;
+ private final float mShade = 0.85f;
+
+ /**
+ * Initialize Effect
+ *
+ * @param scale Float, between 0 and 1. 0 means no change.
+ */
+ public VignetteEffect(float scale) {
+ if (scale < 0.0f)
+ scale = 0.0f;
+ if (scale > 1.0f)
+ scale = 1.0f;
+ this.mScale = scale;
+
+ }
+
+ /**
+ * Init all values that will be used by this shader.
+ *
+ * @param mGlSurfaceView which is responsible for displaying your preview
+ */
+ private void initValues(GLSurfaceView mGlSurfaceView) {
+ mWidth = mGlSurfaceView.getWidth();
+ mHeight = mGlSurfaceView.getHeight();
+ }
+
+ @Override
+ public String getShader(GLSurfaceView mGlSurfaceView) {
+ initValues(mGlSurfaceView);
+ 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;
+ }
+ float max_dist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1]
+ * scale[1])) * 0.5f;
+
+ 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
+ // 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"
+ + "precision mediump float;\n"
+ + "uniform samplerExternalOES sTexture;\n"
+ + " float range;\n"
+ + " float inv_max_dist;\n"
+ + " float shade;\n"
+ + " vec2 scale;\n"
+ + "varying vec2 vTextureCoord;\n"
+ + "void main() {\n"
+ // Parameters that were created above
+ + scaleString[0]
+ + scaleString[1]
+ + inv_max_distString
+ + shadeString
+ + rangeString
+ + " const float slope = 20.0;\n"
+ + " vec2 coord = vTextureCoord - vec2(0.5, 0.5);\n"
+ + " float dist = length(coord * scale);\n"
+ + " float lumen = shade / (1.0 + exp((dist * inv_max_dist - range) * slope)) + (1.0 - shade);\n"
+ + " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ + " gl_FragColor = vec4(color.rgb * lumen, color.a);\n"
+ + "}\n";
+
+ return shader;
+
+ }
+}