Package com.bitfire.postprocessing.utils

Source Code of com.bitfire.postprocessing.utils.PingPongBuffer

/*******************************************************************************
* Copyright 2012 bmanuel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

package com.bitfire.postprocessing.utils;

import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;

/** Encapsulates a framebuffer with the ability to ping-pong between two buffers.
*
* Upon {@link #begin()} the buffer is reset to a known initial state, this is usually done just before the first usage of the
* buffer.
*
* Subsequent {@link #capture()} calls will initiate writing to the next available buffer, returning the previously used one,
* effectively ping-ponging between the two. Until {@link #end()} is called, chained rendering will be possible by retrieving the
* necessary buffers via {@link #getSourceTexture()}, {@link #getSourceBuffer()}, {@link #getResultTexture()} or
* {@link #getResultBuffer}.
*
* When finished, {@link #end()} should be called to stop capturing. When the OpenGL context is lost, {@link #rebind()} should be
* called.
*
* @author bmanuel */
public final class PingPongBuffer {
  public FrameBuffer buffer1, buffer2;
  public Texture texture1, texture2;
  public int width, height;
  public final boolean ownResources;

  // internal state
  private Texture texResult, texSrc;
  private FrameBuffer bufResult, bufSrc;
  private boolean writeState, pending1, pending2;

  // save/restore state
  private final FrameBuffer owned1, owned2;
  private FrameBuffer ownedResult, ownedSource;
  private int ownedW, ownedH;

  /** Creates a new ping-pong buffer and owns the resources. */
  public PingPongBuffer (int width, int height, Format frameBufferFormat, boolean hasDepth) {
    ownResources = true;
    owned1 = new FrameBuffer(frameBufferFormat, width, height, hasDepth);
    owned2 = new FrameBuffer(frameBufferFormat, width, height, hasDepth);
    set(owned1, owned2);
  }

  /** Creates a new ping-pong buffer with the given buffers. */
  public PingPongBuffer (FrameBuffer buffer1, FrameBuffer buffer2) {
    ownResources = false;
    owned1 = null;
    owned2 = null;
    set(buffer1, buffer2);
  }

  /** An instance of this object can also be used to manipulate some other externally-allocated buffers, applying just the same
   * ping-ponging behavior.
   *
   * If this instance of the object was owning the resources, they will be preserved and will be restored by a {@link #reset()}
   * call.
   *
   * @param buffer1 the first buffer
   * @param buffer2 the second buffer */
  public void set (FrameBuffer buffer1, FrameBuffer buffer2) {
    if (ownResources) {
      ownedResult = bufResult;
      ownedSource = bufSrc;
      ownedW = width;
      ownedH = height;
    }

    this.buffer1 = buffer1;
    this.buffer2 = buffer2;
    width = this.buffer1.getWidth();
    height = this.buffer1.getHeight();
    rebind();
  }

  /** Restore the previous buffers if the instance was owning resources. */
  public void reset () {
    if (ownResources) {
      buffer1 = owned1;
      buffer2 = owned2;
      width = ownedW;
      height = ownedH;
      bufResult = ownedResult;
      bufSrc = ownedSource;
    }
  }

  /** Free the resources, if any. */
  public void dispose () {
    if (ownResources) {
      // make sure we delete what we own
      // if the caller didn't call {@link #reset()}
      owned1.dispose();
      owned2.dispose();
    }
  }

  /** When needed graphics memory could be invalidated so buffers should be rebuilt. */
  public void rebind () {
    texture1 = buffer1.getColorBufferTexture();
    texture2 = buffer2.getColorBufferTexture();
  }

  /** Ensures the initial buffer state is always the same before starting ping-ponging. */
  public void begin () {
    pending1 = false;
    pending2 = false;
    writeState = true;

    texSrc = texture1;
    bufSrc = buffer1;
    texResult = texture2;
    bufResult = buffer2;
  }

  /** Starts and/or continue ping-ponging, begin capturing on the next available buffer, returns the result of the previous
   * {@link #capture()} call.
   *
   * @return the Texture containing the result. */
  public Texture capture () {
    endPending();

    if (writeState) {
      // set src
      texSrc = texture1;
      bufSrc = buffer1;

      // set result
      texResult = texture2;
      bufResult = buffer2;

      // write to other
      pending2 = true;
      buffer2.begin();
    } else {
      texSrc = texture2;
      bufSrc = buffer2;

      texResult = texture1;
      bufResult = buffer1;

      pending1 = true;
      buffer1.begin();
    }

    writeState = !writeState;
    return texSrc;
  }

  /** Finishes ping-ponging, must always be called after a call to {@link #capture()} */
  public void end () {
    endPending();
  }

  /** @return the source texture of the current ping-pong chain. */
  public Texture getSouceTexture () {
    return texSrc;
  }

  /** @return the source buffer of the current ping-pong chain. */
  public FrameBuffer getSourceBuffer () {
    return bufSrc;
  }

  /** @return the result's texture of the latest {@link #capture()}. */
  public Texture getResultTexture () {
    return texResult;
  }

  /** @return Returns the result's buffer of the latest {@link #capture()}. */
  public FrameBuffer getResultBuffer () {
    return bufResult;
  }

  // internal use
  // finish writing to the buffers, mark as not pending anymore.
  private void endPending () {
    if (pending1) {
      buffer1.end();
      pending1 = false;
    }

    if (pending2) {
      buffer2.end();
      pending2 = false;
    }
  }
}
TOP

Related Classes of com.bitfire.postprocessing.utils.PingPongBuffer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.