/* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * */ package com.jogamp.opengl.util; import javax.media.opengl.*; public class FBObject { private int width, height; private int fb, fbo_tex, depth_rb, stencil_rb, vStatus; private int texInternalFormat, texDataFormat, texDataType; private boolean bound; public FBObject(int width, int height) { this.width = width; this.height = height; this.fb = 0; this.fbo_tex = 0; this.depth_rb = 0; this.stencil_rb = 0; this.bound = false; } public boolean validateStatus(GL gl) { /* vStatus = */ getStatus(gl); switch(vStatus) { case GL.GL_FRAMEBUFFER_COMPLETE: return true; case GL.GL_FRAMEBUFFER_UNSUPPORTED: case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: case GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: case GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: case GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: //case GL2.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: //case GL2.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: //case GL2.GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT: case 0: default: System.out.println("Framebuffer " + fb + " is incomplete: status = 0x" + Integer.toHexString(vStatus) + " : " + getStatusString(vStatus)); return false; } } /** @return {@link GL.GL_FRAMEBUFFER_COMPLETE} if ok, otherwise return GL FBO error state or -1 */ public int getStatus() { return vStatus; } public int getStatus(GL gl) { if(!gl.glIsFramebuffer(fb)) { vStatus = -1; } else { vStatus = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); } return vStatus; } public String getStatusString() { return getStatusString(vStatus); } public static String getStatusString(int fbStatus) { switch(fbStatus) { case -1: return "NOT A FBO"; case GL.GL_FRAMEBUFFER_COMPLETE: return "OK"; case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return("GL FBO: incomplete,incomplete attachment\n"); case GL.GL_FRAMEBUFFER_UNSUPPORTED: return("GL FBO: Unsupported framebuffer format"); case GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return("GL FBO: incomplete,missing attachment"); case GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: return("GL FBO: incomplete,attached images must have same dimensions"); case GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: return("GL FBO: incomplete,attached images must have same format"); /* case GL2.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: return("GL FBO: incomplete,missing draw buffer"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: return("GL FBO: incomplete,missing read buffer"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT: return("GL FBO: incomplete, duplicate attachment"); */ case 0: return("GL FBO: incomplete, implementation fault"); default: return("GL FBO: incomplete, implementation ERROR"); } } /** * Initializes this FBO's instance with it's texture, * selecting the texture data type and format automatically. * * Leaves the FBO bound! * * @param gl the current GL context * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER} * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER} * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S} * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T} * @return */ public boolean init(GL gl, int magFilter, int minFilter, int wrapS, int wrapT) { int textureInternalFormat, textureDataFormat, textureDataType; if(gl.isGL2()) { textureInternalFormat=GL.GL_RGBA8; textureDataFormat=GL2.GL_BGRA; textureDataType=GL2.GL_UNSIGNED_INT_8_8_8_8_REV; } else if(gl.isGLES()) { textureInternalFormat=GL.GL_RGBA; textureDataFormat=GL.GL_RGBA; textureDataType=GL.GL_UNSIGNED_BYTE; } else { textureInternalFormat=GL.GL_RGB; textureDataFormat=GL.GL_RGB; textureDataType=GL.GL_UNSIGNED_BYTE; } return init(gl, textureInternalFormat, textureDataFormat, textureDataType, magFilter, minFilter, wrapS, wrapT); } /** * Initializes this FBO's instance with it's texture. * * Leaves the FBO bound! * * @param gl the current GL context * @param textureInternalFormat internalFormat parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)} * @param textureDataFormat format parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)} * @param textureDataType type parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)} * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER} * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER} * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S} * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T} * @return true if successful otherwise false */ public boolean init(GL gl, int textureInternalFormat, int textureDataFormat, int textureDataType, int magFilter, int minFilter, int wrapS, int wrapT) { checkBound(false); if(0=fb || 0>=fbo_tex) { throw new GLException("FBO not initialized (fb "+fb+", tex "+fbo_tex+")"); } if(depth_rb != 0) { throw new GLException("FBO depth buffer already attached (rb "+depth_rb+")"); } checkBound(true); int name[] = new int[1]; gl.glGenRenderbuffers(1, name, 0); depth_rb = name[0]; if(depth_rb==0) { throw new GLException("null generated renderbuffer"); } // Initialize the depth buffer: gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, depth_rb); if(!gl.glIsRenderbuffer(depth_rb)) { System.err.println("not a depthbuffer: "+ depth_rb); name[0] = depth_rb; gl.glDeleteRenderbuffers(1, name, 0); depth_rb=0; return false; } gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, depthComponentType, width, height); // Set up the depth buffer attachment: gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depth_rb); return validateStatus(gl); } /** * Assumes a bound FBO * Leaves the FBO bound! * @param stencilComponentType {@link GL#GL_STENCIL_INDEX1}, {@link GL#GL_STENCIL_INDEX4} or {@link GL#GL_STENCIL_INDEX8} * @return true if successful otherwise false */ public boolean attachStencilBuffer(GL gl, int stencilComponentType) { if(0>=fb || 0>=fbo_tex) { throw new GLException("FBO not initialized (fb "+fb+", tex "+fbo_tex+")"); } if(stencil_rb != 0) { throw new GLException("FBO stencil buffer already attached (rb "+stencil_rb+")"); } checkBound(true); int name[] = new int[1]; gl.glGenRenderbuffers(1, name, 0); stencil_rb = name[0]; if(stencil_rb==0) { throw new GLException("null generated stencilbuffer"); } // Initialize the stencil buffer: gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, stencil_rb); if(!gl.glIsRenderbuffer(stencil_rb)) { destroy(gl); System.err.println("not a stencilbuffer: "+ depth_rb); return false; } gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, stencilComponentType, width, height); gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, stencil_rb); return validateStatus(gl); } public void destroy(GL gl) { if(bound) { unbind(gl); } int name[] = new int[1]; if(0!=stencil_rb) { name[0] = stencil_rb; gl.glDeleteRenderbuffers(1, name, 0); stencil_rb = 0; } if(0!=depth_rb) { name[0] = depth_rb; gl.glDeleteRenderbuffers(1, name, 0); depth_rb=0; } if(0!=fbo_tex) { name[0] = fbo_tex; gl.glDeleteTextures(1, name, 0); fbo_tex = 0; } if(0!=fb) { name[0] = fb; gl.glDeleteFramebuffers(1, name, 0); fb = 0; } } private final void checkBound(boolean shallBeBound) { if(bound != shallBeBound) { final String s0 = shallBeBound ? "not" : "already" ; throw new GLException("FBO "+s0+" bound "+toString()); } } public void bind(GL gl) { checkBound(false); gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, fb); bound = true; } public void unbind(GL gl) { checkBound(true); gl.glBindTexture(GL.GL_TEXTURE_2D, 0); gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); bound = false; } public void use(GL gl) { if(bound) { unbind(gl); } gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); // to use it .. } public final boolean isBound() { return bound; } public final int getWidth() { return width; } public final int getHeight() { return height; } public final int getFBName() { return fb; } public final int getTextureName() { return fbo_tex; } public final int getStencilBuffer() { return stencil_rb; } public final int getDepthBuffer() { return depth_rb; } public final String toString() { return "FBO[name "+fb+", size "+width+"x"+height+", tex "+fbo_tex+", depth "+depth_rb+", stencil "+stencil_rb+"]"; } }