package com.marshalchen.common.uimodule.imageprocessing; import java.util.ArrayList; import java.util.List; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLES20; import android.opengl.GLSurfaceView.Renderer; /** * Filter pipeline renderer implementation of the GLSurfaceView.Renderer. In addition to the GLSurfaceView.Renderer methods, * this class provides methods for processing the given graph of filters. This graph of filters can be set by creating one * or more filter graphs and then passing the root of the graphs to this class using addRootRenderer(GLRenderer rootRenderer). * This class will not start processing the filters until startRendering() has been called. Once it has started rendering, * the filter graph should not be changed without first calling pauseRendering(). Although this is theoretically not required, * it is recommended. If a filter is removed from the processing pipeline, addFilterToDestroy(GLRenderer filter) should be called * to clean up opengl memory. * @author Chris Batt */ public class FastImageProcessingPipeline implements Renderer { private boolean rendering; private List<GLRenderer> rootRenderers; private int width; private int height; private List<GLRenderer> filtersToDestroy; /** * Creates a FastImageProcessingPipeline with the initial state as paused and having no rootRenderer. */ public FastImageProcessingPipeline() { rendering = false; filtersToDestroy = new ArrayList<GLRenderer>(); rootRenderers = new ArrayList<GLRenderer>(); } /** * Adds a given filter to the list of filters to have its resources removed next time this pipeline * receives an opengl context. The filter will still be usable and will recreate all of the destroyed * opengl objects next time it is used in the pipeline. * @param renderer */ public void addFilterToDestroy(GLRenderer renderer) { synchronized(filtersToDestroy) { filtersToDestroy.add(renderer); } } /** * Adds a root node of graph of filters that the pipeline will process and draw to the given endpoints of the graph. * @param rootRenderer * A root node (input node) of the graph of filters and endpoints. */ public synchronized void addRootRenderer(GLRenderer rootRenderer) { rootRenderers.add(rootRenderer); } /** * Returns the height of GLSurfaceView on the screen. * @return height */ public int getHeight() { return height; } /** * Returns the width of GLSurfaceView on the screen. * @return width */ public int getWidth() { return width; } private synchronized boolean isRendering() { return rendering; } /* (non-Javadoc) * @see android.opengl.GLSurfaceView.Renderer#onDrawFrame(javax.microedition.khronos.opengles.GL10) */ @Override public void onDrawFrame(GL10 unused) { if(isRendering()) { for(int i = 0; i < rootRenderers.size(); i++) { GLRenderer rootRenderer; synchronized(this) { rootRenderer = rootRenderers.get(i); } rootRenderer.onDrawFrame(); } } synchronized(filtersToDestroy) { for(GLRenderer renderer : filtersToDestroy) { renderer.destroy(); } filtersToDestroy.clear(); } } /* (non-Javadoc) * @see android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int) */ @Override public void onSurfaceChanged(GL10 unused, int width, int height) { this.width = width; this.height = height; } /* (non-Javadoc) * @see android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig) */ @Override public void onSurfaceCreated(GL10 unused, EGLConfig config) { GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); } /** * Pauses the rendering of the graph. This method should be called before the alteration of the filter graph; however, * altering the filter graph without pauses should still work. */ public synchronized void pauseRendering() { rendering = false; } /** * Removes a root node of graph of filters that the pipeline will process and draw to the given endpoints of the graph. * @param rootRenderer * A root node (input node) of the graph of filters and endpoints. */ public synchronized void removeRootRenderer(GLRenderer rootRenderer) { rootRenderers.remove(rootRenderer); } /** * Starts the rendering of the graph. If this is called before a root node renderer has been * added, it will do nothing. */ public synchronized void startRendering() { if(rootRenderers.size() != 0) { rendering = true; } } }