diff options
author | Sven Gothel <[email protected]> | 2011-05-17 13:03:07 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2011-05-17 13:03:07 +0200 |
commit | 526ea7a3fb579f88a0c0a1e597387aae29d5aa06 (patch) | |
tree | 7d2aed914d5ca448afea58859987f16ccf0117e6 /src | |
parent | 88eabad2809d0132f919d655211ffdbfd2feea97 (diff) |
Fix/Extend FBObject (API Change): plain init(GL), support multiple attachTexture2D(..) (MRT) w/ tex units
- plain initialization via init(GL)
- dedicated texture2D color buffer attachement attachTexture2D(..) w/ tex units (<GL_MAX_TEXTURE_UNITS),
which may happen up to max GL_MAX_COLOR_ATTACHMENTS to support MRT (multiple render targets)
- more API doc
- FBO/MRT/GLSL unit test w/ using 2 shader (decompose / compose)
Diffstat (limited to 'src')
6 files changed, 482 insertions, 116 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/FBObject.java b/src/jogl/classes/com/jogamp/opengl/util/FBObject.java index c57d4b057..0b6094128 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/util/FBObject.java @@ -37,16 +37,26 @@ package com.jogamp.opengl.util; import javax.media.opengl.*; public class FBObject { + static final int MAX_FBO_TEXTURES = 32; // just for our impl .. not the real 'max' FBO color attachments + private int[] fbo_tex_names; + private int[] fbo_tex_units; + private int fbo_tex_num; + private int colorattachment_num; + + private boolean initialized; private int width, height; - private int fb, fbo_tex, depth_rb, stencil_rb, vStatus; - private int texInternalFormat, texDataFormat, texDataType; + private int fb, depth_rb, stencil_rb, vStatus; private boolean bound; - + public FBObject(int width, int height) { + this.fbo_tex_names = new int[MAX_FBO_TEXTURES]; + this.fbo_tex_units = new int[MAX_FBO_TEXTURES]; + this.fbo_tex_num = 0; + this.colorattachment_num = 0; + this.initialized = false; this.width = width; this.height = height; this.fb = 0; - this.fbo_tex = 0; this.depth_rb = 0; this.stencil_rb = 0; this.bound = false; @@ -117,38 +127,6 @@ public class FBObject { } } - /** - * 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); - } - private boolean checkNoError(GL gl, int err, String exceptionMessage) { if(GL.GL_NO_ERROR != err) { if(null != gl) { @@ -161,35 +139,36 @@ public class FBObject { } return true; } - + + private final void checkInitialized() { + if(!initialized) { + throw new GLException("FBO not initialized, call init(GL) first."); + } + } + + private final void checkBound(GL gl, boolean shallBeBound) { + checkInitialized(); + if(bound != shallBeBound) { + final String s0 = shallBeBound ? "not" : "already" ; + throw new GLException("FBO "+s0+" bound "+toString()); + } + checkNoError(null, gl.glGetError(), "FBObject pre"); // throws GLException if error + } + /** * Initializes this FBO's instance with it's texture. * - * Leaves the FBO bound! + * <p>Leaves the FBO bound!</p> * * @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 + * @throws GLException in case of an error */ - 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 already initialized (fb "+fb+", tex "+fbo_tex+")"); - } - + public void init(GL gl) throws GLException { + if(initialized) { + throw new GLException("FBO already initialized"); + } checkNoError(null, gl.glGetError(), "FBObject Init.pre"); // throws GLException if error - - texInternalFormat=textureInternalFormat; - texDataFormat=textureDataFormat; - texDataType=textureDataType; - + // generate fbo .. int name[] = new int[1]; @@ -206,16 +185,86 @@ public class FBObject { checkNoError(gl, GL.GL_INVALID_VALUE, "FBObject Init.isFB"); // throws GLException } bound = true; + initialized = true; + + updateStatus(gl); + } - gl.glGenTextures(1, name, 0); - fbo_tex = name[0]; - if(fbo_tex==0) { + /** + * Attaches a[nother] Texture2D Color Buffer to this FBO's instance, + * selecting the texture data type and format automatically. + * <p>This may be done as many times as many color attachments are supported, + * see {@link GL2GL3#GL_MAX_COLOR_ATTACHMENTS}.</p> + * + * <p>Assumes a bound FBO</p> + * <p>Leaves the FBO bound!</p> + * + * @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. + * <p>This may be done as many times as many color attachments are supported, + * see {@link GL2GL3#GL_MAX_COLOR_ATTACHMENTS}.</p> + * + * <p>Assumes a bound FBO</p> + * <p>Leaves the FBO bound!</p> + * + * @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. + * <p>This may be done only one time.</p> + * + * <p>Assumes a bound FBO</p> + * <p>Leaves the FBO bound!</p> + * @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. + * <p>This may be done only one time.</p> + * + * <p>Assumes a bound FBO</p> + * <p>Leaves the FBO bound!</p> + * @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 + * <p>In case you have attached more than one color buffer, + * you may want to setup {@link GL2GL3#glDrawBuffers(int, int[], int)}.</p> + * @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. + * + * <p>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)}.</p> + * @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) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-1.fp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-1.fp new file mode 100644 index 000000000..1738d96d1 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-1.fp @@ -0,0 +1,11 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#version 110 + +varying vec4 frontColor; + +void main (void) +{ + gl_FragData[0] = vec4( frontColor.r, 0.0, 0.0, 1.0 ); + gl_FragData[1] = vec4( 0.0, frontColor.g, 0.0, 1.0 ); +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-1.vp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-1.vp new file mode 100644 index 000000000..7f95a650a --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-1.vp @@ -0,0 +1,16 @@ +// Copyright 2010 JogAmp Community. All rights reserved. + +#version 110 + +uniform mat4 gcu_PMVMatrix[2]; // P, Mv, and Mvi +attribute vec4 gca_Vertices; +attribute vec4 gca_Colors; + +varying vec4 frontColor; + +void main(void) +{ + frontColor = gca_Colors; + gl_Position = gcu_PMVMatrix[0] * gcu_PMVMatrix[1] * gca_Vertices; +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-2.fp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-2.fp new file mode 100644 index 000000000..deac58ce1 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-2.fp @@ -0,0 +1,16 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#version 110 + +uniform sampler2D gcs_TexUnit0; +uniform sampler2D gcs_TexUnit1; + +varying vec4 frontColor; +varying vec2 texCoord; + +void main (void) +{ + vec2 rg = texture2D(gcs_TexUnit0, texCoord).rg + texture2D(gcs_TexUnit1, texCoord).rg; + float b = frontColor.b - length(rg); + gl_FragData[0] = vec4( rg, b, 1.0 ); +}
\ No newline at end of file diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-2.vp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-2.vp new file mode 100644 index 000000000..1b2c02328 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/fbo-mrt-2.vp @@ -0,0 +1,18 @@ +//Copyright 2010 JogAmp Community. All rights reserved. + +#version 110 + +uniform mat4 gcu_PMVMatrix[2]; // P, Mv, and Mvi +attribute vec4 gca_Vertices; +attribute vec4 gca_Colors; +attribute vec2 gca_TexCoords; + +varying vec4 frontColor; +varying vec2 texCoord; + +void main(void) +{ + frontColor = gca_Colors; + texCoord = gca_TexCoords; + gl_Position = gcu_PMVMatrix[0] * gcu_PMVMatrix[1] * gca_Vertices; +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java new file mode 100644 index 000000000..6c826c221 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java @@ -0,0 +1,224 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.test.junit.jogl.glsl; + +import com.jogamp.opengl.util.FBObject; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; +import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquare0; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.NEWTGLContext; +import com.jogamp.opengl.test.junit.util.UITestCase; + +import java.io.IOException; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLProfile; +import javax.media.opengl.GLUniformData; + +import org.junit.Assert; +import org.junit.Test; + +public class TestFBOMRTNEWT01 extends UITestCase { + static long durationPerTest = 10; // ms + + @Test + public void test01() throws InterruptedException { + // preset .. + final NEWTGLContext.WindowContext winctx = NEWTGLContext.createWindow(GLProfile.getGL2ES2(), 640, 480, true); + final GLDrawable drawable = winctx.context.getGLDrawable(); + final GL _gl = winctx.context.getGL(); + Assert.assertTrue(_gl.isGL2GL3()); + final GL2GL3 gl = _gl.getGL2GL3(); + System.err.println(winctx.context); + + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + // test code .. + final ShaderState st = new ShaderState(); + // st.setVerbose(true); + + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, RedSquare0.class, + "shader", "shader/bin", "fbo-mrt-1"); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, RedSquare0.class, + "shader", "shader/bin", "fbo-mrt-1"); + final ShaderProgram sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + Assert.assertTrue(0<=sp0.program()); + Assert.assertTrue(!sp0.inUse()); + Assert.assertTrue(!sp0.linked()); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + st.attachShaderProgram(gl, sp0); + + final ShaderCode vp1 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, RedSquare0.class, + "shader", "shader/bin", "fbo-mrt-2"); + final ShaderCode fp1 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, RedSquare0.class, + "shader", "shader/bin", "fbo-mrt-2"); + final ShaderProgram sp1 = new ShaderProgram(); + sp1.add(gl, vp1, System.err); + sp1.add(gl, fp1, System.err); + Assert.assertTrue(0<=sp1.program()); + Assert.assertTrue(!sp1.inUse()); + Assert.assertTrue(!sp1.linked()); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + st.attachShaderProgram(gl, sp1); + st.useProgram(gl, true); + + final PMVMatrix pmvMatrix = new PMVMatrix(); + final GLUniformData pmvMatrixUniform = new GLUniformData("gcu_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + st.ownUniform(pmvMatrixUniform); + st.uniform(gl, pmvMatrixUniform); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + final GLArrayDataServer vertices0 = GLArrayDataServer.createGLSL(st, "gca_Vertices", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + // st.bindAttribLocation(gl, 0, vertices0); + vertices0.putf(0); vertices0.putf(1); vertices0.putf(0); + vertices0.putf(1); vertices0.putf(1); vertices0.putf(0); + vertices0.putf(0); vertices0.putf(0); vertices0.putf(0); + vertices0.putf(1); vertices0.putf(0); vertices0.putf(0); + vertices0.seal(gl, true); + st.ownAttribute(vertices0, true); + vertices0.enableBuffer(gl, false); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + final GLArrayDataServer colors0 = GLArrayDataServer.createGLSL(st, "gca_Colors", 4, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + // st.bindAttribLocation(gl, 1, colors0); + colors0.putf(1); colors0.putf(0); colors0.putf(1); colors0.putf(1); + colors0.putf(0); colors0.putf(0); colors0.putf(1); colors0.putf(1); + colors0.putf(0); colors0.putf(0); colors0.putf(0); colors0.putf(1); + colors0.putf(0); colors0.putf(1); colors0.putf(1); colors0.putf(1); + colors0.seal(gl, true); + st.ownAttribute(colors0, true); + colors0.enableBuffer(gl, false); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + final GLUniformData texUnit0 = new GLUniformData("gcs_TexUnit0", 0); + st.ownUniform(texUnit0); + st.uniform(gl, texUnit0); + final GLUniformData texUnit1 = new GLUniformData("gcs_TexUnit1", 1); + st.ownUniform(texUnit1); + st.uniform(gl, texUnit1); + + final GLArrayDataServer texCoords0 = GLArrayDataServer.createGLSL(st, "gca_TexCoords", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + // st.bindAttribLocation(gl, 2, texCoords0); + texCoords0.putf(0f); texCoords0.putf(1f); + texCoords0.putf(1f); texCoords0.putf(1f); + texCoords0.putf(0f); texCoords0.putf(0f); + texCoords0.putf(1f); texCoords0.putf(0f); + texCoords0.seal(gl, true); + st.ownAttribute(texCoords0, true); + texCoords0.enableBuffer(gl, false); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + // FBO w/ 2 texture2D color buffers + final FBObject fbo_mrt = new FBObject(drawable.getWidth(), drawable.getHeight()); + fbo_mrt.init(gl); + Assert.assertTrue( 0 == fbo_mrt.attachTexture2D(gl, texUnit0.intValue(), GL.GL_NEAREST, GL.GL_NEAREST, GL2ES2.GL_CLAMP_TO_EDGE, GL2ES2.GL_CLAMP_TO_EDGE) ); + Assert.assertTrue( 1 == fbo_mrt.attachTexture2D(gl, texUnit1.intValue(), GL.GL_NEAREST, GL.GL_NEAREST, GL2ES2.GL_CLAMP_TO_EDGE, GL2ES2.GL_CLAMP_TO_EDGE) ); + Assert.assertTrue( fbo_mrt.attachDepthBuffer(gl, GL.GL_DEPTH_COMPONENT16) ); + Assert.assertTrue( fbo_mrt.isStatusValid() ) ; + fbo_mrt.unbind(gl); + + // misc GL setup + gl.glClearColor(1, 1, 1, 1); + gl.glEnable(GL2ES2.GL_DEPTH_TEST); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + // reshape + pmvMatrix.glMatrixMode(PMVMatrix.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glOrthof(0f, 1f, 0f, 1f, -10f, 10f); + pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + st.uniform(gl, pmvMatrixUniform); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + final int[] two_buffers = new int[] { GL.GL_COLOR_ATTACHMENT0, GL.GL_COLOR_ATTACHMENT0+1 }; + final int[] bck_buffers = new int[] { GL2GL3.GL_BACK_LEFT }; + + for(int i=0; i<durationPerTest; i+=50) { + // pass 1 - MRT: Red -> buffer0, Green -> buffer1 + st.attachShaderProgram(gl, sp0); + vertices0.enableBuffer(gl, true); + colors0.enableBuffer(gl, true); + + fbo_mrt.bind(gl); + gl.glDrawBuffers(2, two_buffers, 0); + gl.glViewport(0, 0, fbo_mrt.getWidth(), fbo_mrt.getHeight()); + + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + fbo_mrt.unbind(gl); + vertices0.enableBuffer(gl, false); + colors0.enableBuffer(gl, false); + + // pass 2 - mix buffer0, buffer1 and blue + // rg = buffer0.rg + buffer1.rg, b = Blue - length(rg); + st.attachShaderProgram(gl, sp1); + vertices0.enableBuffer(gl, true); + colors0.enableBuffer(gl, true); + texCoords0.enableBuffer(gl, true); + gl.glDrawBuffers(1, bck_buffers, 0); + + gl.glViewport(0, 0, drawable.getWidth(), drawable.getHeight()); + fbo_mrt.use(gl, 0); + fbo_mrt.use(gl, 1); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + fbo_mrt.unuse(gl); + vertices0.enableBuffer(gl, false); + colors0.enableBuffer(gl, false); + texCoords0.enableBuffer(gl, false); + + drawable.swapBuffers(); + Thread.sleep(50); + } + + NEWTGLContext.destroyWindow(winctx); + } + + public static void main(String args[]) throws IOException { + System.err.println("main - start"); + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = MiscUtils.atoi(args[++i], (int)durationPerTest); + } + } + String tstname = TestFBOMRTNEWT01.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + System.err.println("main - end"); + } +} + |