Create MultiFilter base implementation

pull/559/head
Mattia Iavarone 6 years ago
parent 7b038f9588
commit e4f9b6a209
  1. 150
      cameraview/src/main/java/com/otaliastudios/cameraview/filter/MultiFilter.java
  2. 14
      cameraview/src/main/java/com/otaliastudios/cameraview/internal/egl/EglViewport.java

@ -0,0 +1,150 @@
package com.otaliastudios.cameraview.filter;
import android.opengl.GLES20;
import androidx.annotation.NonNull;
import com.otaliastudios.cameraview.internal.GlUtils;
import com.otaliastudios.cameraview.size.Size;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class MultiFilter implements Filter {
private static class State {
boolean isCreated = false;
int programHandle = -1;
Size size = null;
}
private final Map<Filter, State> filters = new HashMap<>();
private final Object lock = new Object();
private Size size = null;
@SuppressWarnings("WeakerAccess")
public MultiFilter(@NonNull Filter... filters) {
this(Arrays.asList(filters));
}
@SuppressWarnings("WeakerAccess")
public MultiFilter(@NonNull Collection<Filter> filters) {
for (Filter filter : filters) {
addFilter(filter);
}
}
@SuppressWarnings("WeakerAccess")
public void addFilter(@NonNull Filter filter) {
if (filter instanceof MultiFilter) {
MultiFilter multiFilter = (MultiFilter) filter;
for (Filter multiChild : multiFilter.filters.keySet()) {
addFilter(multiChild);
}
return;
}
synchronized (lock) {
if (!filters.keySet().contains(filter)) {
filters.put(filter, new State());
}
}
}
// We don't offer a removeFilter method since that would cause issues
// with cleanup. Cleanup must happen on the GL thread so we'd have to wait
// for new rendering call (which might not even happen).
private void maybeCreate(@NonNull Filter filter) {
State state = filters.get(filter);
//noinspection ConstantConditions
if (!state.isCreated) {
state.isCreated = true;
state.programHandle = GlUtils.createProgram(filter.getVertexShader(), filter.getFragmentShader());
filter.onCreate(state.programHandle);
// TODO extra creation
}
}
private void maybeDestroy(@NonNull Filter filter) {
State state = filters.get(filter);
//noinspection ConstantConditions
if (state.isCreated) {
state.isCreated = false;
filter.onDestroy();
GLES20.glDeleteProgram(state.programHandle);
state.programHandle = -1;
// TODO extra cleanup.
}
}
private void maybeSetSize(@NonNull Filter filter) {
State state = filters.get(filter);
//noinspection ConstantConditions
if (size != null && !size.equals(state.size)) {
state.size = size;
filter.setSize(size.getWidth(), size.getHeight());
}
}
@NonNull
@Override
public String getVertexShader() {
return new NoFilter().getVertexShader();
}
@NonNull
@Override
public String getFragmentShader() {
return new NoFilter().getFragmentShader();
}
@Override
public void onCreate(int programHandle) {
// We'll create children during the draw() op, since some of them
// might have been added after this onCreate() is called.
}
@Override
public void onDestroy() {
synchronized (lock) {
for (Filter filter : filters.keySet()) {
maybeDestroy(filter);
}
}
}
@Override
public void setSize(int width, int height) {
size = new Size(width, height);
synchronized (lock) {
for (Filter filter : filters.keySet()) {
maybeSetSize(filter);
}
}
}
@Override
public void draw(float[] transformMatrix) {
synchronized (lock) {
for (Filter filter : filters.keySet()) {
maybeCreate(filter);
maybeSetSize(filter);
}
}
// TODO
}
@NonNull
@Override
public Filter copy() {
synchronized (lock) {
MultiFilter copy = new MultiFilter();
for (Filter filter : filters.keySet()) {
copy.addFilter(filter.copy());
}
return copy;
}
}
}

@ -21,7 +21,7 @@ public class EglViewport {
private int mTextureUnit; private int mTextureUnit;
private Filter mFilter; private Filter mFilter;
private boolean mFilterChanged = false; private Filter mPendingFilter;
public EglViewport() { public EglViewport() {
this(new NoFilter()); this(new NoFilter());
@ -35,7 +35,6 @@ public class EglViewport {
} }
private void createProgram() { private void createProgram() {
release(); // Release old program if present.
mProgramHandle = GlUtils.createProgram(mFilter.getVertexShader(), mFilter.getFragmentShader()); mProgramHandle = GlUtils.createProgram(mFilter.getVertexShader(), mFilter.getFragmentShader());
mFilter.onCreate(mProgramHandle); mFilter.onCreate(mProgramHandle);
} }
@ -67,15 +66,16 @@ public class EglViewport {
return texId; return texId;
} }
public void setFilter(@NonNull Filter filter){ public void setFilter(@NonNull Filter filter) {
this.mFilter = filter; mPendingFilter = filter;
mFilterChanged = true;
} }
public void drawFrame(int textureId, float[] textureMatrix) { public void drawFrame(int textureId, float[] textureMatrix) {
if (mFilterChanged) { if (mPendingFilter != null) {
release();
mFilter = mPendingFilter;
mPendingFilter = null;
createProgram(); createProgram();
mFilterChanged = false;
} }
GlUtils.checkError("draw start"); GlUtils.checkError("draw start");

Loading…
Cancel
Save