Update Gamma, Grain, Grayscale, Hue, InvertColors, Lomoish with onPreDraw

pull/535/head
Mattia Iavarone 6 years ago
parent 2d7d73ab08
commit c323586c55
  1. 55
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/GammaFilter.java
  2. 150
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrainFilter.java
  3. 20
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/GrayscaleFilter.java
  4. 110
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/HueFilter.java
  5. 25
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/InvertColorsFilter.java
  6. 244
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/LomoishFilter.java

@ -1,15 +1,29 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.internal.GlUtils;
/**
* Applies gamma correction to the frames.
*/
public class GammaFilter extends BaseFilter {
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "uniform float gamma;\n"
+ "void main() {\n"
+ " vec4 textureColor = texture2D(sTexture, vTextureCoord);\n"
+ " gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n"
+ "}\n";
private float gamma = 2.0f;
private int gammaLocation = -1;
@SuppressWarnings("WeakerAccess")
public GammaFilter() { }
@ -42,24 +56,37 @@ public class GammaFilter extends BaseFilter {
return gamma / 2.0f;
}
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
gammaLocation = GLES20.glGetUniformLocation(programHandle, "gamma");
GlUtils.checkLocation(gammaLocation, "gamma");
}
@Override
public void onDestroy() {
super.onDestroy();
gammaLocation = -1;
}
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
GLES20.glUniform1f(gammaLocation, gamma);
GlUtils.checkError("glUniform1f");
}
@Override
protected BaseFilter onCopy() {
GammaFilter filter = new GammaFilter();
filter.setGamma(getGamma());
return filter;
}
@NonNull
@Override
public String getFragmentShader() {
return "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "float gamma=" + gamma + ";\n"
+ "void main() {\n"
+ " vec4 textureColor = texture2D(sTexture, vTextureCoord);\n"
+ " gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n"
+ "}\n";
}
}

