filters added

pull/1208/head
Arsal Imam 3 years ago
parent 569e57eac8
commit 8875c7bff3
  1. 9
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  2. 9
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  3. 366
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  4. 3
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraEngine.java
  5. 5
      cameraview/src/main/java/com/otaliastudios/cameraview/filter/BaseFilter.java
  6. 14
      cameraview/src/main/java/com/otaliastudios/cameraview/filter/ContextParameterFilter.java
  7. 35
      cameraview/src/main/java/com/otaliastudios/cameraview/filter/Filters.java
  8. 140
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/AirsolidGlitchFilter.java
  9. 81
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/AnaglyphFilter.java
  10. 93
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/AsciiFilter.java
  11. 79
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/ChromaticAberrationFilter.java
  12. 56
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/ColorspaceFilter.java
  13. 109
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrackedFilter.java
  14. 128
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/CrosshatchFilter.java
  15. 134
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/Day41GlitchFilter.java
  16. 108
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/DrunkDialFilter.java
  17. 83
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/EMInterferenceFilter.java
  18. 106
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/EarlybirdFilter.java
  19. 48
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/EdgeDetectionFilter.java
  20. 143
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/EdgeGlowFilter.java
  21. 77
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/ExposureFilter.java
  22. 115
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/HalftoneFilter.java
  23. 141
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/HighEdgeGlowFilter.java
  24. 112
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/HighlightShadowFilter.java
  25. 82
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/LuminanceThresholdFilter.java
  26. 49
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/MirrorFilter.java
  27. 143
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/NeonEdgeGlowFilter.java
  28. 88
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/RainbowFilter.java
  29. 46
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/TextureHelper.java
  30. 90
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/ToasterFilter.java
  31. 38
      cameraview/src/main/java/com/otaliastudios/cameraview/filters/WavesReflectionFilter.java
  32. BIN
      cameraview/src/main/res/drawable/filter2.png

