package loon; import java.util.HashMap; import java.util.Map; import javax.microedition.khronos.opengles.GL11ExtensionPack; import loon.core.event.Updateable; import loon.core.graphics.opengl.FrameBuffer; import loon.core.graphics.opengl.GL10; import loon.core.graphics.opengl.GLEx; import loon.core.graphics.opengl.LTexture; import loon.core.graphics.opengl.LTexture.Format; import loon.utils.collection.Array; public class AndroidFrameBuffer implements FrameBuffer { private final static Map<GLEx, Array<FrameBuffer>> buffers = new HashMap<GLEx, Array<FrameBuffer>>(); int[] framebuffers = new int[1]; private LTexture texture; private int id; private int width, height; private boolean isLoaded; static boolean superFBO(GL10 gl, String extension) { final String extensions = " " + gl.glGetString(GL10.GL_EXTENSIONS) + " "; return extensions.indexOf(" " + extension + " ") >= 0; } 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(); } final GL11ExtensionPack gl11ep = (GL11ExtensionPack) ((AndroidGL10) GLEx.gl10).gl; gl11ep.glGenFramebuffersOES(1, framebuffers, 0); id = framebuffers[0]; gl11ep.glBindFramebufferOES( GL11ExtensionPack.GL_FRAMEBUFFER_OES, id); int depthbuffer; int[] renderbuffers = new int[1]; gl11ep.glGenRenderbuffersOES(1, renderbuffers, 0); depthbuffer = renderbuffers[0]; gl11ep.glBindRenderbufferOES( GL11ExtensionPack.GL_RENDERBUFFER_OES, depthbuffer); gl11ep.glRenderbufferStorageOES( GL11ExtensionPack.GL_RENDERBUFFER_OES, GL11ExtensionPack.GL_DEPTH_COMPONENT16, width, height); gl11ep.glFramebufferRenderbufferOES( GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_DEPTH_ATTACHMENT_OES, GL11ExtensionPack.GL_RENDERBUFFER_OES, depthbuffer); gl11ep.glFramebufferTexture2DOES( GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, texture.getTextureID(), 0); int status = gl11ep .glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES); if (status != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES) { throw new RuntimeException("Framebuffer is not complete: " + Integer.toHexString(status)); } gl11ep.glBindFramebufferOES( GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0); isLoaded = true; } }; LSystem.load(update); } public AndroidFrameBuffer(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 AndroidFrameBuffer(int width, int height, Format format) { this(new LTexture(width, height, format)); } public AndroidFrameBuffer(int width, int height) { this(width, height, LTexture.Format.LINEAR); } @Override public int getWidth() { return width; } @Override public int getHeight() { return height; } @Override public int getID() { return id; } @Override public LTexture getTexture() { return texture; } @Override public boolean isLoaded() { return isLoaded; } @Override public boolean isSupported() { return superFBO(GLEx.gl10, "GL_OES_framebuffer_object"); } public void bind() { if (!isLoaded) { return; } if (id == 0) { throw new IllegalStateException( "can't use FBO as it has been destroyed.."); } final GL11ExtensionPack gl11ep = (GL11ExtensionPack) ((AndroidGL10) GLEx.gl10).gl; gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, id); } public void unbind() { if (!isLoaded) { return; } if (id == 0) { return; } final GL11ExtensionPack gl11ep = (GL11ExtensionPack) ((AndroidGL10) GLEx.gl10).gl; gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0); } 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; final GL11ExtensionPack gl11ep = (GL11ExtensionPack) ((AndroidGL10) GLEx.gl10).gl; gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, 0); gl11ep.glDeleteFramebuffersOES(1, framebuffers, 0); id = 0; } if (texture != null) { texture.destroy(); } if (buffers.get(GLEx.self) != null) { buffers.get(GLEx.self).remove(this); } } }