/*******************************************************************************
 * 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;
		}
	}
}

@@ -5198,24 +5198,214 @@
 ding();%0A%09%7D%0A%0A
+%09/**%0A%09 * @return the source texture of the current ping-pong chain.%0A%09 * @deprecated use getSourceTexture instead.%0A%09 */%0A%09@Deprecated%0A%09public Texture getSouceTexture () %7B%0A%09%09return texSrc;%0A%09%7D%0A%0A
 %09/** @return
@@ -5473,32 +5473,33 @@
 c Texture getSou
+r
 ceTexture () %7B%0A%09

fix typo