@ -1189,6 +1189,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mCameraEngine.setHdr(hdr);
}
public boolean isHDRSupported() {
return mCameraEngine.isHDRSupported();
}
/**
* Gets the current hdr value.
* @return the current hdr value
@ -1312,6 +1316,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mCameraEngine.setFlash(flash);
}
public boolean isFlashModeSupported() {
return mCameraEngine.isFlashModeSupported();
}
/**
* Gets the current flash mode.
* @return a flash mode
@ -2178,6 +2186,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
public boolean getDrawHardwareOverlays() {
return mOverlayLayout.getHardwareCanvasEnabled();
}
//endregion
//region Callbacks and dispatching

@ -515,6 +515,11 @@ public class Camera1Engine extends CameraBaseEngine implements
}
}
@Override
public boolean isFlashModeSupported() {
return mCameraOptions != null && mCameraOptions.getSupportedFlash().size() > 1;
}
@Override
public void setFlash(@NonNull Flash flash) {
final Flash old = mFlash;
@ -595,6 +600,10 @@ public class Camera1Engine extends CameraBaseEngine implements
mWhiteBalance = oldWhiteBalance;
return false;
}
@Override
public boolean isHDRSupported() {
return mCameraOptions != null && mCameraOptions.getSupportedHdr().size() > 1;
}
@Override
public void setHdr(@NonNull Hdr hdr) {

@ -85,7 +85,8 @@ public class Camera2Engine extends CameraBaseEngine implements
ActionHolder {
private static final int FRAME_PROCESSING_FORMAT = ImageFormat.YUV_420_888;
@VisibleForTesting static final long METER_TIMEOUT = 5000;
@VisibleForTesting
static final long METER_TIMEOUT = 5000;
private static final long METER_TIMEOUT_SHORT = 2500;
private final CameraManager mManager;
@ -135,8 +136,8 @@ public class Camera2Engine extends CameraBaseEngine implements
@NonNull
private <T> T readCharacteristic(@NonNull CameraCharacteristics characteristics,
@NonNull CameraCharacteristics.Key<T> key,
@NonNull T fallback) {
@NonNull CameraCharacteristics.Key<T> key,
@NonNull T fallback) {
T value = characteristics.get(key);
return value == null ? fallback : value;
}
@ -232,6 +233,7 @@ public class Camera2Engine extends CameraBaseEngine implements
/**
* Can be changed to select something different than {@link CameraDevice#TEMPLATE_PREVIEW}
* for the default repeating request.
*
* @return the default template for preview
*/
protected int getRepeatingRequestDefaultTemplate() {
@ -241,7 +243,7 @@ public class Camera2Engine extends CameraBaseEngine implements
/**
* Applies the repeating request builder to the preview, assuming we actually have a preview
* running. Can be called after changing parameters to the builder.
*
* <p>
* To apply a new builder (for example switch between TEMPLATE_PREVIEW and TEMPLATE_RECORD)
* it should be set before calling this method, for example by calling
* {@link #createRepeatingRequestBuilder(int)}.
@ -423,10 +425,15 @@ public class Camera2Engine extends CameraBaseEngine implements
boolean flip = getAngles().flip(Reference.SENSOR, Reference.VIEW);
int format;
switch (mPictureFormat) {
case JPEG: format = ImageFormat.JPEG; break;
case DNG: format = ImageFormat.RAW_SENSOR; break;
default: throw new IllegalArgumentException("Unknown format:"
+ mPictureFormat);
case JPEG:
format = ImageFormat.JPEG;
break;
case DNG:
format = ImageFormat.RAW_SENSOR;
break;
default:
throw new IllegalArgumentException("Unknown format:"
+ mPictureFormat);
}
mCameraOptions = new Camera2Options(mManager, mCameraId, flip, format);
createRepeatingRequestBuilder(getRepeatingRequestDefaultTemplate());
@ -541,9 +548,14 @@ public class Camera2Engine extends CameraBaseEngine implements
if (getMode() == Mode.PICTURE) {
int format;
switch (mPictureFormat) {
case JPEG: format = ImageFormat.JPEG; break;
case DNG: format = ImageFormat.RAW_SENSOR; break;
default: throw new IllegalArgumentException("Unknown format:" + mPictureFormat);
case JPEG:
format = ImageFormat.JPEG;
break;
case DNG:
format = ImageFormat.RAW_SENSOR;
break;
default:
throw new IllegalArgumentException("Unknown format:" + mPictureFormat);
}
mPictureReader = ImageReader.newInstance(
mCaptureSize.getWidth(),
@ -644,11 +656,11 @@ public class Camera2Engine extends CameraBaseEngine implements
mFullVideoPendingStub = null;
getOrchestrator().scheduleStateful("do take video", CameraState.PREVIEW,
new Runnable() {
@Override
public void run() {
doTakeVideo(stub);
}
});
@Override
public void run() {
doTakeVideo(stub);
}
});
}
// Wait for the first frame.
@ -875,11 +887,11 @@ public class Camera2Engine extends CameraBaseEngine implements
getOrchestrator().scheduleStateful("reset metering after picture",
CameraState.PREVIEW,
new Runnable() {
@Override
public void run() {
unlockAndResetMetering();
}
});
@Override
public void run() {
unlockAndResetMetering();
}
});
}
}
@ -963,7 +975,10 @@ public class Camera2Engine extends CameraBaseEngine implements
LOG.w("Applying the Issue549 workaround.", Thread.currentThread());
maybeRestorePreviewTemplateAfterVideo();
LOG.w("Applied the Issue549 workaround. Sleeping...");
try { Thread.sleep(600); } catch (InterruptedException ignore) {}
try {
Thread.sleep(600);
} catch (InterruptedException ignore) {
}
LOG.w("Applied the Issue549 workaround. Slept!");
}
}
@ -976,18 +991,18 @@ public class Camera2Engine extends CameraBaseEngine implements
// torn down in the engine thread while this was still being called.
getOrchestrator().scheduleStateful("restore preview template", CameraState.BIND,
new Runnable() {
@Override
public void run() {
maybeRestorePreviewTemplateAfterVideo();
}
});
@Override
public void run() {
maybeRestorePreviewTemplateAfterVideo();
}
});
}
/**
* Video recorders might change the camera template to {@link CameraDevice#TEMPLATE_RECORD}.
* After the video is taken, we should restore the template preview, which also means that
* we'll remove any extra surface target that was added by the video recorder.
*
* <p>
* This method avoids doing this twice by checking the request tag, as set by
* the {@link #createRepeatingRequestBuilder(int)} method.
*/
@ -1043,7 +1058,9 @@ public class Camera2Engine extends CameraBaseEngine implements
int[] modesArray = readCharacteristic(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES,
new int[]{});
List<Integer> modes = new ArrayList<>();
for (int mode : modesArray) { modes.add(mode); }
for (int mode : modesArray) {
modes.add(mode);
}
if (getMode() == Mode.VIDEO &&
modes.contains(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)) {
builder.set(CaptureRequest.CONTROL_AF_MODE,
@ -1083,7 +1100,9 @@ public class Camera2Engine extends CameraBaseEngine implements
int[] modesArray = readCharacteristic(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES,
new int[]{});
List<Integer> modes = new ArrayList<>();
for (int mode : modesArray) { modes.add(mode); }
for (int mode : modesArray) {
modes.add(mode);
}
if (modes.contains(CaptureRequest.CONTROL_AF_MODE_AUTO)) {
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
return;
@ -1103,6 +1122,16 @@ public class Camera2Engine extends CameraBaseEngine implements
}
}
@Override
public boolean isFlashModeSupported() {
return mCameraOptions.getSupportedFlash().size() > 1;
}
@Override
public boolean isHDRSupported() {
return mCameraOptions.getSupportedHdr().size() > 1;
}
@Override
public void setFlash(@NonNull final Flash flash) {
final Flash old = mFlash;
@ -1110,31 +1139,31 @@ public class Camera2Engine extends CameraBaseEngine implements
mFlashTask = getOrchestrator().scheduleStateful("flash (" + flash + ")",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
boolean shouldApply = applyFlash(mRepeatingRequestBuilder, old);
boolean needsWorkaround = getState() == CameraState.PREVIEW;
if (needsWorkaround) {
// Runtime changes to the flash value are not correctly handled by the
// driver. See https://stackoverflow.com/q/53003383/4288782 for example.
// For this reason, we go back to OFF, capture once, then go to the new one.
mFlash = Flash.OFF;
applyFlash(mRepeatingRequestBuilder, old);
try {
mSession.capture(mRepeatingRequestBuilder.build(), null,
null);
} catch (CameraAccessException e) {
throw createCameraException(e);
@Override
public void run() {
boolean shouldApply = applyFlash(mRepeatingRequestBuilder, old);
boolean needsWorkaround = getState() == CameraState.PREVIEW;
if (needsWorkaround) {
// Runtime changes to the flash value are not correctly handled by the
// driver. See https://stackoverflow.com/q/53003383/4288782 for example.
// For this reason, we go back to OFF, capture once, then go to the new one.
mFlash = Flash.OFF;
applyFlash(mRepeatingRequestBuilder, old);
try {
mSession.capture(mRepeatingRequestBuilder.build(), null,
null);
} catch (CameraAccessException e) {
throw createCameraException(e);
}
mFlash = flash;
applyFlash(mRepeatingRequestBuilder, old);
applyRepeatingRequestBuilder();
} else if (shouldApply) {
applyRepeatingRequestBuilder();
}
}
mFlash = flash;
applyFlash(mRepeatingRequestBuilder, old);
applyRepeatingRequestBuilder();
} else if (shouldApply) {
applyRepeatingRequestBuilder();
}
}
});
});
}
/**
@ -1142,14 +1171,14 @@ public class Camera2Engine extends CameraBaseEngine implements
* - {@link CaptureRequest#CONTROL_AE_MODE_ON}
* - {@link CaptureRequest#CONTROL_AE_MODE_ON_AUTO_FLASH}
* - {@link CaptureRequest#CONTROL_AE_MODE_ON_ALWAYS_FLASH}
*
* <p>
* The API offers a high level control through {@link CaptureRequest#CONTROL_AE_MODE},
* which is what the mapper looks at. It will trigger (if specified) flash only for
* still captures which is exactly what we want.
*
* <p>
* However, we set CONTROL_AE_MODE to ON/OFF (depending
* on which is available) with both {@link Flash#OFF} and {@link Flash#TORCH}.
*
* <p>
* When CONTROL_AE_MODE is ON or OFF, the low level control, called
* {@link CaptureRequest#FLASH_MODE}, becomes effective, and that's where we can actually
* distinguish between a turned off flash and a torch flash.
@ -1161,7 +1190,9 @@ public class Camera2Engine extends CameraBaseEngine implements
int[] availableAeModesArray = readCharacteristic(
CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES, new int[]{});
List<Integer> availableAeModes = new ArrayList<>();
for (int mode : availableAeModesArray) { availableAeModes.add(mode); }
for (int mode : availableAeModesArray) {
availableAeModes.add(mode);
}
List<Pair<Integer, Integer>> pairs = mMapper.mapFlash(mFlash);
for (Pair<Integer, Integer> pair : pairs) {
@ -1185,13 +1216,13 @@ public class Camera2Engine extends CameraBaseEngine implements
mLocationTask = getOrchestrator().scheduleStateful("location",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
if (applyLocation(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
}
}
});
@Override
public void run() {
if (applyLocation(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
}
}
});
}
@SuppressWarnings("WeakerAccess")
@ -1211,13 +1242,13 @@ public class Camera2Engine extends CameraBaseEngine implements
"white balance (" + whiteBalance + ")",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
if (applyWhiteBalance(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
}
}
});
@Override
public void run() {
if (applyWhiteBalance(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
}
}
});
}
@SuppressWarnings("WeakerAccess")
@ -1239,13 +1270,13 @@ public class Camera2Engine extends CameraBaseEngine implements
mHdrTask = getOrchestrator().scheduleStateful("hdr (" + hdr + ")",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
if (applyHdr(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
}
}
});
@Override
public void run() {
if (applyHdr(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
}
}
});
}
@SuppressWarnings("WeakerAccess")
@ -1269,16 +1300,16 @@ public class Camera2Engine extends CameraBaseEngine implements
"zoom",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
if (applyZoom(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
if (notify) {
getCallback().dispatchOnZoomChanged(zoom, points);
@Override
public void run() {
if (applyZoom(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
if (notify) {
getCallback().dispatchOnZoomChanged(zoom, points);
}
}
}
}
}
});
});
}
@SuppressWarnings("WeakerAccess")
@ -1327,16 +1358,16 @@ public class Camera2Engine extends CameraBaseEngine implements
"exposure correction",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
if (applyExposureCorrection(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
if (notify) {
getCallback().dispatchOnExposureCorrectionChanged(EVvalue, bounds, points);
@Override
public void run() {
if (applyExposureCorrection(mRepeatingRequestBuilder, old)) {
applyRepeatingRequestBuilder();
if (notify) {
getCallback().dispatchOnExposureCorrectionChanged(EVvalue, bounds, points);
}
}
}
}
}
});
});
}
@SuppressWarnings("WeakerAccess")
@ -1369,13 +1400,13 @@ public class Camera2Engine extends CameraBaseEngine implements
"preview fps (" + previewFrameRate + ")",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
if (applyPreviewFrameRate(mRepeatingRequestBuilder, oldPreviewFrameRate)) {
applyRepeatingRequestBuilder();
}
}
});
@Override
public void run() {
if (applyPreviewFrameRate(mRepeatingRequestBuilder, oldPreviewFrameRate)) {
applyRepeatingRequestBuilder();
}
}
});
}
@SuppressWarnings("WeakerAccess")
@ -1448,11 +1479,11 @@ public class Camera2Engine extends CameraBaseEngine implements
getOrchestrator().scheduleStateful("picture format (" + pictureFormat + ")",
CameraState.ENGINE,
new Runnable() {
@Override
public void run() {
restart();
}
});
@Override
public void run() {
restart();
}
});
}
}
@ -1473,7 +1504,8 @@ public class Camera2Engine extends CameraBaseEngine implements
Image image = null;
try {
image = reader.acquireLatestImage();
} catch (Exception ignore) { }
} catch (Exception ignore) {
}
if (image == null) {
LOG.w("onImageAvailable:", "failed to acquire Image!");
} else if (getState() == CameraState.PREVIEW && !isChangingState()) {
@ -1499,21 +1531,21 @@ public class Camera2Engine extends CameraBaseEngine implements
// the preview. If the value is changed between the two, the preview step can crash.
getOrchestrator().schedule("has frame processors (" + hasFrameProcessors + ")",
true, new Runnable() {
@Override
public void run() {
if (getState().isAtLeast(CameraState.BIND) && isChangingState()) {
// Extremely rare case in which this was called in between startBind and
// startPreview. This can cause issues. Try later.
setHasFrameProcessors(hasFrameProcessors);
return;
}
// Apply and restart.
mHasFrameProcessors = hasFrameProcessors;
if (getState().isAtLeast(CameraState.BIND)) {
restartBind();
}
}
});
@Override
public void run() {
if (getState().isAtLeast(CameraState.BIND) && isChangingState()) {
// Extremely rare case in which this was called in between startBind and
// startPreview. This can cause issues. Try later.
setHasFrameProcessors(hasFrameProcessors);
return;
}
// Apply and restart.
mHasFrameProcessors = hasFrameProcessors;
if (getState().isAtLeast(CameraState.BIND)) {
restartBind();
}
}
});
}
@Override
@ -1524,20 +1556,20 @@ public class Camera2Engine extends CameraBaseEngine implements
// If the value is changed between the two, the preview step can crash.
getOrchestrator().schedule("frame processing format (" + format + ")",
true, new Runnable() {
@Override
public void run() {
if (getState().isAtLeast(CameraState.BIND) && isChangingState()) {
// Extremely rare case in which this was called in between startBind and
// startPreview. This can cause issues. Try later.
setFrameProcessingFormat(format);
return;
}
mFrameProcessingFormat = format > 0 ? format : FRAME_PROCESSING_FORMAT;
if (getState().isAtLeast(CameraState.BIND)) {
restartBind();
}
}
});
@Override
public void run() {
if (getState().isAtLeast(CameraState.BIND) && isChangingState()) {
// Extremely rare case in which this was called in between startBind and
// startPreview. This can cause issues. Try later.
setFrameProcessingFormat(format);
return;
}
mFrameProcessingFormat = format > 0 ? format : FRAME_PROCESSING_FORMAT;
if (getState().isAtLeast(CameraState.BIND)) {
restartBind();
}
}
});
}
//endregion
@ -1554,38 +1586,38 @@ public class Camera2Engine extends CameraBaseEngine implements
getOrchestrator().scheduleStateful("autofocus (" + gesture + ")",
CameraState.PREVIEW,
new Runnable() {
@Override
public void run() {
// The camera options API still has the auto focus API but it really
// refers to "3A metering to a specific point". Since we have a point, check.
if (!mCameraOptions.isAutoFocusSupported()) return;
// Create the meter and start.
getCallback().dispatchOnFocusStart(gesture, legacyPoint);
final MeterAction action = createMeterAction(regions);
Action wrapper = Actions.timeout(METER_TIMEOUT, action);
wrapper.start(Camera2Engine.this);
wrapper.addCallback(new CompletionCallback() {
@Override
protected void onActionCompleted(@NonNull Action a) {
getCallback().dispatchOnFocusEnd(gesture,
action.isSuccessful(), legacyPoint);
getOrchestrator().remove("reset metering");
if (shouldResetAutoFocus()) {
getOrchestrator().scheduleStatefulDelayed("reset metering",
CameraState.PREVIEW,
getAutoFocusResetDelay(),
new Runnable() {
@Override
public void run() {
unlockAndResetMetering();
public void run() {
// The camera options API still has the auto focus API but it really
// refers to "3A metering to a specific point". Since we have a point, check.
if (!mCameraOptions.isAutoFocusSupported()) return;
// Create the meter and start.
getCallback().dispatchOnFocusStart(gesture, legacyPoint);
final MeterAction action = createMeterAction(regions);
Action wrapper = Actions.timeout(METER_TIMEOUT, action);
wrapper.start(Camera2Engine.this);
wrapper.addCallback(new CompletionCallback() {
@Override
protected void onActionCompleted(@NonNull Action a) {
getCallback().dispatchOnFocusEnd(gesture,
action.isSuccessful(), legacyPoint);
getOrchestrator().remove("reset metering");
if (shouldResetAutoFocus()) {
getOrchestrator().scheduleStatefulDelayed("reset metering",
CameraState.PREVIEW,
getAutoFocusResetDelay(),
new Runnable() {
@Override
public void run() {
unlockAndResetMetering();
}
});
}
});
}
}
});
}
});
}
});
}
@NonNull

@ -679,6 +679,9 @@ public abstract class CameraEngine implements
public abstract float getExposureCorrectionValue();
public abstract void setFlash(@NonNull Flash flash);
public abstract boolean isFlashModeSupported();
public abstract boolean isHDRSupported();
@NonNull public abstract Flash getFlash();
public abstract void setWhiteBalance(@NonNull WhiteBalance whiteBalance);

@ -103,6 +103,11 @@ public abstract class BaseFilter implements Filter {
@SuppressWarnings({"unused", "WeakerAccess"})
protected String fragmentTextureCoordinateName = DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME;
public Size getSize() {
return size;
}
@SuppressWarnings("WeakerAccess")
@NonNull
protected String createDefaultVertexShader() {

@ -0,0 +1,14 @@
package com.otaliastudios.cameraview.filter;
import android.content.Context;
public interface ContextParameterFilter {
/**
* Sets the parameter.
* The value should always be between 0 and 1.
*
* @param value parameter
*/
void setContext(Context value);
}

