From 526ea7a3fb579f88a0c0a1e597387aae29d5aa06 Mon Sep 17 00:00:00 2001
From: Sven Gothel Leaves the FBO bound!
Assumes a bound FBO
+ *Leaves the FBO bound!
+ * + * @param gl the current GL context + * @param texUnit the desired texture unit ranging from [0..{@link GL2#GL_MAX_TEXTURE_UNITS}-1], or -1 if no unit shall be activate at {@link #use(GL, int)} + * @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 idx of the new attached texture, otherwise -1 + * @throws GLException in case of an error + */ + public int attachTexture2D(GL gl, int texUnit, int magFilter, int minFilter, int wrapS, int wrapT) throws GLException { + final 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 attachTexture2D(gl, texUnit, textureInternalFormat, textureDataFormat, textureDataType, magFilter, minFilter, wrapS, wrapT); + } + + /** + * Attaches a[nother] Texture2D Color Buffer to this FBO's instance, + * selecting the texture data type and format automatically. + *This may be done as many times as many color attachments are supported, + * see {@link GL2GL3#GL_MAX_COLOR_ATTACHMENTS}.
+ * + *Assumes a bound FBO
+ *Leaves the FBO bound!
+ * + * @param gl the current GL context + * @param texUnit the desired texture unit ranging from [0..{@link GL2#GL_MAX_TEXTURE_UNITS}-1], or -1 if no unit shall be activate at {@link #use(GL, int)} + * @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 index of the texture colorbuffer if bound and configured successfully, otherwise -1 + * @throws GLException in case the texture colorbuffer couldn't be allocated + */ + public int attachTexture2D(GL gl, int texUnit, + int textureInternalFormat, int textureDataFormat, int textureDataType, + int magFilter, int minFilter, int wrapS, int wrapT) throws GLException { + checkBound(gl, true); + final int fbo_tex_idx = fbo_tex_num; + gl.glGenTextures(1, fbo_tex_names, fbo_tex_num); + if(fbo_tex_names[fbo_tex_idx]==0) { throw new GLException("null generated texture"); } - gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); + fbo_tex_units[fbo_tex_idx] = texUnit; + fbo_tex_num++; + if(0<=texUnit) { + gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit); + } + gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex_names[fbo_tex_idx]); checkNoError(gl, gl.glGetError(), "FBObject Init.bindTex"); // throws GLException if error - gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, texInternalFormat, width, height, 0, - texDataFormat, texDataType, null); + gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, textureInternalFormat, width, height, 0, + textureDataFormat, textureDataType, null); checkNoError(gl, gl.glGetError(), "FBObject Init.texImage2D"); // throws GLException if error if( 0 < magFilter ) { gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, magFilter); @@ -232,31 +281,32 @@ public class FBObject { // Set up the color buffer for use as a renderable texture: gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, - GL.GL_COLOR_ATTACHMENT0, - GL.GL_TEXTURE_2D, fbo_tex, 0); + GL.GL_COLOR_ATTACHMENT0 + colorattachment_num++, + GL.GL_TEXTURE_2D, fbo_tex_names[fbo_tex_idx], 0); - updateStatus(gl); - return isStatusValid(); + updateStatus(gl); + return isStatusValid() ? fbo_tex_idx : -1; } - + /** - * Assumes a bound FBO - * Leaves the FBO bound! + * Attaches one Depth Buffer to this FBO's instance. + *This may be done only one time.
+ * + *Assumes a bound FBO
+ *Leaves the FBO bound!
+ * @param gl the current GL context * @param depthComponentType {@link GL#GL_DEPTH_COMPONENT16}, {@link GL#GL_DEPTH_COMPONENT24} or {@link GL#GL_DEPTH_COMPONENT32} - * @return true if successful otherwise false + * @return true if the depth renderbuffer could be bound and configured, otherwise false + * @throws GLException in case the depth renderbuffer couldn't be allocated or one is already attached. */ - public boolean attachDepthBuffer(GL gl, int depthComponentType) { - if(0>=fb || 0>=fbo_tex) { - throw new GLException("FBO not initialized (fb "+fb+", tex "+fbo_tex+")"); - } + public boolean attachDepthBuffer(GL gl, int depthComponentType) throws GLException { + checkBound(gl, true); 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]; - + depth_rb = name[0]; if(depth_rb==0) { throw new GLException("null generated renderbuffer"); } @@ -273,26 +323,28 @@ public class FBObject { 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); + GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, depth_rb); updateStatus(gl); return isStatusValid(); } /** - * Assumes a bound FBO - * Leaves the FBO bound! + * Attaches one Stencil Buffer to this FBO's instance. + *This may be done only one time.
+ * + *Assumes a bound FBO
+ *Leaves the FBO bound!
+ * @param gl the current GL context * @param stencilComponentType {@link GL#GL_STENCIL_INDEX1}, {@link GL#GL_STENCIL_INDEX4} or {@link GL#GL_STENCIL_INDEX8} - * @return true if successful otherwise false + * @return true if the stencil renderbuffer could be bound and configured, otherwise false + * @throws GLException in case the stencil renderbuffer couldn't be allocated or one is already attached. */ - public boolean attachStencilBuffer(GL gl, int stencilComponentType) { - if(0>=fb || 0>=fbo_tex) { - throw new GLException("FBO not initialized (fb "+fb+", tex "+fbo_tex+")"); - } + public boolean attachStencilBuffer(GL gl, int stencilComponentType) throws GLException { + checkBound(gl, true); 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]; @@ -302,18 +354,23 @@ public class FBObject { // 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; + System.err.println("not a stencilbuffer: "+ stencil_rb); + name[0] = stencil_rb; + gl.glDeleteRenderbuffers(1, name, 0); + stencil_rb=0; + return false; } gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, stencilComponentType, width, height); gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, stencil_rb); + GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, stencil_rb); updateStatus(gl); return isStatusValid(); } + /** + * @param gl the current GL context + */ public void destroy(GL gl) { if(bound) { unbind(gl); @@ -331,46 +388,65 @@ public class FBObject { 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(null!=fbo_tex_names && fbo_tex_num>0) { + gl.glDeleteTextures(1, fbo_tex_names, fbo_tex_num); + fbo_tex_names = new int[MAX_FBO_TEXTURES]; + fbo_tex_units = new int[MAX_FBO_TEXTURES]; + fbo_tex_num = 0; } + colorattachment_num = 0; if(0!=fb) { name[0] = fb; gl.glDeleteFramebuffers(1, name, 0); fb = 0; } + initialized = false; } - private final void checkBound(boolean shallBeBound) { - if(bound != shallBeBound) { - final String s0 = shallBeBound ? "not" : "already" ; - throw new GLException("FBO "+s0+" bound "+toString()); - } - } - + /** + * Bind this FBO + *In case you have attached more than one color buffer, + * you may want to setup {@link GL2GL3#glDrawBuffers(int, int[], int)}.
+ * @param gl the current GL context + */ public void bind(GL gl) { - checkBound(false); - gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); + checkBound(gl, false); gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, fb); bound = true; } + /** + * Unbind FBO, ie bind 'non' FBO 0 + * @param gl the current GL context + */ public void unbind(GL gl) { - checkBound(true); - gl.glBindTexture(GL.GL_TEXTURE_2D, 0); + checkBound(gl, true); gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); bound = false; } - public void use(GL gl) { - checkBound(false); - gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); // use it .. + /** + * Bind the texture with given index. + * + *If a valid texture unit was named via {@link #attachTexture2D(GL, int, int, int, int, int) attachTexture2D(..)}, + * the unit is activated via {@link GL#glActiveTexture(int) glActiveTexture(GL.GL_TEXTURE0 + unit)}.
+ * @param gl the current GL context + * @param texIdx index of the texture to use, prev. attached w/ {@link #attachTexture2D(GL, int, int, int, int, int) attachTexture2D(..)} + */ + public void use(GL gl, int texIdx) { + checkBound(gl, false); + if(texIdx >= fbo_tex_num) { + throw new GLException("Invalid texId, only "+fbo_tex_num+" textures are attached"); + } + if(0<=fbo_tex_units[texIdx]) { + gl.glActiveTexture(GL.GL_TEXTURE0 + fbo_tex_units[texIdx]); + } + gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex_names[texIdx]); // use it .. } + /** Unbind texture, ie bind 'non' texture 0 */ public void unuse(GL gl) { - checkBound(false); + checkBound(gl, false); gl.glBindTexture(GL.GL_TEXTURE_2D, 0); // don't use it } @@ -378,11 +454,16 @@ public class FBObject { 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 getTextureNumber() { return fbo_tex_num; } + public final int getTextureName(int idx) { return fbo_tex_names[idx]; } + + /** @return the named texture unit ranging from [0..{@link GL2#GL_MAX_TEXTURE_UNITS}-1], or -1 if no unit was desired. */ + public final int getTextureUnit(int idx) { return fbo_tex_units[idx]; } + public final int getColorAttachmentNumber() { return colorattachment_num; } 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+"]"; + return "FBO[name "+fb+", size "+width+"x"+height+", color num "+colorattachment_num+", tex num "+fbo_tex_num+", depth "+depth_rb+", stencil "+stencil_rb+"]"; } private void updateStatus(GL gl) { -- cgit v1.2.3