package com.marshalchen.common.uimodule.imageprocessing.filter;
import java.util.ArrayList;
import java.util.List;
import com.marshalchen.common.uimodule.imageprocessing.input.GLTextureOutputRenderer;
import android.opengl.GLES20;
/**
* A multiple filter input extension of the BasicFilter.
* This class allows for multiple textures as inputs to the filter.
* This class can be used as the base for a filter which requires multiple filter inputs.
* By itself, this class is not useful because it's fragment shader only uses one texture.
* To take advantage of the multiple texture inputs, the getFragmentShader() method should be
* override to return a more useful fragment shader. This class supports a maximum of 10
* input textures. However, only one set of texture coordinates is used so any rotation done in
* this filter will be applied to all input images.
*
* The position of the input textures should be registered before the filter attempts to draw.
* For example, if this class was extended with a fragment shader that required a grey scale filter as the first input
* texture and a blur filter as the second input, it would be set up as follows:
* <code>
* GreyScaleFilter grey = new GreyScaleFilter();
* FastBlurFilter blur = new FastBlurFilter();
* SomeMultiInputFilter multiInput = new SomeMultiInputFilter();
* grey.addTarget(multiInput);
* blur.addTarget(multiInput);
* multiInput.registerFilterLocation(grey, 0);
* multiInput.registerFilterLocation(blur, 1);
* </code>
* @author Chris Batt
*/
public abstract class MultiInputFilter extends BasicFilter {
private int numOfInputs;
private int[] textureHandle;
protected int[] texture;
protected List<GLTextureOutputRenderer> texturesReceived;
protected List<GLTextureOutputRenderer> filterLocations;
/**
* Creates a MultiInputFilter with any number of initial filters or filter graphs that produce a
* set number of textures which can be used by this filter.
* @param numOfInputs
* The number of inputs of this filter. For example, if the fragment shader of this filter
* requires three input textures, then this would be set to three.
*/
public MultiInputFilter(int numOfInputs) {
super();
this.numOfInputs = numOfInputs;
textureHandle = new int[numOfInputs-1];
texture = new int[numOfInputs-1];
texturesReceived = new ArrayList<GLTextureOutputRenderer>(numOfInputs);
filterLocations = new ArrayList<GLTextureOutputRenderer>(numOfInputs);
}
/**
* Removes all currently registered filters from filter location list.
*/
public void clearRegisteredFilterLocations() {
filterLocations.clear();
}
@Override
protected void initShaderHandles() {
super.initShaderHandles();
for(int i = 0; i < numOfInputs-1; i++) {
textureHandle[i] = GLES20.glGetUniformLocation(programHandle, UNIFORM_TEXTUREBASE+(i+1));
}
}
/* (non-Javadoc)
* @see com.marshalchen.common.uimodule.imageprocessing.filter.BasicFilter#newTextureReady(int, com.marshalchen.common.uimodule.imageprocessing.input.GLTextureOutputRenderer)
*/
@Override
public synchronized void newTextureReady(int texture, GLTextureOutputRenderer source, boolean newData) {
if(!texturesReceived.contains(source)) {
texturesReceived.add(source);
if(newData) {
markAsDirty();
}
}
int pos = filterLocations.lastIndexOf(source);
if(pos == 0) {
texture_in = texture;
} else {
this.texture[pos-1] = texture;
}
if(texturesReceived.size() == numOfInputs) {
setWidth(source.getWidth());
setHeight(source.getHeight());
onDrawFrame();
texturesReceived.clear();
}
}
@Override
protected void passShaderValues() {
super.passShaderValues();
int tex = 0;
for(int i = 0; i < numOfInputs-1; i++) {
switch(i) {
case 0: tex = GLES20.GL_TEXTURE1; break;
case 1: tex = GLES20.GL_TEXTURE2; break;
case 2: tex = GLES20.GL_TEXTURE3; break;
case 3: tex = GLES20.GL_TEXTURE4; break;
case 4: tex = GLES20.GL_TEXTURE5; break;
case 5: tex = GLES20.GL_TEXTURE6; break;
case 6: tex = GLES20.GL_TEXTURE7; break;
case 7: tex = GLES20.GL_TEXTURE8; break;
case 8: tex = GLES20.GL_TEXTURE9; break;
}
GLES20.glActiveTexture(tex);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[i]);
GLES20.glUniform1i(textureHandle[i], i+1);
}
}
/**
* Registers the given filter in the next available texture location.
* @param filter
* An output filter which passes its output to this filter.
*/
public void registerFilterLocation(GLTextureOutputRenderer filter) {
if(!filterLocations.contains(filter)) {
filterLocations.add(filter);
}
}
/**
* Registers the given filter in the given texture location.
* @param filter
* An output filter which passes its output to this filter.
* @param location
* The texture location that this filter should pass its output to. This location must be in [0,numOfInputs).
*/
public void registerFilterLocation(GLTextureOutputRenderer filter, int location) {
if(filterLocations.contains(filter)) {
filterLocations.remove(filter);
}
filterLocations.add(location, filter);
}
}