@ -4,18 +4,28 @@ import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filters.AutoFixFilter;
import com.otaliastudios.cameraview.filters.BlackAndWhiteFilter;
import com.otaliastudios.cameraview.filters.ToasterFilter;
import com.otaliastudios.cameraview.filters.BrightnessFilter;
import com.otaliastudios.cameraview.filters.ChromaticAberrationFilter;
import com.otaliastudios.cameraview.filters.ColorspaceFilter;
import com.otaliastudios.cameraview.filters.ContrastFilter;
import com.otaliastudios.cameraview.filters.CrossProcessFilter;
import com.otaliastudios.cameraview.filters.DocumentaryFilter;
import com.otaliastudios.cameraview.filters.DuotoneFilter;
import com.otaliastudios.cameraview.filters.EMInterferenceFilter;
import com.otaliastudios.cameraview.filters.EarlybirdFilter;
import com.otaliastudios.cameraview.filters.EdgeDetectionFilter;
import com.otaliastudios.cameraview.filters.ExposureFilter;
import com.otaliastudios.cameraview.filters.FillLightFilter;
import com.otaliastudios.cameraview.filters.GammaFilter;
import com.otaliastudios.cameraview.filters.GrainFilter;
import com.otaliastudios.cameraview.filters.GrayscaleFilter;
import com.otaliastudios.cameraview.filters.HalftoneFilter;
import com.otaliastudios.cameraview.filters.HighlightShadowFilter;
import com.otaliastudios.cameraview.filters.HueFilter;
import com.otaliastudios.cameraview.filters.InvertColorsFilter;
import com.otaliastudios.cameraview.filters.LomoishFilter;
import com.otaliastudios.cameraview.filters.LuminanceThresholdFilter;
import com.otaliastudios.cameraview.filters.PosterizeFilter;
import com.otaliastudios.cameraview.filters.SaturationFilter;
import com.otaliastudios.cameraview.filters.SepiaFilter;
@ -23,6 +33,7 @@ import com.otaliastudios.cameraview.filters.SharpnessFilter;
import com.otaliastudios.cameraview.filters.TemperatureFilter;
import com.otaliastudios.cameraview.filters.TintFilter;
import com.otaliastudios.cameraview.filters.VignetteFilter;
import com.otaliastudios.cameraview.filters.WavesReflectionFilter;
/**
* Contains commonly used {@link Filter}s.
@ -96,7 +107,29 @@ public enum Filters {
TINT(TintFilter.class),
/** @see VignetteFilter */
VIGNETTE(VignetteFilter.class);
VIGNETTE(VignetteFilter.class),
COLOR_SPACE(ColorspaceFilter.class),
EXPOSURE(ExposureFilter.class),
HIGHLIGHT_SHADOW(HighlightShadowFilter.class),
HALF_TONE(HalftoneFilter.class),
LUMINANCE_THRESHOLD(LuminanceThresholdFilter.class),
WAVES_REFLECTION(WavesReflectionFilter.class),
EM_INTERFERENCE(EMInterferenceFilter.class),
CHROMATIC_ABERRATION(ChromaticAberrationFilter.class),
EDGE_DETECTION(EdgeDetectionFilter.class),
EARLY_BIRD(EarlybirdFilter.class),
BRANNAN(ToasterFilter.class);
private Class<? extends Filter> filterClass;

@ -0,0 +1,140 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class AirsolidGlitchFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"float rand(vec2 p)\n" +
"{\n" +
" float t = floor(iTime * 50.) / 10.; //speed \n" +
" return fract(sin(dot(p, vec2(t * 12.9898, t * 78.233))) * 43758.5453);\n" +
"}\n" +
"\n" +
"float noise(vec2 uv, float blockiness)\n" +
"{ \n" +
" vec2 lv = fract(uv);\n" +
" vec2 id = floor(uv);\n" +
" \n" +
" float n1 = rand(id);\n" +
" float n2 = rand(id+vec2(1,0));\n" +
" float n3 = rand(id+vec2(0,1));\n" +
" float n4 = rand(id+vec2(1,1));\n" +
" \n" +
" vec2 u = smoothstep(0.0, 1.0 + blockiness, lv);\n" +
"\n" +
" return mix(mix(n1, n2, u.x), mix(n3, n4, u.x), u.y);\n" +
"}\n" +
"\n" +
"float fbm(vec2 uv, int count, float blockiness, float complexity)\n" +
"{\n" +
" float val = 0.0;\n" +
" float amp = 0.5;\n" +
" \n" +
" while(count != 0)\n" +
" {\n" +
" \tval += amp * noise(uv, blockiness);\n" +
" amp *= 0.5;\n" +
" uv *= complexity; \n" +
" count--;\n" +
" }\n" +
" \n" +
" return val;\n" +
"}\n" +
"\n" +
"const float glitchAmplitude = 0.9; // increase this\n" +
"const float glitchNarrowness = 400.0;\n" +
"const float glitchBlockiness = 10000.0;\n" +
"const float glitchMinimizer = 10.0; // decrease this\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" // Normalized pixel coordinates (from 0 to 1)\n" +
" vec2 uv = fragCoord/iResolution.xy;\n" +
" vec2 a = vec2(uv.x * (iResolution.x / iResolution.y), uv.y);\n" +
" vec2 uv2 = vec2(a.x / iResolution.x, exp(a.y));\n" +
"\tvec2 id = floor(uv * 20.0); // size noise\n" +
" //id.x /= floor(texture(iChannel0, vec2(id / 8.0)).r * 8.0);\n" +
"\n" +
" // Generate shift amplitude\n" +
" float shift = glitchAmplitude * pow(fbm(uv2, int(rand(id) * 6.), glitchBlockiness, glitchNarrowness), glitchMinimizer);\n" +
" \n" +
" // Create a scanline effect\n" +
" float scanline = abs(cos(uv.y * 400.)); //scanline intensite\n" +
" scanline = smoothstep(0.0, 2.0, scanline);\n" +
" shift = smoothstep(0.00001, 0.2, shift);\n" +
" \n" +
" // Apply glitch and RGB shift\n" +
" float colR = texture2D(iChannel0, vec2(uv.x + shift, uv.y)).r * (1. - shift) ;\n" +
" float colG = texture2D(iChannel0, vec2(uv.x - shift, uv.y)).g * (1. - shift) + rand(id) * shift;\n" +
" float colB = texture2D(iChannel0, vec2(uv.x - shift, uv.y)).b * (1. - shift);\n" +
" // Mix with the scanline effect\n" +
" vec3 f = vec3(colR, colG, colB) - (0.1 * scanline); //scanline intensite\n" +
" \n" +
" // Output to screen\n" +
" fragColor = vec4(f, 1.0);\n" +
"}" +
"\nvoid main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iResolutionLocation = -1;
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = (((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f) + 1;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,81 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class AnaglyphFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
"\tvec2 uv = fragCoord.xy / iResolution.xy;\n" +
" \n" +
" vec4 left = texture2D(iChannel0, uv);\n" +
" vec4 right = texture2D(iChannel0, uv + vec2(0.015, 0.0));\n" +
"\t\n" +
" vec3 color = vec3(left.r, right.gb);\n" +
" color = clamp(color, 0.0, 1.0);\n" +
" fragColor = vec4(color, 1.0);\n" +
"}\n" +
"void main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iResolutionLocation = -1;
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
// Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,93 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class AsciiFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"float character(int n, vec2 p)\n" +
"{\n" +
"\tp = floor(p*vec2(4.0, -4.0) + 2.5);\n" +
" if (clamp(p.x, 0.0, 4.0) == p.x)\n" +
"\t{\n" +
" if (clamp(p.y, 0.0, 4.0) == p.y)\t\n" +
"\t\t{\n" +
" \tint a = int(round(p.x) + 5.0 * round(p.y));\n" +
"\t\t\tif (((n >> a) & 1) == 1) return 1.0;\n" +
"\t\t}\t\n" +
" }\n" +
"\treturn 0.0;\n" +
"}\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
"\tvec2 pix = fragCoord.xy;\n" +
"\tvec3 col = texture2D(iChannel0, floor(pix/8.0)*8.0/iResolution.xy).rgb;\t\n" +
"\t\n" +
"\tfloat gray = 0.3 * col.r + 0.59 * col.g + 0.11 * col.b;\n" +
"\t\n" +
"\tint n = 4096; // .\n" +
"\tif (gray > 0.2) n = 65600; // :\n" +
"\tif (gray > 0.3) n = 332772; // *\n" +
"\tif (gray > 0.4) n = 15255086; // o \n" +
"\tif (gray > 0.5) n = 23385164; // &\n" +
"\tif (gray > 0.6) n = 15252014; // 8\n" +
"\tif (gray > 0.7) n = 13199452; // @\n" +
"\tif (gray > 0.8) n = 11512810; // #\n" +
"\t\n" +
"\tvec2 p = mod(pix/4.0, 2.0) - vec2(1.0);\n" +
" \n" +
"\tif (iMouse.z > 0.5)\tcol = gray*vec3(character(n, p));\n" +
"\telse col = col*character(n, p);\n" +
"\t\n" +
"\tfragColor = vec4(col, 1.0);\n" +
"}" +
"\nvoid main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iResolutionLocation = -1;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
}
}

