public void preFrame(float tpf) {
    if (filters.isEmpty() || lastFilterIndex == -1) {
      // If the camera is initialized and there are no filter to render, the camera viewport is
      // restored as it was
      if (cameraInit) {
        viewPort.getCamera().resize(originalWidth, originalHeight, true);
        viewPort.getCamera().setViewPort(left, right, bottom, top);
        viewPort.setOutputFrameBuffer(outputBuffer);
        cameraInit = false;
      }

    } else {
      if (renderFrameBufferMS != null) {
        viewPort.setOutputFrameBuffer(renderFrameBufferMS);
      } else {
        viewPort.setOutputFrameBuffer(renderFrameBuffer);
      }
      // init of the camera if it wasn't already
      if (!cameraInit) {
        viewPort.getCamera().resize(width, height, true);
        viewPort.getCamera().setViewPort(0, 1, 0, 1);
      }
    }

    for (Iterator<Filter> it = filters.iterator(); it.hasNext(); ) {
      Filter filter = it.next();
      if (filter.isEnabled()) {
        filter.preFrame(tpf);
      }
    }
  }
 public void cleanup() {
   if (viewPort != null) {
     // reseting the viewport camera viewport to its initial value
     viewPort.getCamera().resize(originalWidth, originalHeight, true);
     viewPort.getCamera().setViewPort(left, right, bottom, top);
     viewPort.setOutputFrameBuffer(outputBuffer);
     viewPort = null;
     for (Filter filter : filters) {
       filter.cleanup(renderer);
     }
   }
 }
  public void postFrame(FrameBuffer out) {

    FrameBuffer sceneBuffer = renderFrameBuffer;
    if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL31)) {
      renderer.copyFrameBuffer(renderFrameBufferMS, renderFrameBuffer);
    } else if (renderFrameBufferMS != null) {
      sceneBuffer = renderFrameBufferMS;
    }
    renderFilterChain(renderer, sceneBuffer);
    renderer.setFrameBuffer(outputBuffer);

    // viewport can be null if no filters are enabled
    if (viewPort != null) {
      renderManager.setCamera(viewPort.getCamera(), false);
    }
  }
  public void initialize(RenderManager rm, ViewPort vp) {
    renderManager = rm;
    renderer = rm.getRenderer();
    viewPort = vp;
    fsQuad = new Picture("filter full screen quad");

    Camera cam = vp.getCamera();

    // save view port diensions
    left = cam.getViewPortLeft();
    right = cam.getViewPortRight();
    top = cam.getViewPortTop();
    bottom = cam.getViewPortBottom();
    originalWidth = cam.getWidth();
    originalHeight = cam.getHeight();
    // first call to reshape
    reshape(vp, cam.getWidth(), cam.getHeight());
  }
  public void reshape(ViewPort vp, int w, int h) {
    // this has no effect at first init but is useful when resizing the canvas with multi views
    Camera cam = vp.getCamera();
    cam.setViewPort(left, right, bottom, top);
    // resizing the camera to fit the new viewport and saving original dimensions
    cam.resize(w, h, false);
    left = cam.getViewPortLeft();
    right = cam.getViewPortRight();
    top = cam.getViewPortTop();
    bottom = cam.getViewPortBottom();
    originalWidth = w;
    originalHeight = h;
    cam.setViewPort(0, 1, 0, 1);

    // computing real dimension of the viewport and resizing he camera
    width = (int) (w * (Math.abs(right - left)));
    height = (int) (h * (Math.abs(bottom - top)));
    width = Math.max(1, width);
    height = Math.max(1, height);
    cam.resize(width, height, false);
    cameraInit = true;
    computeDepth = false;

    if (renderFrameBuffer == null) {
      outputBuffer = viewPort.getOutputFrameBuffer();
    }

    Collection<Caps> caps = renderer.getCaps();

    // antialiasing on filters only supported in opengl 3 due to depth read problem
    if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample)) {
      renderFrameBufferMS = new FrameBuffer(width, height, numSamples);
      if (caps.contains(Caps.OpenGL31)) {
        Texture2D msColor = new Texture2D(width, height, numSamples, Format.RGBA8);
        Texture2D msDepth = new Texture2D(width, height, numSamples, Format.Depth);
        renderFrameBufferMS.setDepthTexture(msDepth);
        renderFrameBufferMS.setColorTexture(msColor);
        filterTexture = msColor;
        depthTexture = msDepth;
      } else {
        renderFrameBufferMS.setDepthBuffer(Format.Depth);
        renderFrameBufferMS.setColorBuffer(Format.RGBA8);
      }
    }

    if (numSamples <= 1 || !caps.contains(Caps.OpenGL31)) {
      renderFrameBuffer = new FrameBuffer(width, height, 1);
      renderFrameBuffer.setDepthBuffer(Format.Depth);
      filterTexture = new Texture2D(width, height, Format.RGBA8);
      renderFrameBuffer.setColorTexture(filterTexture);
    }

    for (Iterator<Filter> it = filters.iterator(); it.hasNext(); ) {
      Filter filter = it.next();
      initFilter(filter, vp);
    }

    if (renderFrameBufferMS != null) {
      viewPort.setOutputFrameBuffer(renderFrameBufferMS);
    } else {
      viewPort.setOutputFrameBuffer(renderFrameBuffer);
    }
  }