package loon;
import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glCheckFramebufferStatusEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glDeleteFramebuffersEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glFramebufferTexture2DEXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glGenFramebuffersEXT;
import static org.lwjgl.opengl.GL30.GL_COLOR_ATTACHMENT0;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_COMPLETE;
import static org.lwjgl.opengl.GL30.glDeleteFramebuffers;
import java.util.HashMap;
import java.util.Map;
import loon.core.event.Updateable;
import loon.core.graphics.opengl.FrameBuffer;
import loon.core.graphics.opengl.GL;
import loon.core.graphics.opengl.GLEx;
import loon.core.graphics.opengl.LTexture;
import loon.core.graphics.opengl.LTexture.Format;
import loon.utils.collection.Array;
import org.lwjgl.opengl.GLContext;
public class JavaSEFrameBuffer implements FrameBuffer {
private final static Map<GLEx, Array<FrameBuffer>> buffers = new HashMap<GLEx, Array<FrameBuffer>>();
private LTexture texture;
private int id;
private int width, height;
private boolean isLoaded;
private static void addManagedFrameBuffer(GLEx app, FrameBuffer frameBuffer) {
Array<FrameBuffer> managedResources = buffers.get(app);
if (managedResources == null) {
managedResources = new Array<FrameBuffer>();
}
managedResources.add(frameBuffer);
buffers.put(app, managedResources);
}
public static void invalidateAllFrameBuffers(GLEx app) {
if (GLEx.gl == null) {
return;
}
Array<FrameBuffer> bufferArray = buffers.get(app);
if (bufferArray == null) {
return;
}
for (int i = 0; i < bufferArray.size(); i++) {
bufferArray.get(i).build();
}
}
public static void clearAllFrameBuffers(GLEx app) {
buffers.remove(app);
}
public void build() {
isLoaded = false;
Updateable update = new Updateable() {
@Override
public void action(Object a) {
if (!texture.isLoaded()) {
texture.loadTexture();
}
id = glGenFramebuffersEXT();
glBindFramebufferEXT(GL_FRAMEBUFFER, id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL.GL_TEXTURE_2D, texture.getTextureID(), 0);
int result = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
if (result != GL_FRAMEBUFFER_COMPLETE) {
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(id);
throw new RuntimeException("exception " + result
+ " when checking JavaSEFBO status");
}
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
isLoaded = true;
}
};
LSystem.load(update);
}
public JavaSEFrameBuffer(final LTexture texture) {
if (!isSupported()) {
throw new RuntimeException(
"FBO extension not supported in hardware");
}
this.texture = texture;
this.width = texture.getWidth();
this.height = texture.getHeight();
this.build();
addManagedFrameBuffer(GLEx.self, this);
}
public JavaSEFrameBuffer(int width, int height, Format format) {
this(new LTexture(width, height, format));
}
public JavaSEFrameBuffer(int width, int height) {
this(width, height, LTexture.Format.LINEAR);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getID() {
return id;
}
public LTexture getTexture() {
return texture;
}
public boolean isLoaded() {
return isLoaded;
}
public boolean isSupported() {
return GLContext.getCapabilities().GL_EXT_framebuffer_object;
}
public void bind() {
if (!isLoaded) {
return;
}
if (id == 0) {
throw new IllegalStateException(
"can't use FBO as it has been destroyed..");
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
}
public void unbind() {
if (!isLoaded) {
return;
}
if (id == 0) {
return;
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
public void begin() {
bind();
setFrameBufferViewport();
}
protected void setFrameBufferViewport() {
GLEx.gl.glViewport(0, 0, texture.getWidth(), texture.getHeight());
}
public void end() {
unbind();
setDefaultFrameBufferViewport();
}
protected void setDefaultFrameBufferViewport() {
GLEx.gl.glViewport(0, 0, GLEx.width(), GLEx.height());
}
public void end(int x, int y, int width, int height) {
unbind();
GLEx.gl.glViewport(x, y, width, height);
}
public void destroy() {
if (isLoaded) {
isLoaded = false;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteFramebuffersEXT(id);
id = 0;
}
if (texture != null) {
texture.destroy();
}
if (buffers.get(GLEx.self) != null) {
buffers.get(GLEx.self).remove(this);
}
}
}