@ -0,0 +1,79 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.opengl.core.Egloo;
public class ChromaticAberrationFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iGlobalTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" vec2 uv = fragCoord.xy;\n" +
"\n" +
"\tfloat amount = 0.0;\n" +
"\t\n" +
"\tamount = (1.0 + sin(iGlobalTime*6.0)) * 0.5;\n" +
"\tamount *= 1.0 + sin(iGlobalTime*16.0) * 0.5;\n" +
"\tamount *= 1.0 + sin(iGlobalTime*19.0) * 0.5;\n" +
"\tamount *= 1.0 + sin(iGlobalTime*27.0) * 0.5;\n" +
"\tamount = pow(amount, 3.0);\n" +
"\n" +
"\tamount *= 0.05;\n" +
"\t\n" +
" vec3 col;\n" +
" col.r = texture2D( iChannel0, vec2(uv.x+amount,uv.y) ).r;\n" +
" col.g = texture2D( iChannel0, uv ).g;\n" +
" col.b = texture2D( iChannel0, vec2(uv.x-amount,uv.y) ).b;\n" +
"\n" +
"\tcol *= (1.0 - amount * 0.5);\n" +
"\t\n" +
" fragColor = vec4(col,1.0);\n" +
"}\n" +
"\n" +
"\n" +
"void main() {\n" +
" \tmainImage(gl_FragColor, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iGlobalTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iGlobalTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,56 @@
package com.otaliastudios.cameraview.filters;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.OneParameterFilter;
public class ColorspaceFilter extends BaseFilter {
private static final String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
"varying vec2 vTextureCoord;" +
"uniform samplerExternalOES sTexture;" +
"void main() {" +
"highp vec2 sampleDivisor = vec2(1.0 / 200.0, 1.0 / 320.0);" +
"highp vec2 samplePos = vTextureCoord - mod(vTextureCoord, sampleDivisor);" +
"highp vec4 color = texture2D(sTexture, samplePos);" +
"mediump vec4 colorCyan = vec4(85.0 / 255.0, 1.0, 1.0, 1.0);" +
"mediump vec4 colorMagenta = vec4(1.0, 85.0 / 255.0, 1.0, 1.0);" +
"mediump vec4 colorWhite = vec4(1.0, 1.0, 1.0, 1.0);" +
"mediump vec4 colorBlack = vec4(0.0, 0.0, 0.0, 1.0);" +
"mediump vec4 endColor;" +
"highp float blackDistance = distance(color, colorBlack);" +
"highp float whiteDistance = distance(color, colorWhite);" +
"highp float magentaDistance = distance(color, colorMagenta);" +
"highp float cyanDistance = distance(color, colorCyan);" +
"mediump vec4 finalColor;" +
"highp float colorDistance = min(magentaDistance, cyanDistance);" +
"colorDistance = min(colorDistance, whiteDistance);" +
"colorDistance = min(colorDistance, blackDistance);" +
"if (colorDistance == blackDistance) {" +
"finalColor = colorBlack;" +
"} else if (colorDistance == whiteDistance) {" +
"finalColor = colorWhite;" +
"} else if (colorDistance == cyanDistance) {" +
"finalColor = colorCyan;" +
"} else {" +
"finalColor = colorMagenta;" +
"}" +
"gl_FragColor = finalColor;" +
"}";
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
}

@ -0,0 +1,109 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class CrackedFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"#extension GL_OES_standard_derivatives : enable\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
// "uniform float iGlobalTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"float rnd(vec2 s)\n" +
"{\n" +
" return 1.-2.*fract(sin(s.x*253.13+s.y*341.41)*589.19);\n" +
"}\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
"\tvec2 p=(fragCoord.xy*2.-iResolution.xy)/iResolution.x;\n" +
"\n" +
" vec2 v=vec2(1E3);\n" +
" vec2 v2=vec2(1E4);\n" +
" vec2 center=vec2(.1,-.5);\n" +
" for(int c=0;c<30;c++)\n" +
" {\n" +
" float angle=floor(rnd(vec2(float(c),387.44))*16.)*3.1415*.4-.5;\n" +
" float dist=pow(rnd(vec2(float(c),78.21)),2.)*.5;\n" +
" vec2 vc=vec2(center.x+cos(angle)*dist+rnd(vec2(float(c),349.3))*7E-3,\n" +
" center.y+sin(angle)*dist+rnd(vec2(float(c),912.7))*7E-3);\n" +
" if(length(vc-p)<length(v-p))\n" +
" {\n" +
"\t v2=v;\n" +
"\t v=vc;\n" +
" }\n" +
" else if(length(vc-p)<length(v2-p))\n" +
" {\n" +
" v2=vc;\n" +
" }\n" +
" }\n" +
"\n" +
" float col=abs(length(dot(p-v,normalize(v-v2)))-length(dot(p-v2,normalize(v-v2))))+.002*length(p-center);\n" +
" col=7E-4/col;\n" +
" if(length(v-v2)<4E-3)col=0.;\n" +
"// if(length(v-p)<4E-3)col=1E-6;\n" +
" if(col<.3)col=0.;\n" +
" vec4 tex=texture2D(iChannel0,(fragCoord.xy)/iResolution.xy+rnd(v)*.02);\n" +
" fragColor=col*vec4(vec3(1.-tex.xyz),1.)+(1.-col)*tex;\n" +
"}\n" +
"\n" +
"void main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
// private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
// iGlobalTimeLocation = -1;
// START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
// iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iGlobalTime");
// Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iGlobalTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
// GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,128 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.TwoParameterFilter;
import com.otaliastudios.opengl.core.Egloo;
public class CrosshatchFilter extends BaseFilter implements TwoParameterFilter {
private static final String CROSSHATCH_FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"varying vec2 vTextureCoord;\n" +
" uniform samplerExternalOES sTexture;\n" +
"uniform highp float crossHatchSpacing;\n" +
"uniform highp float lineWidth;\n" +
"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" +
"void main()\n" +
"{\n" +
"highp float luminance = dot(texture2D(sTexture, vTextureCoord).rgb, W);\n" +
"lowp vec4 colorToDisplay = vec4(1.0, 1.0, 1.0, 1.0);\n" +
"if (luminance < 1.00)\n" +
"{\n" +
"if (mod(vTextureCoord.x + vTextureCoord.y, crossHatchSpacing) <= lineWidth)\n" +
"{\n" +
"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" +
"}\n" +
"}\n" +
"if (luminance < 0.75)\n" +
"{\n" +
"if (mod(vTextureCoord.x - vTextureCoord.y, crossHatchSpacing) <= lineWidth)\n" +
"{\n" +
"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" +
"}\n" +
"}\n" +
"if (luminance < 0.50)\n" +
"{\n" +
"if (mod(vTextureCoord.x + vTextureCoord.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)\n" +
"{\n" +
"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" +
"}\n" +
"}\n" +
"if (luminance < 0.3)\n" +
"{\n" +
"if (mod(vTextureCoord.x - vTextureCoord.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)\n" +
"{\n" +
"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" +
"}\n" +
"}\n" +
"gl_FragColor = colorToDisplay;\n" +
"}\n";
private float crossHatchSpacing = 0.03f;
private int crossHatchSpacingLocation = -1;
private float lineWidth = 0.003f;
private int lineWidthLocation = -1;
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
crossHatchSpacingLocation = GLES20.glGetUniformLocation(programHandle, "crossHatchSpacing");
Egloo.checkGlProgramLocation(crossHatchSpacingLocation, "crossHatchSpacing");
lineWidthLocation = GLES20.glGetUniformLocation(programHandle, "lineWidth");
Egloo.checkGlProgramLocation(lineWidthLocation, "lineWidth");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
GLES20.glUniform1f(crossHatchSpacingLocation, crossHatchSpacing);
GLES20.glUniform1f(lineWidthLocation, lineWidth);
Egloo.checkGlError("glUniform1f");
}
@Override
public void onDestroy() {
super.onDestroy();
crossHatchSpacing = 0.03f;
crossHatchSpacingLocation = -1;
lineWidth = 0.003f;
lineWidthLocation = -1;
}
@NonNull
@Override
public String getFragmentShader() {
return CROSSHATCH_FRAGMENT_SHADER;
}
@Override
public void setParameter1(float value) {
setCrossHatchSpacing(value);
}
@Override
public float getParameter1() {
return getCrossHatchSpacing();
}
@Override
public void setParameter2(float value) {
setLineWidth(value);
}
@Override
public float getParameter2() {
return getLineWidth();
}
public float getLineWidth() {
return lineWidth;
}
public void setLineWidth(float lineWidth) {
this.lineWidth = lineWidth;
}
public float getCrossHatchSpacing() {
return crossHatchSpacing;
}
public void setCrossHatchSpacing(float crossHatchSpacing) {
this.crossHatchSpacing = crossHatchSpacing;
}
}