@ -1,10 +1,12 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.internal.GlUtils;
import java.util.Date;
import java.util.Random;
/**
@ -12,10 +14,51 @@ import java.util.Random;
*/
public class GrainFilter extends BaseFilter {
private final static Random RANDOM = new Random();
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "vec2 seed;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES tex_sampler_0;\n"
+ "uniform samplerExternalOES tex_sampler_1;\n"
+ "uniform float scale;\n"
+ "uniform float stepX;\n"
+ "uniform 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"
+ " seed[0] = " + RANDOM.nextFloat() + ";\n"
+ " seed[1] = " + RANDOM.nextFloat() + ";\n"
+ " 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";
private float strength = 0.5f;
private Random mRandom = new Random(new Date().getTime());
private int mOutputWidth = 1;
private int mOutputHeight = 1;
private int width = 1;
private int height = 1;
private int strengthLocation = -1;
private int stepXLocation = -1;
private int stepYLocation = -1;
@SuppressWarnings("WeakerAccess")
public GrainFilter() { }
@ -23,8 +66,8 @@ public class GrainFilter extends BaseFilter {
@Override
public void setSize(int width, int height) {
super.setSize(width, height);
mOutputWidth = width;
mOutputHeight = height;
this.width = width;
this.height = height;
}
/**
@ -52,68 +95,47 @@ public class GrainFilter extends BaseFilter {
return strength;
}
@Override
protected BaseFilter onCopy() {
GrainFilter filter = new GrainFilter();
filter.setStrength(getStrength());
return filter;
}
@NonNull
@Override
public String getFragmentShader() {
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 / mOutputWidth + ";\n";
String stepY = "stepY = " + 0.5f / mOutputHeight + ";\n";
// locString[1] = "loc[1] = loc[1]+" + seedString[1] + ";\n";
return "#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 FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
strengthLocation = GLES20.glGetUniformLocation(programHandle, "scale");
GlUtils.checkLocation(strengthLocation, "scale");
stepXLocation = GLES20.glGetUniformLocation(programHandle, "stepX");
GlUtils.checkLocation(stepXLocation, "stepX");
stepYLocation = GLES20.glGetUniformLocation(programHandle, "stepY");
GlUtils.checkLocation(stepYLocation, "stepY");
}
@Override
public void onDestroy() {
super.onDestroy();
strengthLocation = -1;
stepXLocation = -1;
stepYLocation = -1;
}
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
GLES20.glUniform1f(strengthLocation, strength);
GlUtils.checkError("glUniform1f");
GLES20.glUniform1f(stepXLocation, 0.5f / width);
GlUtils.checkError("glUniform1f");
GLES20.glUniform1f(stepYLocation, 0.5f / height);
GlUtils.checkError("glUniform1f");
}
@Override
protected BaseFilter onCopy() {
GrainFilter filter = new GrainFilter();
filter.setStrength(getStrength());
return filter;
}
}

@ -9,19 +9,21 @@ import com.otaliastudios.cameraview.filter.BaseFilter;
*/
public class GrayscaleFilter extends BaseFilter {
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " float y = dot(color, vec4(0.299, 0.587, 0.114, 0));\n"
+ " gl_FragColor = vec4(y, y, y, color.a);\n"
+ "}\n";
public GrayscaleFilter() { }
@NonNull
@Override
public String getFragmentShader() {
return "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "varying vec2 vTextureCoord;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " float y = dot(color, vec4(0.299, 0.587, 0.114, 0));\n"
+ " gl_FragColor = vec4(y, y, y, color.a);\n"
+ "}\n";
return FRAGMENT_SHADER;
}
}

@ -1,15 +1,45 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.internal.GlUtils;
/**
* Applies a hue effect on the input frames.
*/
public class HueFilter extends BaseFilter {
private float hueValue = 0.0f;
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "uniform float hue;\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";
private float hue = 0.0f;
private int hueLocation = -1;
@SuppressWarnings("WeakerAccess")
public HueFilter() { }
@ -17,47 +47,57 @@ public class HueFilter extends BaseFilter {
/**
* Sets the hue value in degrees. See the values chart:
* https://cloud.githubusercontent.com/assets/2201511/21810115/b99ac22a-d74a-11e6-9f6c-ef74d15c88c7.jpg
*
* @param hue hue degrees
*/
@SuppressWarnings("unused")
public void setHue(float degrees) {
// manipulating input value so that we can map it on 360 degree circle
hueValue = ((degrees - 45) / 45f + 0.5f) * -1;
@SuppressWarnings({"unused", "WeakerAccess"})
public void setHue(float hue) {
this.hue = hue;
}
@Override
protected BaseFilter onCopy() {
HueFilter filter = new HueFilter();
filter.hueValue = hueValue;
return filter;
/**
* Returns the current hue value.
*
* @see #setHue(float)
* @return hue
*/
@SuppressWarnings("WeakerAccess")
public float getHue() {
return hue;
}
@NonNull
@Override
public String getFragmentShader() {
return "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "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 FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
hueLocation = GLES20.glGetUniformLocation(programHandle, "hue");
GlUtils.checkLocation(hueLocation, "hue");
}
@Override
public void onDestroy() {
super.onDestroy();
hueLocation = -1;
}
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
// map it on 360 degree circle
float shaderHue = ((hue - 45) / 45f + 0.5f) * -1;
GLES20.glUniform1f(hueLocation, shaderHue);
GlUtils.checkError("glUniform1f");
}
@Override
protected BaseFilter onCopy() {
HueFilter filter = new HueFilter();
filter.setHue(getHue());
return filter;
}
}

@ -9,22 +9,23 @@ import com.otaliastudios.cameraview.filter.BaseFilter;
*/
public class InvertColorsFilter extends BaseFilter {
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " float colorR = (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";
public InvertColorsFilter() { }
@NonNull
@Override
public String getFragmentShader() {
return "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 vTextureCoord;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, vTextureCoord);\n"
+ " float colorR = (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 FRAGMENT_SHADER;
}
}

@ -1,8 +1,11 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.internal.GlUtils;
import java.util.Date;
import java.util.Random;
@ -12,132 +15,151 @@ import java.util.Random;
*/
public class LomoishFilter extends BaseFilter {
private final Random mRandom = new Random(new Date().getTime());
private int mOutputWidth = 1;
private int mOutputHeight = 1;
private final static Random RANDOM = new Random();
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "vec2 seed;\n"
+ "uniform float stepsizeX;\n"
+ "uniform float stepsizeY;\n"
+ "float stepsize;\n"
+ "uniform vec2 scale;\n"
+ "uniform 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"
+ " seed[0] = " + RANDOM.nextFloat() + ";\n"
+ " seed[1] = " + RANDOM.nextFloat() + ";\n"
+ " stepsize = " + 1.0f / 255.0f + ";\n"
// 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";
private int width = 1;
private int height = 1;
private int scaleLocation = -1;
private int maxDistLocation = -1;
private int stepSizeXLocation = -1;
private int stepSizeYLocation = -1;
public LomoishFilter() { }
@Override
public void setSize(int width, int height) {
super.setSize(width, height);
mOutputWidth = width;
mOutputHeight = height;
this.width = width;
this.height = height;
}
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
scaleLocation = GLES20.glGetUniformLocation(programHandle, "scale");
GlUtils.checkLocation(scaleLocation, "scale");
maxDistLocation = GLES20.glGetUniformLocation(programHandle, "inv_max_dist");
GlUtils.checkLocation(maxDistLocation, "inv_max_dist");
stepSizeXLocation = GLES20.glGetUniformLocation(programHandle, "stepsizeX");
GlUtils.checkLocation(stepSizeXLocation, "stepsizeX");
stepSizeYLocation = GLES20.glGetUniformLocation(programHandle, "stepsizeY");
GlUtils.checkLocation(stepSizeYLocation, "stepsizeY");
}
@Override
public void onDestroy() {
super.onDestroy();
scaleLocation = -1;
maxDistLocation = -1;
stepSizeXLocation = -1;
stepSizeYLocation = -1;
}
@Override
protected void onPreDraw(float[] transformMatrix) {
super.onPreDraw(transformMatrix);
float[] scale = new float[2];
if (mOutputWidth > mOutputHeight) {
if (width > height) {
scale[0] = 1f;
scale[1] = ((float) mOutputHeight) / mOutputWidth;
scale[1] = ((float) height) / width;
} else {
scale[0] = ((float) mOutputWidth) / mOutputHeight;
scale[0] = ((float) width) / height;
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 / mOutputWidth + ";\n";
String stepsizeYString = "stepsizeY = " + 1.0f / mOutputHeight + ";\n";
return "#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";
float maxDist = ((float) Math.sqrt(scale[0] * scale[0] + scale[1] * scale[1])) * 0.5f;
GLES20.glUniform2fv(scaleLocation, 1, scale, 0);
GlUtils.checkError("glUniform2fv");
GLES20.glUniform1f(maxDistLocation, 1.0F / maxDist);
GlUtils.checkError("glUniform1f");
GLES20.glUniform1f(stepSizeXLocation, 1.0F / width);
GlUtils.checkError("glUniform1f");
GLES20.glUniform1f(stepSizeYLocation, 1.0F / height);
GlUtils.checkError("glUniform1f");
}
}

Loading…
Cancel
Save