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) { 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