@ -0,0 +1,134 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class Day41GlitchFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"float rand(vec2 p)\n" +
"{\n" +
" float t = floor(iTime * 20.) / 10.;\n" +
" return fract(sin(dot(p, vec2(t * 12.9898, t * 78.233))) * 43758.5453);\n" +
"}\n" +
"\n" +
"float noise(vec2 uv, float blockiness)\n" +
"{ \n" +
" vec2 lv = fract(uv);\n" +
" vec2 id = floor(uv);\n" +
" \n" +
" float n1 = rand(id);\n" +
" float n2 = rand(id+vec2(1,0));\n" +
" float n3 = rand(id+vec2(0,1));\n" +
" float n4 = rand(id+vec2(1,1));\n" +
" \n" +
" vec2 u = smoothstep(0.0, 1.0 + blockiness, lv);\n" +
"\n" +
" return mix(mix(n1, n2, u.x), mix(n3, n4, u.x), u.y);\n" +
"}\n" +
"\n" +
"float fbm(vec2 uv, int count, float blockiness, float complexity)\n" +
"{\n" +
" float val = 0.0;\n" +
" float amp = 0.5;\n" +
" \n" +
" while(count != 0)\n" +
" {\n" +
" \tval += amp * noise(uv, blockiness);\n" +
" amp *= 0.5;\n" +
" uv *= complexity; \n" +
" count--;\n" +
" }\n" +
" \n" +
" return val;\n" +
"}\n" +
"\n" +
"const float glitchAmplitude = 0.2; // increase this\n" +
"const float glitchNarrowness = 4.0;\n" +
"const float glitchBlockiness = 2.0;\n" +
"const float glitchMinimizer = 8.0; // decrease this\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" \n" +
" vec2 uv = fragCoord/iResolution.xy;\n" +
" float aspect = iResolution.x / iResolution.y;\n" +
" vec2 a = vec2(uv.x * aspect , uv.y);\n" +
" vec2 uv2 = vec2(a.x / iResolution.x, exp(a.y));\n" +
"\n" +
" \n" +
" float shift = glitchAmplitude * pow(fbm(uv2, 4, glitchBlockiness, glitchNarrowness), glitchMinimizer);\n" +
" \n" +
" float colR = texture2D(iChannel0, vec2(uv.x + shift, uv.y)).r * (1. - shift);\n" +
" float colG = texture2D(iChannel0, vec2(uv.x - shift, uv.y)).g * (1. - shift);\n" +
" float colB = texture2D(iChannel0, vec2(uv.x - shift, uv.y)).b * (1. - shift);\n" +
" \n" +
" // Mix with the scanline effect\n" +
" vec3 f = vec3(colR, colG, colB);\n" +
"\n" +
" \n" +
" fragColor = vec4(f, 1.);\n" +
"}" +
"\nvoid main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iResolutionLocation = -1;
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = (((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f) + 1;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,108 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class DrunkDialFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
"\t// Just playing around with shaders for my first time.\n" +
"\t// Pardon the unoptimized mess.\n" +
"\t// -Dan\n" +
"\tfloat drunk = sin(iTime*2.0)*6.0;\n" +
"\tfloat unitDrunk1 = (sin(iTime*1.2)+1.0)/2.0;\n" +
"\tfloat unitDrunk2 = (sin(iTime*1.8)+1.0)/2.0;\n" +
"\n" +
"\tvec2 normalizedCoord = mod((fragCoord.xy + vec2(0, drunk)) / iResolution.xy, 1.0);\n" +
"\tnormalizedCoord.x = pow(normalizedCoord.x, mix(1.25, 0.85, unitDrunk1));\n" +
"\tnormalizedCoord.y = pow(normalizedCoord.y, mix(0.85, 1.25, unitDrunk2));\n" +
"\n" +
"\tvec2 normalizedCoord2 = mod((fragCoord.xy + vec2(drunk, 0)) / iResolution.xy, 1.0);\t\n" +
"\tnormalizedCoord2.x = pow(normalizedCoord2.x, mix(0.95, 1.1, unitDrunk2));\n" +
"\tnormalizedCoord2.y = pow(normalizedCoord2.y, mix(1.1, 0.95, unitDrunk1));\n" +
"\n" +
"\tvec2 normalizedCoord3 = fragCoord.xy/iResolution.xy;\n" +
"\t\n" +
"\tvec4 color = texture2D(iChannel0, normalizedCoord);\t\n" +
"\tvec4 color2 = texture2D(iChannel0, normalizedCoord2);\n" +
"\tvec4 color3 = texture2D(iChannel0, normalizedCoord3);\n" +
"\n" +
"\t// Mess with colors and test swizzling\n" +
"\tcolor.x = sqrt(color2.x);\n" +
"\tcolor2.x = sqrt(color2.x);\n" +
"\t\n" +
"\tvec4 finalColor = mix( mix(color, color2, mix(0.4, 0.6, unitDrunk1)), color3, 0.4);\n" +
"\t\n" +
"\t// \n" +
"\tif (length(finalColor) > 1.4)\n" +
"\t\tfinalColor.xy = mix(finalColor.xy, normalizedCoord3, 0.5);\n" +
"\telse if (length(finalColor) < 0.4)\n" +
"\t\tfinalColor.yz = mix(finalColor.yz, normalizedCoord3, 0.5);\n" +
"\t\t\n" +
"\tfragColor = finalColor;\t\t\n" +
"}\n"+
"\nvoid main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iResolutionLocation = -1;
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = (((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f) + 1;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,83 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class EMInterferenceFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform float iGlobalTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"float rng2(vec2 seed)\n" +
"{\n" +
" return fract(sin(dot(seed * floor(iGlobalTime * 12.), vec2(127.1,311.7))) * 43758.5453123);\n" +
"}\n" +
"\n" +
"float rng(float seed)\n" +
"{\n" +
" return rng2(vec2(seed, 1.0));\n" +
"}\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
"\tvec2 uv = fragCoord.xy;\n" +
" vec2 blockS = floor(uv * vec2(24., 9.));\n" +
" vec2 blockL = floor(uv * vec2(8., 4.));\n" +
"\n" +
" float r = rng2(uv);\n" +
" vec3 noise = (vec3(r, 1. - r, r / 2. + 0.5) * 1.0 - 2.0) * 0.08;\n" +
"\n" +
" float lineNoise = pow(rng2(blockS), 8.0) * pow(rng2(blockL), 3.0) - pow(rng(7.2341), 17.0) * 2.;\n" +
"\n" +
" vec4 col1 = texture2D(iChannel0, uv);\n" +
" vec4 col2 = texture2D(iChannel0, uv + vec2(lineNoise * 0.05 * rng(5.0), 0));\n" +
" vec4 col3 = texture2D(iChannel0, uv - vec2(lineNoise * 0.05 * rng(31.0), 0));\n" +
"\n" +
"\tfragColor = vec4(vec3(col1.x, col2.y, col3.z) + noise, 1.0);\n" +
"}\n" +
"\n" +
"void main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ");\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iGlobalTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iGlobalTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,106 @@
package com.otaliastudios.cameraview.filters;
import android.content.Context;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.R;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.ContextParameterFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class EarlybirdFilter extends BaseFilter implements ContextParameterFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float; \n" +
"uniform samplerExternalOES sTexture; \n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + "; \n" +
"const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" +
"\n" +
"vec3 BrightnessContrastSaturation(vec3 color, float brt, float con, float sat)\n" +
"{\n" +
"\tvec3 black = vec3(0., 0., 0.);\n" +
"\tvec3 middle = vec3(0.5, 0.5, 0.5);\n" +
"\tfloat luminance = dot(color, W);\n" +
"\tvec3 gray = vec3(luminance, luminance, luminance);\n" +
"\t\n" +
"\tvec3 brtColor = mix(black, color, brt);\n" +
"\tvec3 conColor = mix(middle, brtColor, con);\n" +
"\tvec3 satColor = mix(gray, conColor, sat);\n" +
"\treturn satColor;\n" +
"}\n" +
"\n" +
"vec3 ovelayBlender(vec3 Color, vec3 filter){\n" +
"\tvec3 filter_result;\n" +
"\tfloat luminance = dot(filter, W);\n" +
"\t\n" +
"\tif(luminance < 0.5)\n" +
"\t\tfilter_result = 2. * filter * Color;\n" +
"\telse\n" +
"\t\tfilter_result = 1. - (1. - (2. *(filter - 0.5)))*(1. - Color);\n" +
"\t\t\n" +
"\treturn filter_result;\n" +
"}\n" +
"\n" +
"vec3 multiplyBlender(vec3 Color, vec3 filter){\n" +
"\tvec3 filter_result;\n" +
"\tfloat luminance = dot(filter, W);\n" +
"\t\n" +
"\tif(luminance < 0.5)\n" +
"\t\tfilter_result = 2. * filter * Color;\n" +
"\telse\n" +
"\t\tfilter_result = Color;\n" +
"\t\t\t\n" +
"\treturn filter_result;\n" +
"}\n" +
"\n" +
"void main()\n" +
"{\n" +
"\t //get the pixel\n" +
" vec2 st = " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ".st;\n" +
" vec3 irgb = texture2D(sTexture, st).rgb;\n" +
" \n" +
" //adjust the brightness/contrast/saturation\n" +
" float T_bright = 1.2;\n" +
" float T_contrast = 1.1;\n" +
" float T_saturation = 1.2;\n" +
" vec3 bcs_result = BrightnessContrastSaturation(irgb, T_bright, T_contrast, T_saturation);\n" +
" \n" +
" //more red, less blue\n" +
" vec3 rb_result = vec3(bcs_result.r*1.1, bcs_result.g, bcs_result.b*0.9);\n" +
" \n" +
" gl_FragColor = vec4(rb_result, 1.);\n" +
"}";
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
}
@Override
public void setContext(Context value) {
}
}

@ -0,0 +1,48 @@
package com.otaliastudios.cameraview.filters;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
public class EdgeDetectionFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"#extension GL_OES_standard_derivatives : enable\n" +
"precision highp float;\n" +
"\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" vec2 uv = fragCoord.xy;\n" +
" vec4 color = texture2D(iChannel0, fragCoord);\n" +
" float gray = length(color.rgb);\n" +
" fragColor = vec4(vec3(step(0.06, length(vec2(dFdx(gray), dFdy(gray))))), 1.0);\n" +
"}\n" +
"\n" +
"void main() {\n" +
" mainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ");\n" +
"}";
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
}
}

@ -0,0 +1,143 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class EdgeGlowFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"/* Returns rgb vec from input 0-1 */\n" +
"vec3 getRainbowColor(in float val) {\n" +
" /*convert to rainbow RGB*/\n" +
" float a = (1.0 - val) * 6.0;\n" +
" int X = int(floor(a));\n" +
" float Y = a - float(X);\n" +
" float r = 0.;\n" +
" float g = 0.;\n" +
" float b = 0.;\n" +
" if (X == 0) {\n" +
" r = 1.; g = Y; b = 0.;\n" +
" } else if (X == 1) {\n" +
" r = 1. - Y; g = 1.; b = 0.;\n" +
" } else if (X == 2) {\n" +
" r = 0.; g = 1.; b = Y;\n" +
" } else if (X == 3) {\n" +
" r = 0.; g = 1. - Y; b = 1.;\n" +
" } else if (X == 4) {\n" +
" r = Y; g = 0.; b = 1.;\n" +
" } else if (X == 5) {\n" +
" r = 1.; g = 0.; b = 1. - Y;\n" +
" } else {\n" +
" r = 0.; g = 0.; b = 0.;\n" +
" }\n" +
" return vec3(r, g, b);\n" +
"}\n" +
"\n" +
"float d;\n" +
"\n" +
"float lookup(vec2 p, float dx, float dy, float edgeIntensity)\n" +
"{\n" +
" vec2 uv = (p.xy + vec2(dx * edgeIntensity, dy * edgeIntensity)) / iResolution.xy;\n" +
" vec4 c = texture2D(iChannel0, uv.xy);\n" +
"\t\n" +
"\t// return as luma\n" +
" return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n" +
"}\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" float timeNorm = mod(iTime, 5.) / 5.;\n" +
" vec3 glowCol = getRainbowColor(timeNorm);\n" +
" float edgeIntensity = 1.;\n" +
" if (timeNorm < .5) { edgeIntensity += (4. * timeNorm);}\n" +
" else { edgeIntensity += -4. * (timeNorm - 1.); }\n" +
" vec2 p = fragCoord.xy;\n" +
" \n" +
"\t// simple sobel edge detection\n" +
" float gx = 0.0;\n" +
" gx += -1.0 * lookup(p, -1.0, -1.0, edgeIntensity);\n" +
" gx += -2.0 * lookup(p, -1.0, 0.0, edgeIntensity);\n" +
" gx += -1.0 * lookup(p, -1.0, 1.0, edgeIntensity);\n" +
" gx += 1.0 * lookup(p, 1.0, -1.0, edgeIntensity);\n" +
" gx += 2.0 * lookup(p, 1.0, 0.0, edgeIntensity);\n" +
" gx += 1.0 * lookup(p, 1.0, 1.0, edgeIntensity);\n" +
" \n" +
" float gy = 0.0;\n" +
" gy += -1.0 * lookup(p, -1.0, -1.0, edgeIntensity);\n" +
" gy += -2.0 * lookup(p, 0.0, -1.0, edgeIntensity);\n" +
" gy += -1.0 * lookup(p, 1.0, -1.0, edgeIntensity);\n" +
" gy += 1.0 * lookup(p, -1.0, 1.0, edgeIntensity);\n" +
" gy += 2.0 * lookup(p, 0.0, 1.0, edgeIntensity);\n" +
" gy += 1.0 * lookup(p, 1.0, 1.0, edgeIntensity);\n" +
" \n" +
"\t// hack: use g^2 to conceal noise in the video\n" +
" float g = gx*gx + gy*gy;\n" +
" \n" +
" vec4 col = texture2D(iChannel0, p / iResolution.xy);\n" +
" col += vec4(g * glowCol, 1.0);\n" +
" \n" +
" fragColor = col;\n" +
"}" +
"\n" +
"void main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,77 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.OneParameterFilter;
import com.otaliastudios.cameraview.filter.TwoParameterFilter;
import com.otaliastudios.opengl.core.Egloo;
/**
* exposure: The adjusted exposure (-1 - 0 - 1 as the default)
*/
public class ExposureFilter extends BaseFilter implements OneParameterFilter {
private static final String EXPOSURE_FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
"uniform samplerExternalOES sTexture;\n" +
"uniform float exposure;\n" +
"varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n" +
"void main()\n" +
"{\n" +
" vec4 textureColor = texture2D(sTexture, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n" +
" gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);\n" +
"}";
private float exposure = 1f;
private int exposureLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return EXPOSURE_FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
exposureLocation = GLES20.glGetUniformLocation(programHandle, "exposure");
Egloo.checkGlProgramLocation(exposureLocation, "exposure");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
GLES20.glUniform1f(exposureLocation, exposure);
Egloo.checkGlError("glUniform1f");
}
@Override
public void onDestroy() {
super.onDestroy();
exposure = 1f;
exposureLocation = -1;
}
@Override
public void setParameter1(float value) {
setExposure(value);
}
@Override
public float getParameter1() {
return getExposure();
}
public float getExposure() {
return exposure;
}
/**
* exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default)
*/
public void setExposure(float exposure) {
this.exposure = exposure;
}
}

@ -0,0 +1,115 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.OneParameterFilter;
import com.otaliastudios.cameraview.filter.TwoParameterFilter;
import com.otaliastudios.opengl.core.Egloo;
/**
* exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default)
*/
public class HalftoneFilter extends BaseFilter implements TwoParameterFilter {
private static final String EXPOSURE_FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"varying vec2 vTextureCoord;\n" +
"uniform samplerExternalOES sTexture;\n" +
"uniform highp float fractionalWidthOfPixel;\n" +
"uniform highp float aspectRatio;\n" +
"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" +
"void main()\n" +
"{\n" +
" highp vec2 sampleDivisor = vec2(fractionalWidthOfPixel, fractionalWidthOfPixel / aspectRatio);\n" +
" highp vec2 samplePos = vTextureCoord - mod(vTextureCoord, sampleDivisor) + 0.5 * sampleDivisor;\n" +
" highp vec2 textureCoordinateToUse = vec2(vTextureCoord.x, (vTextureCoord.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\n" +
" highp vec2 adjustedSamplePos = vec2(samplePos.x, (samplePos.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\n" +
" highp float distanceFromSamplePoint = distance(adjustedSamplePos, textureCoordinateToUse);\n" +
" lowp vec3 sampledColor = texture2D(sTexture, samplePos).rgb;\n" +
" highp float dotScaling = 1.0 - dot(sampledColor, W);\n" +
" lowp float checkForPresenceWithinDot = 1.0 - step(distanceFromSamplePoint, (fractionalWidthOfPixel * 0.5) * dotScaling);\n" +
" gl_FragColor = vec4(vec3(checkForPresenceWithinDot), 1.0);\n" +
"}";
private float fractionalWidthOfPixel = 0.01f;
private int fractionalWidthOfPixelLocation = -1;
private float aspectRatio = 1f;
private int aspectRatioLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return EXPOSURE_FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
fractionalWidthOfPixelLocation = GLES20.glGetUniformLocation(programHandle, "fractionalWidthOfPixel");
Egloo.checkGlProgramLocation(fractionalWidthOfPixelLocation, "fractionalWidthOfPixel");
aspectRatioLocation = GLES20.glGetUniformLocation(programHandle, "aspectRatio");
Egloo.checkGlProgramLocation(aspectRatioLocation, "aspectRatio");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
GLES20.glUniform1f(fractionalWidthOfPixelLocation, fractionalWidthOfPixel);
GLES20.glUniform1f(aspectRatioLocation, aspectRatio);
Egloo.checkGlError("glUniform1f");
}
@Override
public void onDestroy() {
super.onDestroy();
fractionalWidthOfPixel = 0.01f;
fractionalWidthOfPixelLocation = -1;
aspectRatio = 1f;
aspectRatioLocation = -1;
}
@Override
public void setParameter1(float value) {
setFractionalWidthOfPixel(value);
}
@Override
public float getParameter1() {
return getFractionalWidthOfPixel();
}
@Override
public void setParameter2(float value) {
setAspectRatio(value);
}
@Override
public float getParameter2() {
return getAspectRatio();
}
public float getFractionalWidthOfPixel() {
return fractionalWidthOfPixel;
}
public void setFractionalWidthOfPixel(float fractionalWidthOfPixel) {
this.fractionalWidthOfPixel = fractionalWidthOfPixel;
}
public float getAspectRatio() {
return aspectRatio;
}
public void setAspectRatio(float aspectRatio) {
this.aspectRatio = aspectRatio;
}
}

@ -0,0 +1,141 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class HighEdgeGlowFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"/* Returns rgb vec from input 0-1 */\n" +
"vec3 getRainbowColor(in float val) {\n" +
" /*convert to rainbow RGB*/\n" +
" float a = (1.0 - val) * 6.0;\n" +
" int X = int(floor(a));\n" +
" float Y = a - float(X);\n" +
" float r = 0.;\n" +
" float g = 0.;\n" +
" float b = 0.;\n" +
" if (X == 0) {\n" +
" r = 1.; g = Y; b = 0.;\n" +
" } else if (X == 1) {\n" +
" r = 1. - Y; g = 1.; b = 0.;\n" +
" } else if (X == 2) {\n" +
" r = 0.; g = 1.; b = Y;\n" +
" } else if (X == 3) {\n" +
" r = 0.; g = 1. - Y; b = 1.;\n" +
" } else if (X == 4) {\n" +
" r = Y; g = 0.; b = 1.;\n" +
" } else if (X == 5) {\n" +
" r = 1.; g = 0.; b = 1. - Y;\n" +
" } else {\n" +
" r = 0.; g = 0.; b = 0.;\n" +
" }\n" +
" return vec3(r, g, b);\n" +
"}\n" +
"\n" +
"float d;\n" +
"\n" +
"float lookup(vec2 p, float dx, float dy, float edgeIntensity)\n" +
"{\n" +
" vec2 uv = (p.xy + vec2(dx * edgeIntensity, dy * edgeIntensity)) / iResolution.xy;\n" +
" vec4 c = texture2D(iChannel0, uv.xy);\n" +
"\t\n" +
"\t// return as luma\n" +
" return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n" +
"}\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" float timeNorm = mod(iTime, 5.) / 5.;\n" +
" vec3 glowCol = getRainbowColor(timeNorm);\n" +
" float edgeIntensity = 10.;\n" +
" vec2 p = fragCoord.xy;\n" +
" \n" +
"\t// simple sobel edge detection\n" +
" float gx = 0.0;\n" +
" gx += -1.0 * lookup(p, -1.0, -1.0, edgeIntensity);\n" +
" gx += -2.0 * lookup(p, -1.0, 0.0, edgeIntensity);\n" +
" gx += -1.0 * lookup(p, -1.0, 1.0, edgeIntensity);\n" +
" gx += 1.0 * lookup(p, 1.0, -1.0, edgeIntensity);\n" +
" gx += 2.0 * lookup(p, 1.0, 0.0, edgeIntensity);\n" +
" gx += 1.0 * lookup(p, 1.0, 1.0, edgeIntensity);\n" +
" \n" +
" float gy = 0.0;\n" +
" gy += -1.0 * lookup(p, -1.0, -1.0, edgeIntensity);\n" +
" gy += -2.0 * lookup(p, 0.0, -1.0, edgeIntensity);\n" +
" gy += -1.0 * lookup(p, 1.0, -1.0, edgeIntensity);\n" +
" gy += 1.0 * lookup(p, -1.0, 1.0, edgeIntensity);\n" +
" gy += 2.0 * lookup(p, 0.0, 1.0, edgeIntensity);\n" +
" gy += 1.0 * lookup(p, 1.0, 1.0, edgeIntensity);\n" +
" \n" +
"\t// hack: use g^2 to conceal noise in the video\n" +
" float g = gx*gx + gy*gy;\n" +
" \n" +
" vec4 col = texture2D(iChannel0, p / iResolution.xy);\n" +
" col += vec4(g * glowCol, 1.0);\n" +
" \n" +
" fragColor = col;\n" +
"}" +
"\n" +
"void main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,112 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.TwoParameterFilter;
import com.otaliastudios.opengl.core.Egloo;
/**
* between 0.0 to 1.0
*/
public class HighlightShadowFilter extends BaseFilter implements TwoParameterFilter {
private static final String EXPOSURE_FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
" uniform samplerExternalOES sTexture;\n" +
" uniform float shadows;\n" +
" uniform float highlights;\n" +
" varying vec2 vTextureCoord;\n" +
" \n" +
" const mediump vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);\n" +
" \n" +
" void main()\n" +
" {\n" +
" vec4 source = texture2D(sTexture, vTextureCoord);\n" +
" mediump float luminance = dot(source.rgb, luminanceWeighting);\n" +
" \n" +
" mediump float shadow = clamp((pow(luminance, 1.0/(shadows+1.0)) + (-0.76)*pow(luminance, 2.0/(shadows+1.0))) - luminance, 0.0, 1.0);\n" +
" mediump float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0);\n" +
" lowp vec3 result = vec3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((source.rgb - vec3(0.0, 0.0, 0.0))/(luminance - 0.0));\n" +
" \n" +
" gl_FragColor = vec4(result.rgb, source.a);\n" +
" }";
private float shadows = 1f;
private int shadowsLocation = -1;
private float highlights = 0f;
private int highlightsLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return EXPOSURE_FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
shadowsLocation = GLES20.glGetUniformLocation(programHandle, "shadows");
Egloo.checkGlProgramLocation(shadowsLocation, "shadows");
highlightsLocation = GLES20.glGetUniformLocation(programHandle, "highlights");
Egloo.checkGlProgramLocation(highlightsLocation, "highlights");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
GLES20.glUniform1f(shadowsLocation, shadows);
GLES20.glUniform1f(highlightsLocation, highlights);
Egloo.checkGlError("glUniform1f");
}
@Override
public void onDestroy() {
super.onDestroy();
shadows = 1f;
shadowsLocation = -1;
highlights = 0f;
highlightsLocation = -1;
}
@Override
public void setParameter1(float value) {
setShadows(value);
}
@Override
public float getParameter1() {
return getShadows();
}
@Override
public void setParameter2(float value) {
setHighlights(value);
}
@Override
public float getParameter2() {
return getHighlights();
}
public float getShadows() {
return shadows;
}
public void setShadows(float shadows) {
this.shadows = shadows;
}
public float getHighlights() {
return highlights;
}
public void setHighlights(float highlights) {
this.highlights = highlights;
}
}

@ -0,0 +1,82 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.filter.OneParameterFilter;
import com.otaliastudios.opengl.core.Egloo;
/**
* exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default)
*/
public class LuminanceThresholdFilter extends BaseFilter implements OneParameterFilter {
private static final String EXPOSURE_FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;" +
"varying highp vec2 vTextureCoord;\n" +
"\n" +
"uniform samplerExternalOES sTexture;\n" +
"uniform highp float threshold;\n" +
"\n" +
"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" +
"\n" +
"void main()\n" +
"{\n" +
" highp vec4 textureColor = texture2D(sTexture, vTextureCoord);\n" +
" highp float luminance = dot(textureColor.rgb, W);\n" +
" highp float thresholdResult = step(threshold, luminance);\n" +
" \n" +
" gl_FragColor = vec4(vec3(thresholdResult), textureColor.w);\n" +
"}";
private float threshold = 0.5f;
private int thresholdLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return EXPOSURE_FRAGMENT_SHADER;
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
thresholdLocation = GLES20.glGetUniformLocation(programHandle, "threshold");
Egloo.checkGlProgramLocation(thresholdLocation, "threshold");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
GLES20.glUniform1f(thresholdLocation, threshold);
Egloo.checkGlError("glUniform1f");
}
@Override
public void onDestroy() {
super.onDestroy();
threshold = 0.5f;
thresholdLocation = -1;
}
@Override
public void setParameter1(float value) {
setThreshold(value);
}
@Override
public float getParameter1() {
return getThreshold();
}
public float getThreshold() {
return threshold;
}
public void setThreshold(float threshold) {
this.threshold = threshold;
}
}

@ -0,0 +1,49 @@
package com.otaliastudios.cameraview.filters;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
public class MirrorFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
" {\n" +
" vec2 flipCoord = vec2(1.0-fragCoord.x, fragCoord.y);\n" +
" if(flipCoord.x >= 0.5){\n" +
" \tfragColor = texture2D(iChannel0, vec2( flipCoord.x - 0.5, flipCoord.y ));\n" +
" } else {\n" +
" \tfragColor = texture2D(iChannel0, vec2( 0.5 - flipCoord.x,flipCoord.y ));\n" +
" }\n" +
" }\n" +
"\n" +
"void main() {\n" +
" \tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ");\n" +
" }";
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
}
}

@ -0,0 +1,143 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class NeonEdgeGlowFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform float iTime;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"/* Returns rgb vec from input 0-1 */\n" +
"vec3 getRainbowColor(in float val) {\n" +
" /*convert to rainbow RGB*/\n" +
" float a = (1.0 - val) * 6.0;\n" +
" int X = int(floor(a));\n" +
" float Y = a - float(X);\n" +
" float r = 0.;\n" +
" float g = 0.;\n" +
" float b = 0.;\n" +
" if (X == 0) {\n" +
" r = 1.; g = Y; b = 0.;\n" +
" } else if (X == 1) {\n" +
" r = 1. - Y; g = 1.; b = 0.;\n" +
" } else if (X == 2) {\n" +
" r = 0.; g = 1.; b = Y;\n" +
" } else if (X == 3) {\n" +
" r = 0.; g = 1. - Y; b = 1.;\n" +
" } else if (X == 4) {\n" +
" r = Y; g = 0.; b = 1.;\n" +
" } else if (X == 5) {\n" +
" r = 1.; g = 0.; b = 1. - Y;\n" +
" } else {\n" +
" r = 0.; g = 0.; b = 0.;\n" +
" }\n" +
" return vec3(57,255,20);\n" +
"}\n" +
"\n" +
"float d;\n" +
"\n" +
"float lookup(vec2 p, float dx, float dy, float edgeIntensity)\n" +
"{\n" +
" vec2 uv = (p.xy + vec2(dx * edgeIntensity, dy * edgeIntensity)) / iResolution.xy;\n" +
" vec4 c = texture2D(iChannel0, uv.xy);\n" +
"\t\n" +
"\t// return as luma\n" +
" return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b;\n" +
"}\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" float timeNorm = mod(iTime, 5.) / 5.;\n" +
" vec3 glowCol = getRainbowColor(timeNorm);\n" +
" float edgeIntensity = 1.;\n" +
" if (timeNorm < .5) { edgeIntensity += (4. * timeNorm);}\n" +
" else { edgeIntensity += -4. * (timeNorm - 1.); }\n" +
" vec2 p = fragCoord.xy;\n" +
" \n" +
"\t// simple sobel edge detection\n" +
" float gx = 0.0;\n" +
" gx += -1.0 * lookup(p, -1.0, -1.0, edgeIntensity);\n" +
" gx += -2.0 * lookup(p, -1.0, 0.0, edgeIntensity);\n" +
" gx += -1.0 * lookup(p, -1.0, 1.0, edgeIntensity);\n" +
" gx += 1.0 * lookup(p, 1.0, -1.0, edgeIntensity);\n" +
" gx += 2.0 * lookup(p, 1.0, 0.0, edgeIntensity);\n" +
" gx += 1.0 * lookup(p, 1.0, 1.0, edgeIntensity);\n" +
" \n" +
" float gy = 0.0;\n" +
" gy += -1.0 * lookup(p, -1.0, -1.0, edgeIntensity);\n" +
" gy += -2.0 * lookup(p, 0.0, -1.0, edgeIntensity);\n" +
" gy += -1.0 * lookup(p, 1.0, -1.0, edgeIntensity);\n" +
" gy += 1.0 * lookup(p, -1.0, 1.0, edgeIntensity);\n" +
" gy += 2.0 * lookup(p, 0.0, 1.0, edgeIntensity);\n" +
" gy += 1.0 * lookup(p, 1.0, 1.0, edgeIntensity);\n" +
" \n" +
"\t// hack: use g^2 to conceal noise in the video\n" +
" float g = gx*gx + gy*gy;\n" +
" \n" +
" vec4 col = texture2D(iChannel0, p / iResolution.xy);\n" +
" col += vec4(g * glowCol, 1.0);\n" +
" \n" +
" fragColor = col;\n" +
"}" +
"\n" +
"void main() {\n" +
"\tmainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + " * iResolution.xy);\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = (((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f) + 1;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,88 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class RainbowFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"uniform float iTime;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ";\n" +
"\n" +
"vec2 size = vec2(50.0, 50.0);\n" +
"vec2 distortion = vec2(20.0, 20.0);\n" +
"float speed = 0.75;" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
"{\n" +
" vec2 transformed = vec2(\n" +
" fragCoord.x + sin(fragCoord.y / size.x + iTime * speed) * distortion.x,\n" +
" fragCoord.y + cos(fragCoord.x / size.y + iTime * speed) * distortion.y\n" +
" );\n" +
" vec2 relCoord = fragCoord.xy / iResolution.xy;\n" +
" fragColor = texture2D(iChannel0, fragCoord/iResolution.xy) + vec4(\n" +
" (cos(relCoord.x + iTime * speed * 4.0) + 1.0) / 2.0,\n" +
" (relCoord.x + relCoord.y) / 2.0,\n" +
" (sin(relCoord.y + iTime * speed) + 1.0) / 2.0,\n" +
" 0\n" +
" );\n" +
"}\n" +
"void main() {\n" +
" mainImage(gl_FragColor, " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ");\n" +
"}";
long START_TIME = System.currentTimeMillis();
private int iGlobalTimeLocation = -1;
private int iResolutionLocation = -1;
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
iGlobalTimeLocation = -1;
START_TIME = System.currentTimeMillis();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
iResolutionLocation = GLES20.glGetUniformLocation(programHandle, "iResolution");
Egloo.checkGlProgramLocation(iResolutionLocation, "iResolution");
iGlobalTimeLocation = GLES20.glGetUniformLocation(programHandle, "iTime");
Egloo.checkGlProgramLocation(iGlobalTimeLocation, "iTime");
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
Size size = getSize();
if (size != null) {
GLES20.glUniform3fv(iResolutionLocation, 1,
FloatBuffer.wrap(new float[]{(float) size.getWidth(), (float) size.getHeight(), 1.0f}));
Egloo.checkGlError("glUniform3fv");
}
float time = ((float) (System.currentTimeMillis() - START_TIME)) / 1000.0f;
GLES20.glUniform1f(iGlobalTimeLocation, time);
Egloo.checkGlError("glUniform1f");
}
}

@ -0,0 +1,46 @@
package com.otaliastudios.cameraview.filters;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
public class TextureHelper {
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
}

@ -0,0 +1,90 @@
package com.otaliastudios.cameraview.filters;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.opengl.core.Egloo;
import java.nio.FloatBuffer;
public class ToasterFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float; \n" +
"uniform samplerExternalOES u_Texture0; \n" +
// "uniform sampler2D u_Texture4;\n" +
"varying vec2 " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + "; \n" +
"const vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" +
"\n" +
"vec3 BrightnessContrastSaturation(vec3 color, float brt, float con, float sat)\n" +
"{\n" +
"\tvec3 black = vec3(0., 0., 0.);\n" +
"\tvec3 middle = vec3(0.5, 0.5, 0.5);\n" +
"\tfloat luminance = dot(color, W);\n" +
"\tvec3 gray = vec3(luminance, luminance, luminance);\n" +
"\t\n" +
"\tvec3 brtColor = mix(black, color, brt);\n" +
"\tvec3 conColor = mix(middle, brtColor, con);\n" +
"\tvec3 satColor = mix(gray, conColor, sat);\n" +
"\treturn satColor;\n" +
"}\n" +
"\n" +
"vec3 ovelayBlender(vec3 Color, vec3 filter){\n" +
"\tvec3 filter_result;\n" +
"\t\n" +
"\t//if(luminance < 0.5)\n" +
"\t//\tfilter_result = 2. * trans_filter * Color;\n" +
"\t//else\n" +
"\t\tfilter_result = 1. - (1. - (2. *(filter - 0.5)))*(1. - Color);\n" +
"\t\t\n" +
"\treturn filter_result;\n" +
"}\n" +
"\n" +
"void main()\n" +
"{\n" +
"\t //get the pixel\n" +
" vec2 st = " + DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME + ".st;\n" +
" vec3 irgb = texture2D(u_Texture0, st).rgb;\n" +
// " vec3 filter = texture2D(u_Texture4, st).rgb;\n" +
" \n" +
" //adjust the brightness/contrast/saturation\n" +
" float T_bright = 1.0;\n" +
" float T_contrast = 1.0;\n" +
" float T_saturation = 1.0;\n" +
" vec3 bcs_result = BrightnessContrastSaturation(irgb, T_bright, T_contrast, T_saturation);\n" +
" \n" +
" //more red\n" +
" vec3 rb_result = vec3(bcs_result.r*1.3, bcs_result.g, bcs_result.b*0.9);\n" +
" \n" +
// " //add filter (overlay blending)\n" +
// " vec3 after_filter = mix(bcs_result, ovelayBlender(bcs_result, filter), 0.55);\n" +
" \t\n" +
" gl_FragColor = vec4(rb_result, 1.);\n" +
"}";
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onCreate(int programHandle) {
super.onCreate(programHandle);
}
@Override
protected void onPreDraw(long timestampUs, @NonNull float[] transformMatrix) {
super.onPreDraw(timestampUs, transformMatrix);
}
}

@ -0,0 +1,38 @@
package com.otaliastudios.cameraview.filters;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.filter.BaseFilter;
public class WavesReflectionFilter extends BaseFilter {
private static final String FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision highp float;\n" +
"\n" +
"uniform vec3 iResolution;\n" +
"uniform samplerExternalOES iChannel0;\n" +
"varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n" +
"\n" +
"float waterLevel = 0.5;\n" +
"float waveAmplitude = 0.01;\n" +
"\n" +
"void mainImage( out vec4 fragColor, in vec2 fragCoord )\n" +
" {\n" +
" if(fragCoord.y >= waterLevel){\n" +
" fragColor = texture2D(iChannel0, fragCoord);\n" +
" }else{\n" +
" fragColor = texture2D(iChannel0,vec2(fragCoord.x + fract(sin(dot(fragCoord.xy ,vec2(12.9898,78.233))) * 43758.5453) * waveAmplitude,\n" +
" \t\t\t\t2.0 * waterLevel - fragCoord.y));\n" +
" }\n" +
" }\n" +
"\n" +
"void main() {\n" +
" \tmainImage(gl_FragColor, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n" +
" }";
@NonNull
@Override
public String getFragmentShader() {
return FRAGMENT_SHADER;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 KiB

Loading…
Cancel
Save